From b6d38417ee2651d97657c3bc148dfd5dee8804e3 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 7 Aug 2008 14:53:14 -0700 Subject: [PATCH 001/387] [FIX] More flexible detection of gpl3_or_later --- lib/licenses/license_map.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/licenses/license_map.rb b/lib/licenses/license_map.rb index 04f96e7..666941e 100644 --- a/lib/licenses/license_map.rb +++ b/lib/licenses/license_map.rb @@ -115,7 +115,7 @@ def initialize() SoftwareLicense.new(:gpl3_or_later, "http://www.gnu.org/licenses/gpl-3.0.html", "GNU General Public License 3.0", - /GNU GENERAL PUBLIC LICENSE.{0,100}Version 3.{0,50}later version/im), + /\b(GNU GENERAL PUBLIC LICENSE|GPL).{0,100}(Version)? 3.{0,50}later/im), SoftwareLicense.new(:gpl3, "http://www.gnu.org/licenses/gpl-3.0.html", From b84f28ccae360885b9f151154e3e58c26729250e Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 7 Aug 2008 14:53:45 -0700 Subject: [PATCH 002/387] [FIX] Forgotten files --- test/expected_licenses/gpl3_or_later_t3 | 1 + test/src_licenses/gpl3_or_later_t3.cpp | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 test/expected_licenses/gpl3_or_later_t3 create mode 100644 test/src_licenses/gpl3_or_later_t3.cpp diff --git a/test/expected_licenses/gpl3_or_later_t3 b/test/expected_licenses/gpl3_or_later_t3 new file mode 100644 index 0000000..9765a18 --- /dev/null +++ b/test/expected_licenses/gpl3_or_later_t3 @@ -0,0 +1 @@ +gpl3_or_later diff --git a/test/src_licenses/gpl3_or_later_t3.cpp b/test/src_licenses/gpl3_or_later_t3.cpp new file mode 100644 index 0000000..8f3df8b --- /dev/null +++ b/test/src_licenses/gpl3_or_later_t3.cpp @@ -0,0 +1,3 @@ +/*************************************************************** + * License: GPL version 3 or later + **************************************************************/ From a62c2495929c711250849813eef31fd7c4dd933b Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 7 Aug 2008 15:08:17 -0700 Subject: [PATCH 003/387] [CHANGE] Cut the feature to remove trailing punctuation from comments, since it can lead to runaway regex CPU churn --- lib/licenses/license_sniffer.rb | 5 ++--- test/expected_licenses/gpl_line_wrap_2 | 1 - test/src_licenses/gpl_line_wrap_2.c | 5 ----- 3 files changed, 2 insertions(+), 9 deletions(-) delete mode 100644 test/expected_licenses/gpl_line_wrap_2 delete mode 100644 test/src_licenses/gpl_line_wrap_2.c diff --git a/lib/licenses/license_sniffer.rb b/lib/licenses/license_sniffer.rb index 6763b79..25e6b9e 100644 --- a/lib/licenses/license_sniffer.rb +++ b/lib/licenses/license_sniffer.rb @@ -65,9 +65,8 @@ def self.licenses_from_source_code(file, files = []) if entity == :comment text = sfc.contents[s...e] # e is non-inclusive, so use ... text.split(/[\r\n\f]+/).each do |line| - # Strip leading punctuation. Also strip trailing punctuation - # if it is padded with leading white space. - comments << ' ' + $1 if line =~ /^[\s[:punct:]]*(.*?)(\s+[\s[:punct:]]*)*$/ + # Strip leading punctuation. + comments << ' ' + $1 if line =~ /^[\s[:punct:]]*(.*?)$/ end end end diff --git a/test/expected_licenses/gpl_line_wrap_2 b/test/expected_licenses/gpl_line_wrap_2 deleted file mode 100644 index fc03356..0000000 --- a/test/expected_licenses/gpl_line_wrap_2 +++ /dev/null @@ -1 +0,0 @@ -gpl diff --git a/test/src_licenses/gpl_line_wrap_2.c b/test/src_licenses/gpl_line_wrap_2.c deleted file mode 100644 index 7a71eae..0000000 --- a/test/src_licenses/gpl_line_wrap_2.c +++ /dev/null @@ -1,5 +0,0 @@ -/************************************************************************** - * The line break and comment syntax should not disrupt the license match * - * GNU General * - * Public License * - **************************************************************************/ From f44464a4380d9bcebbbf84129a7006edd46537c1 Mon Sep 17 00:00:00 2001 From: fperraad <> Date: Tue, 26 Aug 2008 14:43:44 -0700 Subject: [PATCH 004/387] [NEW] Count *.pmc (Perl Magic Cookie) and *.xs (Perl/C native interfact) files as C --- lib/ohcount/detector.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index 3410197..bbe91fb 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -196,6 +196,7 @@ def self.binary_filename?(filename) '.pod' => "perl", '.t' => "perl", '.pike' => "pike", + '.pmc' => "c", '.pmod' => "pike", '.py' => "python", '.rhtml'=> "rhtml", @@ -221,6 +222,7 @@ def self.binary_filename?(filename) '.vhdl' => "vhdl", '.vim' => "vim", '.xml' => "xml", + '.xs' => "c", '.xsd' => "xmlschema", '.xsl' => "xslt", '.d' => 'dmd', From 5e763c02d7db9c1f1a49eb3cc6473167cb3ea46b Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 28 Aug 2008 13:46:54 -0700 Subject: [PATCH 005/387] [FIX] Massive change triggered by a bug in the Ohloh/Ohcount interface. Some Ohloh-specific code has been removed from Ohcount. This also (happily) leads to a refactoring of the unit tests. It should be much easier to create tests now. --- bin/ohcount | 3 +- lib/licenses/license_sniffer.rb | 17 +- lib/ohcount.rb | 2 - lib/ohcount/diff.rb | 115 -- lib/ohcount/parser.rb | 62 - test/.gitignore | 1 - test/expected_dir/Makefile | 5 + test/expected_dir/Makefile.am | 3 + test/expected_dir/Makefile.am/automake/blanks | 1 - test/expected_dir/Makefile.am/automake/code | 1 - test/expected_dir/Makefile.am/automake/comment | 1 - test/expected_dir/Makefile/make/blanks | 1 - test/expected_dir/Makefile/make/code | 2 - test/expected_dir/Makefile/make/comment | 1 - test/expected_dir/ada1.ada | 18 + test/expected_dir/ada1.ada/ada/blanks | 1 - test/expected_dir/ada1.ada/ada/code | 12 - test/expected_dir/ada1.ada/ada/comment | 1 - test/expected_dir/ada1.adb | 18 + test/expected_dir/ada1.adb/ada/blanks | 1 - test/expected_dir/ada1.adb/ada/code | 12 - test/expected_dir/ada1.adb/ada/comment | 1 - test/expected_dir/as1.as | 140 ++ test/expected_dir/as1.as/actionscript/code | 60 - test/expected_dir/as1.as/actionscript/comment | 68 - test/expected_dir/assembler1.asm | 68 + test/expected_dir/assembler1.asm/assembler/blanks | 1 - test/expected_dir/assembler1.asm/assembler/code | 54 - test/expected_dir/assembler1.asm/assembler/comment | 12 - test/expected_dir/assembler2.S | 7 + test/expected_dir/assembler2.S/assembler/blanks | 1 - test/expected_dir/assembler2.S/assembler/code | 2 - test/expected_dir/assembler2.S/assembler/comment | 3 - test/expected_dir/awk1.awk | 53 + test/expected_dir/awk1.awk/awk/blanks | 1 - test/expected_dir/awk1.awk/awk/code | 45 - test/expected_dir/awk1.awk/awk/comment | 3 - test/expected_dir/bat1.bat | 6 + test/expected_dir/bat1.bat/bat/blanks | 1 - test/expected_dir/bat1.bat/bat/code | 1 - test/expected_dir/bat1.bat/bat/comment | 3 - test/expected_dir/boo1.boo | 112 ++ test/expected_dir/boo1.boo/boo/blanks | 1 - test/expected_dir/boo1.boo/boo/code | 71 - test/expected_dir/boo1.boo/boo/comment | 21 - test/expected_dir/c1.c | 70 + test/expected_dir/c1.c/c/blanks | 1 - test/expected_dir/c1.c/c/code | 36 - test/expected_dir/c1.c/c/comment | 30 - test/expected_dir/c2.h.in | 15 + test/expected_dir/c2.h.in/c/blanks | 1 - test/expected_dir/c2.h.in/c/code | 6 - test/expected_dir/c2.h.in/c/comment | 4 - test/expected_dir/c_str.c | 2 + test/expected_dir/c_str.c/c/blanks | 1 - test/expected_dir/c_str.c/c/code | 1 - test/expected_dir/c_str.c/c/comment | 1 - test/expected_dir/classic_basic.b | 19 + .../classic_basic.b/classic_basic/blanks | 1 - .../classic_basic.b/classic_basic/code | 17 - .../classic_basic.b/classic_basic/comment | 2 - test/expected_dir/classic_basic.bas | 20 + .../classic_basic.bas/classic_basic/blanks | 1 - .../classic_basic.bas/classic_basic/code | 17 - .../classic_basic.bas/classic_basic/comment | 2 - .../html/comment => classic_basic1.classic_basic} | 0 .../classic_basic1.classic_basic/basic/code | 17 - .../classic_basic1.classic_basic/basic/comment | 2 - test/expected_dir/clearsilver_template1.cs | 6 + .../clearsilver_template1.cs/clearsilver/blanks | 1 - .../clearsilver_template1.cs/clearsilver/code | 1 - .../clearsilver_template1.cs/clearsilver/comment | 1 - .../clearsilver_template1.cs/html/blanks | 1 - .../clearsilver_template1.cs/html/code | 4 - .../{css1.css/css/comment => cobol1.cbl} | 0 test/expected_dir/cobol1.cbl/cobol/blank | 4 - test/expected_dir/cobol1.cbl/cobol/code | 13 - test/expected_dir/cobol1.cbl/cobol/comment | 7 - test/expected_dir/configure.ac | 5 + test/expected_dir/configure.ac/autoconf/blanks | 1 - test/expected_dir/configure.ac/autoconf/code | 2 - test/expected_dir/configure.ac/autoconf/comment | 1 - test/expected_dir/cs1.cs | 55 + test/expected_dir/cs1.cs/csharp/blanks | 1 - test/expected_dir/cs1.cs/csharp/code | 41 - test/expected_dir/cs1.cs/csharp/comment | 8 - test/expected_dir/css1.css | 3 + test/expected_dir/css1.css/css/blanks | 1 - test/expected_dir/css1.css/css/code | 3 - test/expected_dir/d1.d | 26 + test/expected_dir/d1.d/dmd/blanks | 1 - test/expected_dir/d1.d/dmd/code | 9 - test/expected_dir/d1.d/dmd/comment | 12 - test/expected_dir/dcl.com | 12 + test/expected_dir/dcl.com/dcl/blanks | 1 - test/expected_dir/dcl.com/dcl/code | 4 - test/expected_dir/dcl.com/dcl/comment | 4 - test/expected_dir/diff1_new.html | 11 + test/expected_dir/diff1_old.html | 11 + test/expected_dir/diff2_new.c | 7 + test/expected_dir/diff2_old.c | 7 + test/expected_dir/diff3_new.xml | 3 + test/expected_dir/diff3_old.xml | 3 + test/expected_dir/dylan1.dylan | 17 + test/expected_dir/dylan1.dylan/dylan/blanks | 1 - test/expected_dir/dylan1.dylan/dylan/code | 12 - test/expected_dir/dylan1.dylan/dylan/comment | 3 - test/expected_dir/eiffel.e | 13 + test/expected_dir/eiffel.e/eiffel/blanks | 1 - test/expected_dir/eiffel.e/eiffel/code | 10 - test/expected_dir/eiffel.e/eiffel/comment | 1 - test/expected_dir/el1.el | 22 + test/expected_dir/el1.el/emacslisp/blanks | 1 - test/expected_dir/el1.el/emacslisp/code | 10 - test/expected_dir/el1.el/emacslisp/comment | 11 - test/expected_dir/erl1.erl | 189 +++ test/expected_dir/erl1.erl/erlang/blanks | 1 - test/expected_dir/erl1.erl/erlang/code | 161 -- test/expected_dir/erl1.erl/erlang/comment | 14 - test/expected_dir/example.xsl | 17 + test/expected_dir/example.xsl/xslt/blanks | 1 - test/expected_dir/example.xsl/xslt/code | 14 - test/expected_dir/example.xsl/xslt/comment | 2 - test/expected_dir/factor1.factor | 14 + test/expected_dir/factor1.factor/factor/blanks | 1 - test/expected_dir/factor1.factor/factor/code | 7 - test/expected_dir/factor1.factor/factor/comment | 4 - test/expected_dir/foo.ebuild | 21 + test/expected_dir/foo.ebuild/ebuild/blanks | 1 - test/expected_dir/foo.ebuild/ebuild/code | 12 - test/expected_dir/foo.ebuild/ebuild/comment | 4 - test/expected_dir/foo.exheres-0 | 20 + test/expected_dir/foo.exheres-0/exheres/blanks | 1 - test/expected_dir/foo.exheres-0/exheres/code | 13 - test/expected_dir/foo.exheres-0/exheres/comment | 1 - test/expected_dir/foo.tex | 8 + test/expected_dir/foo.tex/tex/blanks | 1 - test/expected_dir/foo.tex/tex/code | 3 - test/expected_dir/foo.tex/tex/comment | 2 - test/expected_dir/foo.vim | 21 + test/expected_dir/foo.vim/vim/blanks | 1 - test/expected_dir/foo.vim/vim/code | 9 - test/expected_dir/foo.vim/vim/comment | 7 - test/expected_dir/fortranfixed.f | 12 + .../fortranfixed.f/fortranfixed/blanks | 1 - test/expected_dir/fortranfixed.f/fortranfixed/code | 5 - .../fortranfixed.f/fortranfixed/comment | 5 - test/expected_dir/fortranfree.f | 18 + test/expected_dir/fortranfree.f/fortranfree/blanks | 1 - test/expected_dir/fortranfree.f/fortranfree/code | 8 - .../expected_dir/fortranfree.f/fortranfree/comment | 6 - test/expected_dir/frx1.frx | 60 + test/expected_dir/frx1.frx/visualbasic/blanks | 1 - test/expected_dir/frx1.frx/visualbasic/code | 36 - test/expected_dir/frx1.frx/visualbasic/comment | 17 - test/expected_dir/groovy1.groovy | 9 + test/expected_dir/groovy1.groovy/groovy/blanks | 1 - test/expected_dir/groovy1.groovy/groovy/code | 4 - test/expected_dir/groovy1.groovy/groovy/comment | 5 - test/expected_dir/haml.haml | 20 + test/expected_dir/haml.haml/haml/blanks | 1 - test/expected_dir/haml.haml/haml/code | 7 - test/expected_dir/haml.haml/haml/comment | 8 - test/expected_dir/haml.haml/ruby/blanks | 1 - test/expected_dir/haml.haml/ruby/code | 4 - test/expected_dir/haml.haml/ruby/comment | 0 test/expected_dir/haskell1.hs | 108 ++ test/expected_dir/haskell1.hs/haskell/blanks | 1 - test/expected_dir/haskell1.hs/haskell/code | 62 - test/expected_dir/haskell1.hs/haskell/comment | 36 - test/expected_dir/haskell2.hs | 4 + test/expected_dir/haskell2.hs/haskell/blanks | 1 - test/expected_dir/haskell2.hs/haskell/code | 0 test/expected_dir/haskell2.hs/haskell/comment | 2 - test/expected_dir/haskell3.hs | 5 + test/expected_dir/haskell3.hs/haskell/blanks | 1 - test/expected_dir/haskell3.hs/haskell/code | 0 test/expected_dir/haskell3.hs/haskell/comment | 3 - test/expected_dir/html1.html | 38 + test/expected_dir/html1.html/css/blanks | 1 - test/expected_dir/html1.html/css/code | 3 - test/expected_dir/html1.html/css/comment | 0 test/expected_dir/html1.html/html/blanks | 1 - test/expected_dir/html1.html/html/code | 18 - test/expected_dir/html1.html/html/comment | 3 - test/expected_dir/html1.html/javascript/blanks | 1 - test/expected_dir/html1.html/javascript/code | 13 - test/expected_dir/html1.html/javascript/comment | 1 - test/expected_dir/java1.java | 48 + test/expected_dir/java1.java/java/blanks | 1 - test/expected_dir/java1.java/java/code | 27 - test/expected_dir/java1.java/java/comment | 6 - test/expected_dir/java2.java | 3 + test/expected_dir/java2.java/java/blanks | 1 - test/expected_dir/java2.java/java/code | 0 test/expected_dir/java2.java/java/comment | 2 - test/expected_dir/js1.js | 1781 ++++++++++++++++++++ test/expected_dir/js1.js/javascript/code | 1446 ---------------- test/expected_dir/js1.js/javascript/comment | 46 - test/expected_dir/js2.js | 13 + test/expected_dir/js2.js/javascript/code | 6 - test/expected_dir/js2.js/javascript/comment | 7 - test/expected_dir/js3.js | 2 + test/expected_dir/jsp1.jsp | 14 + test/expected_dir/jsp1.jsp/html/code | 8 - test/expected_dir/jsp1.jsp/java/blanks | 1 - test/expected_dir/jsp1.jsp/java/code | 2 - test/expected_dir/jsp1.jsp/java/comment | 4 - test/expected_dir/lsp1.lsp | 135 ++ test/expected_dir/lsp1.lsp/lisp/blanks | 1 - test/expected_dir/lsp1.lsp/lisp/code | 46 - test/expected_dir/lsp1.lsp/lisp/comment | 38 - test/expected_dir/lua1.lua | 121 ++ test/expected_dir/lua1.lua/lua/blanks | 1 - test/expected_dir/lua1.lua/lua/code | 100 -- test/expected_dir/lua1.lua/lua/comment | 9 - test/expected_dir/matlab1.m | 54 + test/expected_dir/matlab1.m/matlab/blanks | 1 - test/expected_dir/matlab1.m/matlab/code | 29 - test/expected_dir/matlab1.m/matlab/comment | 16 - test/expected_dir/metafont.mf | 22 + test/expected_dir/metafont.mf/metafont/blanks | 1 - test/expected_dir/metafont.mf/metafont/code | 13 - test/expected_dir/metafont.mf/metafont/comment | 4 - test/expected_dir/metapost.mp | 62 + test/expected_dir/metapost.mp/metapost/blanks | 1 - test/expected_dir/metapost.mp/metapost/code | 29 - test/expected_dir/metapost.mp/metapost/comment | 8 - test/expected_dir/metapost.mp/tex/blanks | 1 - test/expected_dir/metapost.mp/tex/code | 16 - test/expected_dir/metapost.mp/tex/comment | 1 - test/expected_dir/mxml1.mxml | 26 + test/expected_dir/mxml1.mxml/actionscript/code | 3 - test/expected_dir/mxml1.mxml/css/code | 3 - test/expected_dir/mxml1.mxml/mxml/code | 10 - test/expected_dir/ocaml.ml | 10 + test/expected_dir/ocaml.ml/ocaml/blanks | 1 - test/expected_dir/ocaml.ml/ocaml/code | 1 - test/expected_dir/ocaml.ml/ocaml/comment | 7 - test/expected_dir/pascal1.pas | 112 ++ test/expected_dir/pascal1.pas/pascal/blanks | 1 - test/expected_dir/pascal1.pas/pascal/code | 90 - test/expected_dir/pascal1.pas/pascal/comment | 13 - test/expected_dir/pascal2.pp | 112 ++ test/expected_dir/pascal2.pp/pascal/blanks | 1 - test/expected_dir/pascal2.pp/pascal/code | 90 - test/expected_dir/pascal2.pp/pascal/comment | 13 - test/expected_dir/perl.cgi | 66 + test/expected_dir/perl.cgi/perl/blanks | 1 - test/expected_dir/perl.cgi/perl/code | 47 - test/expected_dir/perl.cgi/perl/comment | 5 - test/expected_dir/perl1.pl | 72 + test/expected_dir/perl1.pl/perl/blanks | 1 - test/expected_dir/perl1.pl/perl/code | 45 - test/expected_dir/perl1.pl/perl/comment | 15 - test/expected_dir/perl_module.pm | 1191 +++++++++++++ test/expected_dir/perl_module.pm/perl/blanks | 1 - test/expected_dir/perl_module.pm/perl/code | 642 ------- test/expected_dir/perl_module.pm/perl/comment | 285 ---- test/expected_dir/php1.php | 59 + test/expected_dir/php1.php/css/code | 3 - test/expected_dir/php1.php/css/comment | 1 - test/expected_dir/php1.php/html/blanks | 1 - test/expected_dir/php1.php/html/code | 25 - test/expected_dir/php1.php/javascript/code | 1 - test/expected_dir/php1.php/javascript/comment | 1 - test/expected_dir/php1.php/php/code | 16 - test/expected_dir/php1.php/php/comment | 3 - test/expected_dir/pike1.pike | 6 + test/expected_dir/pike1.pike/pike/blanks | 1 - test/expected_dir/pike1.pike/pike/code | 5 - test/expected_dir/pike1.pike/pike/comment | 1 - test/expected_dir/pike2.pmod | 241 +++ test/expected_dir/pike2.pmod/pike/blanks | 1 - test/expected_dir/pike2.pmod/pike/code | 157 -- test/expected_dir/pike2.pmod/pike/comment | 45 - test/expected_dir/py1.py | 18 + test/expected_dir/py1.py/python/blanks | 1 - test/expected_dir/py1.py/python/code | 5 - test/expected_dir/py1.py/python/comment | 10 - test/expected_dir/rexx1.rex | 311 ++++ test/expected_dir/rexx1.rex/rexx/blanks | 1 - test/expected_dir/rexx1.rex/rexx/code | 231 --- test/expected_dir/rexx1.rex/rexx/comment | 41 - test/expected_dir/rhtml1.rhtml | 25 + test/expected_dir/rhtml1.rhtml/html/blanks | 1 - test/expected_dir/rhtml1.rhtml/html/code | 10 - test/expected_dir/rhtml1.rhtml/html/comment | 3 - test/expected_dir/rhtml1.rhtml/ruby/code | 9 - test/expected_dir/rhtml1.rhtml/ruby/comment | 1 - test/expected_dir/ruby1.rb | 22 + test/expected_dir/ruby1.rb/ruby/blanks | 1 - test/expected_dir/ruby1.rb/ruby/code | 17 - test/expected_dir/ruby1.rb/ruby/comment | 3 - test/expected_dir/scala1.scala | 63 + test/expected_dir/scala1.scala/scala/blanks | 1 - test/expected_dir/scala1.scala/scala/code | 48 - test/expected_dir/scala1.scala/scala/comment | 11 - test/expected_dir/schema.xsd | 68 + test/expected_dir/schema.xsd/xmlschema/blanks | 1 - test/expected_dir/schema.xsd/xmlschema/code | 66 - test/expected_dir/schema.xsd/xmlschema/comment | 2 - test/expected_dir/scheme.scm | 32 + test/expected_dir/scheme.scm/scheme/blanks | 1 - test/expected_dir/scheme.scm/scheme/code | 21 - test/expected_dir/scheme.scm/scheme/comment | 6 - test/expected_dir/sh1.sh | 5 + test/expected_dir/sh1.sh/shell/blanks | 1 - test/expected_dir/sh1.sh/shell/code | 2 - test/expected_dir/sh1.sh/shell/comment | 2 - test/expected_dir/smalltalk1.st | 19 + test/expected_dir/smalltalk1.st/smalltalk/blanks | 1 - test/expected_dir/smalltalk1.st/smalltalk/code | 9 - test/expected_dir/smalltalk1.st/smalltalk/comment | 7 - test/expected_dir/sql1.sql | 31 + test/expected_dir/sql1.sql/sql/blanks | 1 - test/expected_dir/sql1.sql/sql/code | 4 - test/expected_dir/sql1.sql/sql/comment | 23 - test/expected_dir/stratego.str | 25 + test/expected_dir/stratego.str/stratego/blanks | 1 - test/expected_dir/stratego.str/stratego/code | 15 - test/expected_dir/stratego.str/stratego/comment | 4 - test/expected_dir/structured_basic.b | 20 + .../structured_basic.b/structured_basic/blanks | 1 - .../structured_basic.b/structured_basic/code | 17 - .../structured_basic.b/structured_basic/comment | 2 - test/expected_dir/structured_basic.bas | 20 + .../structured_basic.bas/structured_basic/blanks | 1 - .../structured_basic.bas/structured_basic/code | 17 - .../structured_basic.bas/structured_basic/comment | 2 - test/expected_dir/tcl1.tcl | 35 + test/expected_dir/tcl1.tcl/tcl/blanks | 1 - test/expected_dir/tcl1.tcl/tcl/code | 19 - test/expected_dir/tcl1.tcl/tcl/comment | 12 - test/expected_dir/vala1.vala | 61 + test/expected_dir/vala1.vala/vala/blanks | 1 - test/expected_dir/vala1.vala/vala/code | 44 - test/expected_dir/vala1.vala/vala/comment | 7 - test/expected_dir/vb1.vb | 16 + test/expected_dir/vbs1.vbs | 14 + test/expected_dir/vhdl1.vhd | 92 + test/expected_dir/vhdl1.vhd/vhdl/blanks | 1 - test/expected_dir/vhdl1.vhd/vhdl/code | 58 - test/expected_dir/vhdl1.vhd/vhdl/comment | 15 - test/expected_dir/vhdl1.vhdl | 40 + test/expected_dir/vhdl1.vhdl/vhdl/blanks | 1 - test/expected_dir/vhdl1.vhdl/vhdl/code | 18 - test/expected_dir/vhdl1.vhdl/vhdl/comment | 10 - test/expected_dir/visual_basic.bas | 60 + .../visual_basic.bas/visualbasic/blanks | 1 - .../expected_dir/visual_basic.bas/visualbasic/code | 36 - .../visual_basic.bas/visualbasic/comment | 17 - test/expected_dir/xml1.xml | 14 + test/expected_dir/xml1.xml/xml/blanks | 1 - test/expected_dir/xml1.xml/xml/code | 7 - test/expected_dir/xml1.xml/xml/comment | 5 - test/test_helper.rb | 118 +- test/unit/basic_test.rb | 2 +- test/unit/diff_test.rb | 43 - test/unit/license_sniffer_test.rb | 7 +- 360 files changed, 6503 insertions(+), 5804 deletions(-) delete mode 100644 lib/ohcount/diff.rb delete mode 100644 lib/ohcount/parser.rb create mode 100644 test/expected_dir/Makefile create mode 100644 test/expected_dir/Makefile.am delete mode 100644 test/expected_dir/Makefile.am/automake/blanks delete mode 100644 test/expected_dir/Makefile.am/automake/code delete mode 100644 test/expected_dir/Makefile.am/automake/comment delete mode 100644 test/expected_dir/Makefile/make/blanks delete mode 100644 test/expected_dir/Makefile/make/code delete mode 100644 test/expected_dir/Makefile/make/comment create mode 100644 test/expected_dir/ada1.ada delete mode 100644 test/expected_dir/ada1.ada/ada/blanks delete mode 100644 test/expected_dir/ada1.ada/ada/code delete mode 100644 test/expected_dir/ada1.ada/ada/comment create mode 100644 test/expected_dir/ada1.adb delete mode 100644 test/expected_dir/ada1.adb/ada/blanks delete mode 100644 test/expected_dir/ada1.adb/ada/code delete mode 100644 test/expected_dir/ada1.adb/ada/comment create mode 100644 test/expected_dir/as1.as delete mode 100644 test/expected_dir/as1.as/actionscript/code delete mode 100644 test/expected_dir/as1.as/actionscript/comment create mode 100644 test/expected_dir/assembler1.asm delete mode 100644 test/expected_dir/assembler1.asm/assembler/blanks delete mode 100644 test/expected_dir/assembler1.asm/assembler/code delete mode 100644 test/expected_dir/assembler1.asm/assembler/comment create mode 100644 test/expected_dir/assembler2.S delete mode 100644 test/expected_dir/assembler2.S/assembler/blanks delete mode 100644 test/expected_dir/assembler2.S/assembler/code delete mode 100644 test/expected_dir/assembler2.S/assembler/comment create mode 100644 test/expected_dir/awk1.awk delete mode 100644 test/expected_dir/awk1.awk/awk/blanks delete mode 100644 test/expected_dir/awk1.awk/awk/code delete mode 100644 test/expected_dir/awk1.awk/awk/comment create mode 100644 test/expected_dir/bat1.bat delete mode 100644 test/expected_dir/bat1.bat/bat/blanks delete mode 100644 test/expected_dir/bat1.bat/bat/code delete mode 100644 test/expected_dir/bat1.bat/bat/comment create mode 100644 test/expected_dir/boo1.boo delete mode 100644 test/expected_dir/boo1.boo/boo/blanks delete mode 100644 test/expected_dir/boo1.boo/boo/code delete mode 100644 test/expected_dir/boo1.boo/boo/comment create mode 100644 test/expected_dir/c1.c delete mode 100644 test/expected_dir/c1.c/c/blanks delete mode 100644 test/expected_dir/c1.c/c/code delete mode 100644 test/expected_dir/c1.c/c/comment create mode 100644 test/expected_dir/c2.h.in delete mode 100644 test/expected_dir/c2.h.in/c/blanks delete mode 100644 test/expected_dir/c2.h.in/c/code delete mode 100644 test/expected_dir/c2.h.in/c/comment create mode 100644 test/expected_dir/c_str.c delete mode 100644 test/expected_dir/c_str.c/c/blanks delete mode 100644 test/expected_dir/c_str.c/c/code delete mode 100644 test/expected_dir/c_str.c/c/comment create mode 100644 test/expected_dir/classic_basic.b delete mode 100644 test/expected_dir/classic_basic.b/classic_basic/blanks delete mode 100644 test/expected_dir/classic_basic.b/classic_basic/code delete mode 100644 test/expected_dir/classic_basic.b/classic_basic/comment create mode 100644 test/expected_dir/classic_basic.bas delete mode 100644 test/expected_dir/classic_basic.bas/classic_basic/blanks delete mode 100644 test/expected_dir/classic_basic.bas/classic_basic/code delete mode 100644 test/expected_dir/classic_basic.bas/classic_basic/comment rename test/expected_dir/{clearsilver_template1.cs/html/comment => classic_basic1.classic_basic} (100%) delete mode 100644 test/expected_dir/classic_basic1.classic_basic/basic/code delete mode 100644 test/expected_dir/classic_basic1.classic_basic/basic/comment create mode 100644 test/expected_dir/clearsilver_template1.cs delete mode 100644 test/expected_dir/clearsilver_template1.cs/clearsilver/blanks delete mode 100644 test/expected_dir/clearsilver_template1.cs/clearsilver/code delete mode 100644 test/expected_dir/clearsilver_template1.cs/clearsilver/comment delete mode 100644 test/expected_dir/clearsilver_template1.cs/html/blanks delete mode 100644 test/expected_dir/clearsilver_template1.cs/html/code rename test/expected_dir/{css1.css/css/comment => cobol1.cbl} (100%) delete mode 100644 test/expected_dir/cobol1.cbl/cobol/blank delete mode 100644 test/expected_dir/cobol1.cbl/cobol/code delete mode 100644 test/expected_dir/cobol1.cbl/cobol/comment create mode 100644 test/expected_dir/configure.ac delete mode 100644 test/expected_dir/configure.ac/autoconf/blanks delete mode 100644 test/expected_dir/configure.ac/autoconf/code delete mode 100644 test/expected_dir/configure.ac/autoconf/comment create mode 100644 test/expected_dir/cs1.cs delete mode 100644 test/expected_dir/cs1.cs/csharp/blanks delete mode 100644 test/expected_dir/cs1.cs/csharp/code delete mode 100644 test/expected_dir/cs1.cs/csharp/comment create mode 100644 test/expected_dir/css1.css delete mode 100644 test/expected_dir/css1.css/css/blanks delete mode 100644 test/expected_dir/css1.css/css/code create mode 100644 test/expected_dir/d1.d delete mode 100644 test/expected_dir/d1.d/dmd/blanks delete mode 100644 test/expected_dir/d1.d/dmd/code delete mode 100644 test/expected_dir/d1.d/dmd/comment create mode 100644 test/expected_dir/dcl.com delete mode 100644 test/expected_dir/dcl.com/dcl/blanks delete mode 100644 test/expected_dir/dcl.com/dcl/code delete mode 100644 test/expected_dir/dcl.com/dcl/comment create mode 100644 test/expected_dir/diff1_new.html create mode 100644 test/expected_dir/diff1_old.html create mode 100644 test/expected_dir/diff2_new.c create mode 100644 test/expected_dir/diff2_old.c create mode 100644 test/expected_dir/diff3_new.xml create mode 100644 test/expected_dir/diff3_old.xml create mode 100644 test/expected_dir/dylan1.dylan delete mode 100644 test/expected_dir/dylan1.dylan/dylan/blanks delete mode 100644 test/expected_dir/dylan1.dylan/dylan/code delete mode 100644 test/expected_dir/dylan1.dylan/dylan/comment create mode 100644 test/expected_dir/eiffel.e delete mode 100644 test/expected_dir/eiffel.e/eiffel/blanks delete mode 100644 test/expected_dir/eiffel.e/eiffel/code delete mode 100644 test/expected_dir/eiffel.e/eiffel/comment create mode 100644 test/expected_dir/el1.el delete mode 100644 test/expected_dir/el1.el/emacslisp/blanks delete mode 100644 test/expected_dir/el1.el/emacslisp/code delete mode 100644 test/expected_dir/el1.el/emacslisp/comment create mode 100644 test/expected_dir/erl1.erl delete mode 100644 test/expected_dir/erl1.erl/erlang/blanks delete mode 100644 test/expected_dir/erl1.erl/erlang/code delete mode 100644 test/expected_dir/erl1.erl/erlang/comment create mode 100644 test/expected_dir/example.xsl delete mode 100644 test/expected_dir/example.xsl/xslt/blanks delete mode 100644 test/expected_dir/example.xsl/xslt/code delete mode 100644 test/expected_dir/example.xsl/xslt/comment create mode 100644 test/expected_dir/factor1.factor delete mode 100644 test/expected_dir/factor1.factor/factor/blanks delete mode 100644 test/expected_dir/factor1.factor/factor/code delete mode 100644 test/expected_dir/factor1.factor/factor/comment create mode 100644 test/expected_dir/foo.ebuild delete mode 100644 test/expected_dir/foo.ebuild/ebuild/blanks delete mode 100644 test/expected_dir/foo.ebuild/ebuild/code delete mode 100644 test/expected_dir/foo.ebuild/ebuild/comment create mode 100644 test/expected_dir/foo.exheres-0 delete mode 100644 test/expected_dir/foo.exheres-0/exheres/blanks delete mode 100644 test/expected_dir/foo.exheres-0/exheres/code delete mode 100644 test/expected_dir/foo.exheres-0/exheres/comment create mode 100644 test/expected_dir/foo.tex delete mode 100644 test/expected_dir/foo.tex/tex/blanks delete mode 100644 test/expected_dir/foo.tex/tex/code delete mode 100644 test/expected_dir/foo.tex/tex/comment create mode 100644 test/expected_dir/foo.vim delete mode 100644 test/expected_dir/foo.vim/vim/blanks delete mode 100644 test/expected_dir/foo.vim/vim/code delete mode 100644 test/expected_dir/foo.vim/vim/comment create mode 100644 test/expected_dir/fortranfixed.f delete mode 100644 test/expected_dir/fortranfixed.f/fortranfixed/blanks delete mode 100644 test/expected_dir/fortranfixed.f/fortranfixed/code delete mode 100644 test/expected_dir/fortranfixed.f/fortranfixed/comment create mode 100644 test/expected_dir/fortranfree.f delete mode 100644 test/expected_dir/fortranfree.f/fortranfree/blanks delete mode 100644 test/expected_dir/fortranfree.f/fortranfree/code delete mode 100644 test/expected_dir/fortranfree.f/fortranfree/comment create mode 100644 test/expected_dir/frx1.frx delete mode 100644 test/expected_dir/frx1.frx/visualbasic/blanks delete mode 100644 test/expected_dir/frx1.frx/visualbasic/code delete mode 100644 test/expected_dir/frx1.frx/visualbasic/comment create mode 100644 test/expected_dir/groovy1.groovy delete mode 100644 test/expected_dir/groovy1.groovy/groovy/blanks delete mode 100644 test/expected_dir/groovy1.groovy/groovy/code delete mode 100644 test/expected_dir/groovy1.groovy/groovy/comment create mode 100644 test/expected_dir/haml.haml delete mode 100644 test/expected_dir/haml.haml/haml/blanks delete mode 100644 test/expected_dir/haml.haml/haml/code delete mode 100644 test/expected_dir/haml.haml/haml/comment delete mode 100644 test/expected_dir/haml.haml/ruby/blanks delete mode 100644 test/expected_dir/haml.haml/ruby/code delete mode 100644 test/expected_dir/haml.haml/ruby/comment create mode 100644 test/expected_dir/haskell1.hs delete mode 100644 test/expected_dir/haskell1.hs/haskell/blanks delete mode 100644 test/expected_dir/haskell1.hs/haskell/code delete mode 100644 test/expected_dir/haskell1.hs/haskell/comment create mode 100644 test/expected_dir/haskell2.hs delete mode 100644 test/expected_dir/haskell2.hs/haskell/blanks delete mode 100644 test/expected_dir/haskell2.hs/haskell/code delete mode 100644 test/expected_dir/haskell2.hs/haskell/comment create mode 100644 test/expected_dir/haskell3.hs delete mode 100644 test/expected_dir/haskell3.hs/haskell/blanks delete mode 100644 test/expected_dir/haskell3.hs/haskell/code delete mode 100644 test/expected_dir/haskell3.hs/haskell/comment create mode 100644 test/expected_dir/html1.html delete mode 100644 test/expected_dir/html1.html/css/blanks delete mode 100644 test/expected_dir/html1.html/css/code delete mode 100644 test/expected_dir/html1.html/css/comment delete mode 100644 test/expected_dir/html1.html/html/blanks delete mode 100644 test/expected_dir/html1.html/html/code delete mode 100644 test/expected_dir/html1.html/html/comment delete mode 100644 test/expected_dir/html1.html/javascript/blanks delete mode 100644 test/expected_dir/html1.html/javascript/code delete mode 100644 test/expected_dir/html1.html/javascript/comment create mode 100644 test/expected_dir/java1.java delete mode 100644 test/expected_dir/java1.java/java/blanks delete mode 100644 test/expected_dir/java1.java/java/code delete mode 100644 test/expected_dir/java1.java/java/comment create mode 100644 test/expected_dir/java2.java delete mode 100644 test/expected_dir/java2.java/java/blanks delete mode 100644 test/expected_dir/java2.java/java/code delete mode 100644 test/expected_dir/java2.java/java/comment create mode 100644 test/expected_dir/js1.js delete mode 100644 test/expected_dir/js1.js/javascript/code delete mode 100644 test/expected_dir/js1.js/javascript/comment create mode 100644 test/expected_dir/js2.js delete mode 100644 test/expected_dir/js2.js/javascript/code delete mode 100644 test/expected_dir/js2.js/javascript/comment create mode 100644 test/expected_dir/js3.js create mode 100644 test/expected_dir/jsp1.jsp delete mode 100644 test/expected_dir/jsp1.jsp/html/code delete mode 100644 test/expected_dir/jsp1.jsp/java/blanks delete mode 100644 test/expected_dir/jsp1.jsp/java/code delete mode 100644 test/expected_dir/jsp1.jsp/java/comment create mode 100644 test/expected_dir/lsp1.lsp delete mode 100644 test/expected_dir/lsp1.lsp/lisp/blanks delete mode 100644 test/expected_dir/lsp1.lsp/lisp/code delete mode 100644 test/expected_dir/lsp1.lsp/lisp/comment create mode 100644 test/expected_dir/lua1.lua delete mode 100644 test/expected_dir/lua1.lua/lua/blanks delete mode 100644 test/expected_dir/lua1.lua/lua/code delete mode 100644 test/expected_dir/lua1.lua/lua/comment create mode 100644 test/expected_dir/matlab1.m delete mode 100644 test/expected_dir/matlab1.m/matlab/blanks delete mode 100644 test/expected_dir/matlab1.m/matlab/code delete mode 100644 test/expected_dir/matlab1.m/matlab/comment create mode 100644 test/expected_dir/metafont.mf delete mode 100644 test/expected_dir/metafont.mf/metafont/blanks delete mode 100644 test/expected_dir/metafont.mf/metafont/code delete mode 100644 test/expected_dir/metafont.mf/metafont/comment create mode 100644 test/expected_dir/metapost.mp delete mode 100644 test/expected_dir/metapost.mp/metapost/blanks delete mode 100644 test/expected_dir/metapost.mp/metapost/code delete mode 100644 test/expected_dir/metapost.mp/metapost/comment delete mode 100644 test/expected_dir/metapost.mp/tex/blanks delete mode 100644 test/expected_dir/metapost.mp/tex/code delete mode 100644 test/expected_dir/metapost.mp/tex/comment create mode 100644 test/expected_dir/mxml1.mxml delete mode 100644 test/expected_dir/mxml1.mxml/actionscript/code delete mode 100644 test/expected_dir/mxml1.mxml/css/code delete mode 100644 test/expected_dir/mxml1.mxml/mxml/code create mode 100644 test/expected_dir/ocaml.ml delete mode 100644 test/expected_dir/ocaml.ml/ocaml/blanks delete mode 100644 test/expected_dir/ocaml.ml/ocaml/code delete mode 100644 test/expected_dir/ocaml.ml/ocaml/comment create mode 100644 test/expected_dir/pascal1.pas delete mode 100644 test/expected_dir/pascal1.pas/pascal/blanks delete mode 100644 test/expected_dir/pascal1.pas/pascal/code delete mode 100644 test/expected_dir/pascal1.pas/pascal/comment create mode 100644 test/expected_dir/pascal2.pp delete mode 100644 test/expected_dir/pascal2.pp/pascal/blanks delete mode 100644 test/expected_dir/pascal2.pp/pascal/code delete mode 100644 test/expected_dir/pascal2.pp/pascal/comment create mode 100644 test/expected_dir/perl.cgi delete mode 100644 test/expected_dir/perl.cgi/perl/blanks delete mode 100644 test/expected_dir/perl.cgi/perl/code delete mode 100644 test/expected_dir/perl.cgi/perl/comment create mode 100644 test/expected_dir/perl1.pl delete mode 100644 test/expected_dir/perl1.pl/perl/blanks delete mode 100644 test/expected_dir/perl1.pl/perl/code delete mode 100644 test/expected_dir/perl1.pl/perl/comment create mode 100644 test/expected_dir/perl_module.pm delete mode 100644 test/expected_dir/perl_module.pm/perl/blanks delete mode 100644 test/expected_dir/perl_module.pm/perl/code delete mode 100644 test/expected_dir/perl_module.pm/perl/comment create mode 100644 test/expected_dir/php1.php delete mode 100644 test/expected_dir/php1.php/css/code delete mode 100644 test/expected_dir/php1.php/css/comment delete mode 100644 test/expected_dir/php1.php/html/blanks delete mode 100644 test/expected_dir/php1.php/html/code delete mode 100644 test/expected_dir/php1.php/javascript/code delete mode 100644 test/expected_dir/php1.php/javascript/comment delete mode 100644 test/expected_dir/php1.php/php/code delete mode 100644 test/expected_dir/php1.php/php/comment create mode 100644 test/expected_dir/pike1.pike delete mode 100644 test/expected_dir/pike1.pike/pike/blanks delete mode 100644 test/expected_dir/pike1.pike/pike/code delete mode 100644 test/expected_dir/pike1.pike/pike/comment create mode 100644 test/expected_dir/pike2.pmod delete mode 100644 test/expected_dir/pike2.pmod/pike/blanks delete mode 100644 test/expected_dir/pike2.pmod/pike/code delete mode 100644 test/expected_dir/pike2.pmod/pike/comment create mode 100644 test/expected_dir/py1.py delete mode 100644 test/expected_dir/py1.py/python/blanks delete mode 100644 test/expected_dir/py1.py/python/code delete mode 100644 test/expected_dir/py1.py/python/comment create mode 100644 test/expected_dir/rexx1.rex delete mode 100644 test/expected_dir/rexx1.rex/rexx/blanks delete mode 100644 test/expected_dir/rexx1.rex/rexx/code delete mode 100644 test/expected_dir/rexx1.rex/rexx/comment create mode 100644 test/expected_dir/rhtml1.rhtml delete mode 100644 test/expected_dir/rhtml1.rhtml/html/blanks delete mode 100644 test/expected_dir/rhtml1.rhtml/html/code delete mode 100644 test/expected_dir/rhtml1.rhtml/html/comment delete mode 100644 test/expected_dir/rhtml1.rhtml/ruby/code delete mode 100644 test/expected_dir/rhtml1.rhtml/ruby/comment create mode 100644 test/expected_dir/ruby1.rb delete mode 100644 test/expected_dir/ruby1.rb/ruby/blanks delete mode 100644 test/expected_dir/ruby1.rb/ruby/code delete mode 100644 test/expected_dir/ruby1.rb/ruby/comment create mode 100644 test/expected_dir/scala1.scala delete mode 100644 test/expected_dir/scala1.scala/scala/blanks delete mode 100644 test/expected_dir/scala1.scala/scala/code delete mode 100644 test/expected_dir/scala1.scala/scala/comment create mode 100644 test/expected_dir/schema.xsd delete mode 100644 test/expected_dir/schema.xsd/xmlschema/blanks delete mode 100644 test/expected_dir/schema.xsd/xmlschema/code delete mode 100644 test/expected_dir/schema.xsd/xmlschema/comment create mode 100644 test/expected_dir/scheme.scm delete mode 100644 test/expected_dir/scheme.scm/scheme/blanks delete mode 100644 test/expected_dir/scheme.scm/scheme/code delete mode 100644 test/expected_dir/scheme.scm/scheme/comment create mode 100644 test/expected_dir/sh1.sh delete mode 100644 test/expected_dir/sh1.sh/shell/blanks delete mode 100644 test/expected_dir/sh1.sh/shell/code delete mode 100644 test/expected_dir/sh1.sh/shell/comment create mode 100644 test/expected_dir/smalltalk1.st delete mode 100644 test/expected_dir/smalltalk1.st/smalltalk/blanks delete mode 100644 test/expected_dir/smalltalk1.st/smalltalk/code delete mode 100644 test/expected_dir/smalltalk1.st/smalltalk/comment create mode 100644 test/expected_dir/sql1.sql delete mode 100644 test/expected_dir/sql1.sql/sql/blanks delete mode 100644 test/expected_dir/sql1.sql/sql/code delete mode 100644 test/expected_dir/sql1.sql/sql/comment create mode 100644 test/expected_dir/stratego.str delete mode 100644 test/expected_dir/stratego.str/stratego/blanks delete mode 100644 test/expected_dir/stratego.str/stratego/code delete mode 100644 test/expected_dir/stratego.str/stratego/comment create mode 100644 test/expected_dir/structured_basic.b delete mode 100644 test/expected_dir/structured_basic.b/structured_basic/blanks delete mode 100644 test/expected_dir/structured_basic.b/structured_basic/code delete mode 100644 test/expected_dir/structured_basic.b/structured_basic/comment create mode 100644 test/expected_dir/structured_basic.bas delete mode 100644 test/expected_dir/structured_basic.bas/structured_basic/blanks delete mode 100644 test/expected_dir/structured_basic.bas/structured_basic/code delete mode 100644 test/expected_dir/structured_basic.bas/structured_basic/comment create mode 100644 test/expected_dir/tcl1.tcl delete mode 100644 test/expected_dir/tcl1.tcl/tcl/blanks delete mode 100644 test/expected_dir/tcl1.tcl/tcl/code delete mode 100644 test/expected_dir/tcl1.tcl/tcl/comment create mode 100644 test/expected_dir/vala1.vala delete mode 100644 test/expected_dir/vala1.vala/vala/blanks delete mode 100644 test/expected_dir/vala1.vala/vala/code delete mode 100644 test/expected_dir/vala1.vala/vala/comment create mode 100644 test/expected_dir/vb1.vb create mode 100644 test/expected_dir/vbs1.vbs create mode 100644 test/expected_dir/vhdl1.vhd delete mode 100644 test/expected_dir/vhdl1.vhd/vhdl/blanks delete mode 100644 test/expected_dir/vhdl1.vhd/vhdl/code delete mode 100644 test/expected_dir/vhdl1.vhd/vhdl/comment create mode 100644 test/expected_dir/vhdl1.vhdl delete mode 100644 test/expected_dir/vhdl1.vhdl/vhdl/blanks delete mode 100644 test/expected_dir/vhdl1.vhdl/vhdl/code delete mode 100644 test/expected_dir/vhdl1.vhdl/vhdl/comment create mode 100644 test/expected_dir/visual_basic.bas delete mode 100644 test/expected_dir/visual_basic.bas/visualbasic/blanks delete mode 100644 test/expected_dir/visual_basic.bas/visualbasic/code delete mode 100644 test/expected_dir/visual_basic.bas/visualbasic/comment create mode 100644 test/expected_dir/xml1.xml delete mode 100644 test/expected_dir/xml1.xml/xml/blanks delete mode 100644 test/expected_dir/xml1.xml/xml/code delete mode 100644 test/expected_dir/xml1.xml/xml/comment delete mode 100644 test/unit/diff_test.rb diff --git a/bin/ohcount b/bin/ohcount index fda731c..7f73791 100755 --- a/bin/ohcount +++ b/bin/ohcount @@ -92,7 +92,8 @@ class OhcountCommandLine # Licenses def licenses files.each do |file| - licenses = LicenseSniffer.licenses_from_source_code(file, files) + sfc = Ohcount::SimpleFileContext.new(file, files) + licenses = LicenseSniffer.parse(sfc.contents, Ohcount::Detector.detect(sfc)) if licenses.any? symbols = licenses.collect { |l| LicenseSniffer::LicenseMap.instance.map[l].symbol }.join(",") puts "#{symbols}\t#{file}" diff --git a/lib/licenses/license_sniffer.rb b/lib/licenses/license_sniffer.rb index 25e6b9e..8886360 100644 --- a/lib/licenses/license_sniffer.rb +++ b/lib/licenses/license_sniffer.rb @@ -50,20 +50,12 @@ def self.sniff(s) ranges.collect { |r| r[0] }.compact.uniq end - def self.sniff_file(filename) - File.open(filename) do |io| - return sniff(io.read) - end - end - - def self.licenses_from_source_code(file, files = []) - sfc = Ohcount::SimpleFileContext.new(file, files) - polyglot = Ohcount::Detector.detect(sfc) - return [] unless polyglot + def self.parse(buffer, polyglot) + return [] unless polyglot comments = '' - Ohcount::parse_entities(sfc.contents, polyglot) do |language, entity, s, e| + Ohcount::parse_entities(buffer, polyglot) do |language, entity, s, e| if entity == :comment - text = sfc.contents[s...e] # e is non-inclusive, so use ... + text = buffer[s...e] # e is non-inclusive, so use ... text.split(/[\r\n\f]+/).each do |line| # Strip leading punctuation. comments << ' ' + $1 if line =~ /^[\s[:punct:]]*(.*?)$/ @@ -72,5 +64,4 @@ def self.licenses_from_source_code(file, files = []) end sniff(comments) end - end diff --git a/lib/ohcount.rb b/lib/ohcount.rb index e6a6f1c..8db7bcf 100644 --- a/lib/ohcount.rb +++ b/lib/ohcount.rb @@ -12,11 +12,9 @@ module Ohcount end require OHCOUNT_ROOT + "/lib/ohcount/detector" -require OHCOUNT_ROOT + "/lib/ohcount/parser" require OHCOUNT_ROOT + "/lib/ohcount/language_breakdown" require OHCOUNT_ROOT + "/lib/ohcount/sloc_info" require OHCOUNT_ROOT + "/lib/ohcount/scratch_dir" -require OHCOUNT_ROOT + "/lib/ohcount/diff" require OHCOUNT_ROOT + "/lib/ohcount/simple_file_context" require OHCOUNT_ROOT + "/lib/licenses/license_sniffer" diff --git a/lib/ohcount/diff.rb b/lib/ohcount/diff.rb deleted file mode 100644 index 3e1ca28..0000000 --- a/lib/ohcount/diff.rb +++ /dev/null @@ -1,115 +0,0 @@ -module Ohcount - - def self.diff_files(old_filename, new_filename) - langs = {} - ScratchDir.new do |old_dir| - ScratchDir.new do |new_dir| - old_buffer = File.new(old_filename).read - old_polyglot = Ohcount::Detector.detect(SimpleFileContext.new(old_filename)) - Ohcount::Parser.parse_to_dir(:dir => old_dir, - :buffer => old_buffer, - :polyglot => old_polyglot) - new_buffer = File.new(new_filename).read - new_polyglot = Ohcount::Detector.detect(SimpleFileContext.new(new_filename)) - Ohcount::Parser.parse_to_dir(:dir => new_dir, - :buffer => new_buffer, - :polyglot => new_polyglot) - langs = diff_sloc_dirs(old_dir, new_dir) - end - end - langs - end - - protected - - def self.blank_diffs(new_file, old_file) - # blanks are stored as a simple string - old_blanks = new_blanks = 0 - if old_file != "/dev/null" && FileTest.file?(old_file) - File.open(old_file) do |io| - old_blanks = io.read.to_i - end - end - if new_file != "/dev/null" && FileTest.file?(new_file) - File.open(new_file) do |io| - new_blanks = io.read.to_i - end - end - blanks_changed = new_blanks - old_blanks - blanks_added = blanks_changed > 0 ? blanks_changed : 0 - blanks_removed = blanks_changed < 0 ? -blanks_changed : 0 - [blanks_added, blanks_removed] - end - - - def self.get_langs(dir) - return {} if dir.nil? - langs = {} - Dir.foreach(dir) do |l| - next unless File.directory?(dir + "/" + l) - next if [".", ".."].include?(l) - langs[l] ||= {} - Dir.foreach(dir + "/" + l) do |s| - next if [".", ".."].include?(s) - langs[l][s] = nil - end - end - langs - end - - def self.diff_sloc_dirs(old_dir, new_dir) - # figure out the superset of all languages and semantics we're dealing with (on old and new) - langs = {} - langs.merge!(get_langs(old_dir)) - langs.merge!(get_langs(new_dir)) - - # now go through each and tally up the added/removed - sloc_infos = [] - langs.each do |lang, semantics| - next if lang == "_file" # this is a special case... - sloc_info = SlocInfo.new(lang) - - semantics.each_key do |s| - old_file = old_dir ? File.join(old_dir, lang, s) : '/dev/null' - new_file = new_dir ? File.join(new_dir, lang, s) : '/dev/null' - if s == 'blanks' - sloc_info.blanks_added, sloc_info.blanks_removed = blank_diffs(new_file, old_file) - else - added_removed = diff_file(old_file, new_file) - case s - when 'code' - sloc_info.code_added, sloc_info.code_removed = added_removed - when 'comment' - sloc_info.comments_added, sloc_info.comments_removed = added_removed - else - raise RuntimeError.new("unknown semantic: #{ s }") - end - end - end - sloc_infos << sloc_info unless sloc_info.empty? - end - - # sort them -- nice thing to do - sloc_infos.sort do |a,b| - a.language <=> b.language - end - end - - def self.diff_file(old, new) - added = removed = 0 - - if FileTest.file?(old) == false - # original file doesn't exist -> return all new lines as added - added = `cat '#{ new }' | wc -l`.strip.to_i - elsif FileTest.file?(new) == false - # new file doesn't exist -> return all old lines as deleted - removed = `cat '#{ old }' | wc -l`.strip.to_i - else - cmd = "diff -d --normal --suppress-common-lines --new-file '#{old}' '#{new}' | grep '^>' | wc -l" - added = `#{cmd}`.to_i - cmd = "diff -d --normal --suppress-common-lines --new-file '#{old}' '#{new}' | grep '^<' | wc -l" - removed = `#{cmd}`.to_i - end - [added, removed] - end -end diff --git a/lib/ohcount/parser.rb b/lib/ohcount/parser.rb deleted file mode 100644 index f6782d2..0000000 --- a/lib/ohcount/parser.rb +++ /dev/null @@ -1,62 +0,0 @@ -require 'yaml' - -class Ohcount::Parser - # Parses a file, and store the results in files on disk. - # - # This method primarily exists for the benefit of the Ohloh analysis engine, - # which prefers to store interim results in files on disk. It is unlikely to be - # useful to the general public. - # - # A subdirectory is created for each language found in the target file. - # Within each language subdirectory, separate files are created for code, comments, and blanks. - # - # The 'code' file contains code lines, the 'comments' file contains comment lines, and the 'blanks' - # file contains a count of the number of blank lines in the file. - def self.parse_to_dir(args) - required_arg_keys = [ - :dir, # directory to parse to - :buffer, # buffer contents of the what we're parsing - :polyglot # the polyglot name of what we're parsing - ] - raise ArgumentError.new('Missing required args') unless (required_arg_keys - args.keys).empty? - - polyglot = args[:polyglot].to_s - dir = args[:dir] - buffer = args[:buffer].to_s - find_licenses = args[:find_licenses].to_s - - licenses = [] - Ohcount::parse(buffer, polyglot).each do |lb| - lb_dest_dir = dir + "/" + lb.name - Dir.mkdir(lb_dest_dir) - if (lb.code) - File.open(lb_dest_dir + "/code", "w") do |io| - code = lb.code - io.write code - io.write "\n" unless (code.size == 0 || code[-1,1] == "\n") - end - end - if (lb.comment) - File.open(lb_dest_dir + "/comment", "w") do |io| - comment = lb.comment - io.write comment - io.write "\n" unless (comment.size == 0 || comment[-1,1] == "\n") - end - - # find licenses if required - licenses += LicenseSniffer.sniff(lb.comment) if find_licenses - end - File.open(lb_dest_dir + "/blanks", "w") do |io| - io.write lb.blanks.to_s - end - end - - if licenses.any? - licenses.uniq! - File.open(dir + "/licenses.yaml", "w") do |io| - io.write licenses.to_yaml - end - end - - end -end diff --git a/test/.gitignore b/test/.gitignore index bdb225c..e69de29 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -1 +0,0 @@ -scratch_dir diff --git a/test/expected_dir/Makefile b/test/expected_dir/Makefile new file mode 100644 index 0000000..97d02ab --- /dev/null +++ b/test/expected_dir/Makefile @@ -0,0 +1,5 @@ +make comment # This is a makefile. +make blank +make code giant_space_monkey : giant_space_monkey.c +make code $(CC) $(CFLAGS) -o $@ $? +make blank diff --git a/test/expected_dir/Makefile.am b/test/expected_dir/Makefile.am new file mode 100644 index 0000000..56cfea6 --- /dev/null +++ b/test/expected_dir/Makefile.am @@ -0,0 +1,3 @@ +automake comment # This is an automake file +automake code EXTRA_DIST = giant-space-monkey.txt +automake blank diff --git a/test/expected_dir/Makefile.am/automake/blanks b/test/expected_dir/Makefile.am/automake/blanks deleted file mode 100644 index 56a6051..0000000 --- a/test/expected_dir/Makefile.am/automake/blanks +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/test/expected_dir/Makefile.am/automake/code b/test/expected_dir/Makefile.am/automake/code deleted file mode 100644 index e6b32ce..0000000 --- a/test/expected_dir/Makefile.am/automake/code +++ /dev/null @@ -1 +0,0 @@ -EXTRA_DIST = giant-space-monkey.txt diff --git a/test/expected_dir/Makefile.am/automake/comment b/test/expected_dir/Makefile.am/automake/comment deleted file mode 100644 index c32b529..0000000 --- a/test/expected_dir/Makefile.am/automake/comment +++ /dev/null @@ -1 +0,0 @@ -# This is an automake file diff --git a/test/expected_dir/Makefile/make/blanks b/test/expected_dir/Makefile/make/blanks deleted file mode 100644 index d8263ee..0000000 --- a/test/expected_dir/Makefile/make/blanks +++ /dev/null @@ -1 +0,0 @@ -2 \ No newline at end of file diff --git a/test/expected_dir/Makefile/make/code b/test/expected_dir/Makefile/make/code deleted file mode 100644 index 6bb19be..0000000 --- a/test/expected_dir/Makefile/make/code +++ /dev/null @@ -1,2 +0,0 @@ -giant_space_monkey : giant_space_monkey.c -$(CC) $(CFLAGS) -o $@ $? diff --git a/test/expected_dir/Makefile/make/comment b/test/expected_dir/Makefile/make/comment deleted file mode 100644 index 78b015b..0000000 --- a/test/expected_dir/Makefile/make/comment +++ /dev/null @@ -1 +0,0 @@ -# This is a makefile. diff --git a/test/expected_dir/ada1.ada b/test/expected_dir/ada1.ada new file mode 100644 index 0000000..82f38b6 --- /dev/null +++ b/test/expected_dir/ada1.ada @@ -0,0 +1,18 @@ +ada code with Ada.Text_IO; use Ada.Text_IO; +ada blank +ada code procedure Get_Name is +ada blank +ada code Name : String (1..80); +ada code Length : Integer; +ada blank +ada code begin +ada comment -- no variables needed here :) +ada blank +ada code Put ("Enter your first name> "); +ada code Get_Line (Name, Length); +ada code New_Line; +ada code Put ("Hello "); +ada code Put (Name (1..Length)); +ada code Put (", we hope that you enjoy learning Ada!"); +ada blank +ada code end Get_Name; diff --git a/test/expected_dir/ada1.ada/ada/blanks b/test/expected_dir/ada1.ada/ada/blanks deleted file mode 100644 index 7813681..0000000 --- a/test/expected_dir/ada1.ada/ada/blanks +++ /dev/null @@ -1 +0,0 @@ -5 \ No newline at end of file diff --git a/test/expected_dir/ada1.ada/ada/code b/test/expected_dir/ada1.ada/ada/code deleted file mode 100644 index 1dc1471..0000000 --- a/test/expected_dir/ada1.ada/ada/code +++ /dev/null @@ -1,12 +0,0 @@ -with Ada.Text_IO; use Ada.Text_IO; -procedure Get_Name is -Name : String (1..80); -Length : Integer; -begin -Put ("Enter your first name> "); -Get_Line (Name, Length); -New_Line; -Put ("Hello "); -Put (Name (1..Length)); -Put (", we hope that you enjoy learning Ada!"); -end Get_Name; diff --git a/test/expected_dir/ada1.ada/ada/comment b/test/expected_dir/ada1.ada/ada/comment deleted file mode 100644 index 3634d72..0000000 --- a/test/expected_dir/ada1.ada/ada/comment +++ /dev/null @@ -1 +0,0 @@ --- no variables needed here :) diff --git a/test/expected_dir/ada1.adb b/test/expected_dir/ada1.adb new file mode 100644 index 0000000..82f38b6 --- /dev/null +++ b/test/expected_dir/ada1.adb @@ -0,0 +1,18 @@ +ada code with Ada.Text_IO; use Ada.Text_IO; +ada blank +ada code procedure Get_Name is +ada blank +ada code Name : String (1..80); +ada code Length : Integer; +ada blank +ada code begin +ada comment -- no variables needed here :) +ada blank +ada code Put ("Enter your first name> "); +ada code Get_Line (Name, Length); +ada code New_Line; +ada code Put ("Hello "); +ada code Put (Name (1..Length)); +ada code Put (", we hope that you enjoy learning Ada!"); +ada blank +ada code end Get_Name; diff --git a/test/expected_dir/ada1.adb/ada/blanks b/test/expected_dir/ada1.adb/ada/blanks deleted file mode 100644 index 7813681..0000000 --- a/test/expected_dir/ada1.adb/ada/blanks +++ /dev/null @@ -1 +0,0 @@ -5 \ No newline at end of file diff --git a/test/expected_dir/ada1.adb/ada/code b/test/expected_dir/ada1.adb/ada/code deleted file mode 100644 index 1dc1471..0000000 --- a/test/expected_dir/ada1.adb/ada/code +++ /dev/null @@ -1,12 +0,0 @@ -with Ada.Text_IO; use Ada.Text_IO; -procedure Get_Name is -Name : String (1..80); -Length : Integer; -begin -Put ("Enter your first name> "); -Get_Line (Name, Length); -New_Line; -Put ("Hello "); -Put (Name (1..Length)); -Put (", we hope that you enjoy learning Ada!"); -end Get_Name; diff --git a/test/expected_dir/ada1.adb/ada/comment b/test/expected_dir/ada1.adb/ada/comment deleted file mode 100644 index 3634d72..0000000 --- a/test/expected_dir/ada1.adb/ada/comment +++ /dev/null @@ -1 +0,0 @@ --- no variables needed here :) diff --git a/test/expected_dir/as1.as b/test/expected_dir/as1.as new file mode 100644 index 0000000..cd3be39 --- /dev/null +++ b/test/expected_dir/as1.as @@ -0,0 +1,140 @@ +actionscript comment /* SVN FILE: $Id: FakeObject.as 42 2008-03-26 03:18:02Z xpointsh $ */ +actionscript comment /** +actionscript comment * Description +actionscript comment * +actionscript comment * Fake +actionscript comment * Copyright 2008, Sean Chatman and Garrett Woodworth +actionscript comment * +actionscript comment * Licensed under The MIT License +actionscript comment * Redistributions of files must retain the above copyright notice. +actionscript comment * +actionscript comment * @filesource +actionscript comment * @copyright Copyright 2008, Sean Chatman and Garrett Woodworth +actionscript comment * @link http://code.google.com/p/fake-as3/ +actionscript comment * @package fake +actionscript comment * @subpackage com.fake +actionscript comment * @since 2008-03-06 +actionscript comment * @version $Revision: 42 $ +actionscript comment * @modifiedby $LastChangedBy: xpointsh $ +actionscript comment * @lastmodified $Date: 2008-03-25 20:18:02 -0700 (Tue, 25 Mar 2008) $ +actionscript comment * @license http://www.opensource.org/licenses/mit-license.php The MIT License +actionscript comment */ +actionscript code package com.fake +actionscript code { +actionscript code import flash.utils.*; +actionscript blank +actionscript comment /** +actionscript comment * FakeObject is the root object for all classes +actionscript comment * in Fake. It contains a reference to the class name +actionscript comment * and class object. These are obtained by using the +actionscript comment * reflection classes in flash.utils. +actionscript comment */ +actionscript code public dynamic class FakeObject extends Proxy +actionscript code { +actionscript comment /** +actionscript comment * The name of the top level subclass +actionscript comment */ +actionscript code [Transient] public var className:String; +actionscript comment /** +actionscript comment * A reference to the top level subclass +actionscript comment */ +actionscript code [Transient] public var ClassRef:Class; +actionscript blank +actionscript code private var __item:Array; +actionscript blank +actionscript code public function FakeObject() +actionscript code { +actionscript code getClassInfo(); +actionscript code __item = new Array(); +actionscript code } +actionscript blank +actionscript comment /** +actionscript comment * This method is called by the constructor. Populates the className and ClassRef using +actionscript comment * getQualifiedClassName and getDefinitionByName +actionscript comment */ +actionscript code private function getClassInfo():void +actionscript code { +actionscript code var qcName:Array = getQualifiedClassName(this).split("::"); +actionscript code className = qcName[1]; +actionscript blank +actionscript code var classPath:String = getQualifiedClassName(this).replace( "::", "." ); +actionscript code ClassRef = getDefinitionByName(classPath) as Class; +actionscript code } +actionscript blank +actionscript comment /** +actionscript comment * Override the callProperty of the flash_proxy +actionscript comment * @param method +actionscript comment * @param args +actionscript comment * @return +actionscript comment * +actionscript comment */ +actionscript code override flash_proxy function callProperty(method: *, ...args):* +actionscript code { +actionscript code try +actionscript code { +actionscript code return ClassRef.prototype[method].apply(method, args); +actionscript code } +actionscript code catch (e:Error) +actionscript code { +actionscript code return overload(method, args); +actionscript code } +actionscript code } +actionscript blank +actionscript comment /** +actionscript comment * To be overriden by subclasses. Allows calling any method on any object that extends FakeOject +actionscript comment * @param method +actionscript comment * @param args +actionscript comment * +actionscript comment */ +actionscript code protected function overload(method:*, args:Array):void +actionscript code { +actionscript code } +actionscript blank +actionscript comment /** +actionscript comment * get a property on the object +actionscript comment * @param name +actionscript comment * @return +actionscript comment * +actionscript comment */ +actionscript code override flash_proxy function getProperty(name:*):* +actionscript code { +actionscript code return overloadGetProperty(name); +actionscript code } +actionscript blank +actionscript code protected function overloadGetProperty(name:*):* +actionscript code { +actionscript code return __item[name]; +actionscript code } +actionscript blank +actionscript comment /** +actionscript comment * Set a property on the object +actionscript comment * @param name +actionscript comment * @param value +actionscript comment * +actionscript comment */ +actionscript code override flash_proxy function setProperty(name:*, value:*):void +actionscript code { +actionscript code overloadSetProperty(name, value) +actionscript code } +actionscript blank +actionscript code protected function overloadSetProperty(name:*, value:*):void +actionscript code { +actionscript code __item[name] = value; +actionscript code } +actionscript blank +actionscript comment /** +actionscript comment * Check if the property exits +actionscript comment * @param name +actionscript comment * @param value +actionscript comment * +actionscript comment */ +actionscript code override flash_proxy function hasProperty(name:*):Boolean +actionscript code { +actionscript code if (__item[name]) +actionscript code { +actionscript code return true; +actionscript code } +actionscript code return false; +actionscript code } +actionscript code } +actionscript code } diff --git a/test/expected_dir/as1.as/actionscript/code b/test/expected_dir/as1.as/actionscript/code deleted file mode 100644 index 69eed6e..0000000 --- a/test/expected_dir/as1.as/actionscript/code +++ /dev/null @@ -1,60 +0,0 @@ -package com.fake -{ -import flash.utils.*; -public dynamic class FakeObject extends Proxy -{ -[Transient] public var className:String; -[Transient] public var ClassRef:Class; -private var __item:Array; -public function FakeObject() -{ -getClassInfo(); -__item = new Array(); -} -private function getClassInfo():void -{ -var qcName:Array = getQualifiedClassName(this).split("::"); -className = qcName[1]; -var classPath:String = getQualifiedClassName(this).replace( "::", "." ); -ClassRef = getDefinitionByName(classPath) as Class; -} -override flash_proxy function callProperty(method: *, ...args):* -{ -try -{ -return ClassRef.prototype[method].apply(method, args); -} -catch (e:Error) -{ -return overload(method, args); -} -} -protected function overload(method:*, args:Array):void -{ -} -override flash_proxy function getProperty(name:*):* -{ -return overloadGetProperty(name); -} -protected function overloadGetProperty(name:*):* -{ -return __item[name]; -} -override flash_proxy function setProperty(name:*, value:*):void -{ -overloadSetProperty(name, value) -} -protected function overloadSetProperty(name:*, value:*):void -{ -__item[name] = value; -} -override flash_proxy function hasProperty(name:*):Boolean -{ -if (__item[name]) -{ -return true; -} -return false; -} -} -} diff --git a/test/expected_dir/as1.as/actionscript/comment b/test/expected_dir/as1.as/actionscript/comment deleted file mode 100644 index a59a041..0000000 --- a/test/expected_dir/as1.as/actionscript/comment +++ /dev/null @@ -1,68 +0,0 @@ -/* SVN FILE: $Id: FakeObject.as 42 2008-03-26 03:18:02Z xpointsh $ */ -/** -* Description -* -* Fake -* Copyright 2008, Sean Chatman and Garrett Woodworth -* -* Licensed under The MIT License -* Redistributions of files must retain the above copyright notice. -* -* @filesource -* @copyright Copyright 2008, Sean Chatman and Garrett Woodworth -* @link http://code.google.com/p/fake-as3/ -* @package fake -* @subpackage com.fake -* @since 2008-03-06 -* @version $Revision: 42 $ -* @modifiedby $LastChangedBy: xpointsh $ -* @lastmodified $Date: 2008-03-25 20:18:02 -0700 (Tue, 25 Mar 2008) $ -* @license http://www.opensource.org/licenses/mit-license.php The MIT License -*/ -/** -* FakeObject is the root object for all classes -* in Fake. It contains a reference to the class name -* and class object. These are obtained by using the -* reflection classes in flash.utils. -*/ -/** -* The name of the top level subclass -*/ -/** -* A reference to the top level subclass -*/ -/** -* This method is called by the constructor. Populates the className and ClassRef using -* getQualifiedClassName and getDefinitionByName -*/ -/** -* Override the callProperty of the flash_proxy -* @param method -* @param args -* @return -* -*/ -/** -* To be overriden by subclasses. Allows calling any method on any object that extends FakeOject -* @param method -* @param args -* -*/ -/** -* get a property on the object -* @param name -* @return -* -*/ -/** -* Set a property on the object -* @param name -* @param value -* -*/ -/** -* Check if the property exits -* @param name -* @param value -* -*/ diff --git a/test/expected_dir/assembler1.asm b/test/expected_dir/assembler1.asm new file mode 100644 index 0000000..7e89a5b --- /dev/null +++ b/test/expected_dir/assembler1.asm @@ -0,0 +1,68 @@ +assembler comment ; int gcdAsm(int a, int b) +assembler comment ; +assembler comment ; computes gcd(a,b) according to: +assembler comment ; 1. a even, b even: gcd(a,b) = 2 * gcd(a/2,b/2), +assembler comment ; and remember how often this happened +assembler comment ; 2. a even, b uneven: gcd(a,b) = gcd(a/2,b) +assembler comment ; 3. a uneven, b even: gcd(a,b) = gcd(a,b/2) +assembler comment ; 4. a uneven, b uneven: a>b ? a -= b : b -= a, +assembler comment ; i.e. gcd(a,b) = gcd(min(a,b),max(a,b) - min(a,b)) +assembler comment ; do 1., repeat 2. - 4. until a = 0 or b = 0 +assembler comment ; return (a + b) corrected by the remembered value from 1. +assembler blank +assembler code BITS 32 +assembler code GLOBAL _gcdAsm +assembler blank +assembler code SECTION .text +assembler code _gcdAsm: +assembler code push ebp +assembler code mov ebp,esp +assembler code push ebx +assembler code push ecx +assembler code push edx +assembler code push edi +assembler code mov eax,[ebp + 8] ; eax = a (0 <= a <= 2^31 - 1) +assembler code mov ebx,[ebp + 12] ; ebx = b (0 <= b <= 2^31 - 1) +assembler comment ; by definition: gcd(a,0) = a, gcd(0,b) = b, gcd(0,0) = 1 ! +assembler code mov ecx,eax +assembler code or ecx,ebx +assembler code bsf ecx,ecx ; greatest common power of 2 of a and b +assembler code jnz notBoth0 +assembler code mov eax,1 ; if a = 0 and b = 0, return 1 +assembler code jmp done +assembler code notBoth0: +assembler code mov edi,ecx +assembler code test eax,eax +assembler code jnz aNot0 +assembler code mov eax,ebx ; if a = 0, return b +assembler code jmp done +assembler code aNot0: +assembler code test ebx,ebx +assembler code jz done ; if b = 0, return a +assembler code bsf ecx,eax ; "simplify" a as much as possible +assembler code shr eax,cl +assembler code bsf ecx,ebx ; "simplify" b as much as possible +assembler code shr ebx,cl +assembler code mainLoop: +assembler code mov ecx,ebx +assembler code sub ecx,eax ; b - a +assembler code sbb edx,edx ; edx = 0 if b >= a or -1 if a > b +assembler code and ecx,edx ; ecx = 0 if b >= a or b - a if a > b +assembler code add eax,ecx ; a-new = min(a,b) +assembler code sub ebx,ecx ; b-new = max(a,b) +assembler code sub ebx,eax ; the difference is >= 0 +assembler code bsf ecx,eax ; "simplify" as much as possible by 2 +assembler code shr eax,cl +assembler code bsf ecx,ebx ; "simplify" as much as possible by 2 +assembler code shr ebx,cl +assembler code jnz mainLoop ; keep looping until ebx = 0 +assembler code mov ecx,edi ; shift back with common power of 2 +assembler code shl eax,cl +assembler code done: +assembler code pop edi +assembler code pop edx +assembler code pop ecx +assembler code pop ebx +assembler code mov esp,ebp +assembler code pop ebp +assembler code ret ; eax = gcd(a,b) diff --git a/test/expected_dir/assembler1.asm/assembler/blanks b/test/expected_dir/assembler1.asm/assembler/blanks deleted file mode 100644 index d8263ee..0000000 --- a/test/expected_dir/assembler1.asm/assembler/blanks +++ /dev/null @@ -1 +0,0 @@ -2 \ No newline at end of file diff --git a/test/expected_dir/assembler1.asm/assembler/code b/test/expected_dir/assembler1.asm/assembler/code deleted file mode 100644 index 3ac6e84..0000000 --- a/test/expected_dir/assembler1.asm/assembler/code +++ /dev/null @@ -1,54 +0,0 @@ -BITS 32 -GLOBAL _gcdAsm -SECTION .text -_gcdAsm: -push ebp -mov ebp,esp -push ebx -push ecx -push edx -push edi -mov eax,[ebp + 8] ; eax = a (0 <= a <= 2^31 - 1) -mov ebx,[ebp + 12] ; ebx = b (0 <= b <= 2^31 - 1) -mov ecx,eax -or ecx,ebx -bsf ecx,ecx ; greatest common power of 2 of a and b -jnz notBoth0 -mov eax,1 ; if a = 0 and b = 0, return 1 -jmp done -notBoth0: -mov edi,ecx -test eax,eax -jnz aNot0 -mov eax,ebx ; if a = 0, return b -jmp done -aNot0: -test ebx,ebx -jz done ; if b = 0, return a -bsf ecx,eax ; "simplify" a as much as possible -shr eax,cl -bsf ecx,ebx ; "simplify" b as much as possible -shr ebx,cl -mainLoop: -mov ecx,ebx -sub ecx,eax ; b - a -sbb edx,edx ; edx = 0 if b >= a or -1 if a > b -and ecx,edx ; ecx = 0 if b >= a or b - a if a > b -add eax,ecx ; a-new = min(a,b) -sub ebx,ecx ; b-new = max(a,b) -sub ebx,eax ; the difference is >= 0 -bsf ecx,eax ; "simplify" as much as possible by 2 -shr eax,cl -bsf ecx,ebx ; "simplify" as much as possible by 2 -shr ebx,cl -jnz mainLoop ; keep looping until ebx = 0 -mov ecx,edi ; shift back with common power of 2 -shl eax,cl -done: -pop edi -pop edx -pop ecx -pop ebx -mov esp,ebp -pop ebp -ret ; eax = gcd(a,b) diff --git a/test/expected_dir/assembler1.asm/assembler/comment b/test/expected_dir/assembler1.asm/assembler/comment deleted file mode 100644 index 1ffc484..0000000 --- a/test/expected_dir/assembler1.asm/assembler/comment +++ /dev/null @@ -1,12 +0,0 @@ -; int gcdAsm(int a, int b) -; -; computes gcd(a,b) according to: -; 1. a even, b even: gcd(a,b) = 2 * gcd(a/2,b/2), -; and remember how often this happened -; 2. a even, b uneven: gcd(a,b) = gcd(a/2,b) -; 3. a uneven, b even: gcd(a,b) = gcd(a,b/2) -; 4. a uneven, b uneven: a>b ? a -= b : b -= a, -; i.e. gcd(a,b) = gcd(min(a,b),max(a,b) - min(a,b)) -; do 1., repeat 2. - 4. until a = 0 or b = 0 -; return (a + b) corrected by the remembered value from 1. -; by definition: gcd(a,0) = a, gcd(0,b) = b, gcd(0,0) = 1 ! diff --git a/test/expected_dir/assembler2.S b/test/expected_dir/assembler2.S new file mode 100644 index 0000000..80c5ece --- /dev/null +++ b/test/expected_dir/assembler2.S @@ -0,0 +1,7 @@ +assembler comment /******************************************************** +assembler comment Made up assembler file, in the style of linux kernel +assembler comment ********************************************************/ +assembler blank +assembler code #define FOO 43 // they even use whack-whack comments +assembler blank +assembler code mov eax, ecx diff --git a/test/expected_dir/assembler2.S/assembler/blanks b/test/expected_dir/assembler2.S/assembler/blanks deleted file mode 100644 index d8263ee..0000000 --- a/test/expected_dir/assembler2.S/assembler/blanks +++ /dev/null @@ -1 +0,0 @@ -2 \ No newline at end of file diff --git a/test/expected_dir/assembler2.S/assembler/code b/test/expected_dir/assembler2.S/assembler/code deleted file mode 100644 index 92839c8..0000000 --- a/test/expected_dir/assembler2.S/assembler/code +++ /dev/null @@ -1,2 +0,0 @@ -#define FOO 43 // they even use whack-whack comments -mov eax, ecx diff --git a/test/expected_dir/assembler2.S/assembler/comment b/test/expected_dir/assembler2.S/assembler/comment deleted file mode 100644 index f0e9c12..0000000 --- a/test/expected_dir/assembler2.S/assembler/comment +++ /dev/null @@ -1,3 +0,0 @@ -/******************************************************** -Made up assembler file, in the style of linux kernel -********************************************************/ diff --git a/test/expected_dir/awk1.awk b/test/expected_dir/awk1.awk new file mode 100644 index 0000000..24f9d37 --- /dev/null +++ b/test/expected_dir/awk1.awk @@ -0,0 +1,53 @@ +awk comment # prchecks - print formatted checks +awk comment # input: number \t amount \t payee +awk comment # output: eight lines of text for preprinted check forms +awk blank +awk code BEGIN { +awk code FS = "\t" +awk code dashes = sp45 = sprintf("%45s", " ") +awk code gsub(/ /, "-", dashes) # to protect the payee +awk code "date" | getline date # get today's date +awk code split(date, d, " ") +awk code date = d[2] " " d[3] ", " d[6] +awk code initnum() # set up tables for number conversion +awk code } +awk code NF != 3 || $2 >= 1000000 { # illegal data +awk code printf("\nline %d illegal:\n%s\n\nVOID\nVOID\n\n\n", NR, $0) +awk code next # no check printed +awk code } +awk code { printf("\n") # nothing on line 1 +awk code printf("%s%s\n", sp45, $1) # number, indented 45 spaces +awk code printf("%s%s\n", sp45, date) # date, indented 45 spaces +awk code amt = sprintf("%.2f", $2) # formatted amount +awk code printf("Pay to %45.45s $%s\n", $3 dashes, amt) # line 4 +awk code printf("the sum of %s\n", numtowords(amt)) # line 5 +awk code printf("\n\n\n") # lines 6, 7 and 8 +awk code } +awk blank +awk code function numtowords(n, cents, dols) { # n has 2 decimal places +awk code cents = substr(n, length(n)-1, 2) +awk code dols = substr(n, 1, length(n)-3) +awk code if (dols == 0) +awk code return "zero dollars and " cents " cents exactly" +awk code return intowords(dols) " dollars and " cents " cents exactly" +awk code } +awk blank +awk code function intowords(n) { +awk code n = int(n) +awk code if (n >= 1000) +awk code return intowords(n/1000) " thousand " intowords(n%1000) +awk code if (n >= 100) +awk code return intowords(n/100) " hundred " intowords(n%100) +awk code if (n >= 20) +awk code return tens[int(n/10)] " " intowords(n%10) +awk code return nums[n] +awk code } +awk blank +awk code function initnum() { +awk code split("one two three four five six seven eight nine " \ +awk code prchecks "ten eleven twelve thirteen fourteen fifteen " \ +awk code prchecks "sixteen seventeen eighteen nineteen", nums, " ") +awk code split("ten twenty thirty forty fifty sixty " \ +awk code prchecks "seventy eighty ninety", tens, " ") +awk code } +awk blank diff --git a/test/expected_dir/awk1.awk/awk/blanks b/test/expected_dir/awk1.awk/awk/blanks deleted file mode 100644 index 7813681..0000000 --- a/test/expected_dir/awk1.awk/awk/blanks +++ /dev/null @@ -1 +0,0 @@ -5 \ No newline at end of file diff --git a/test/expected_dir/awk1.awk/awk/code b/test/expected_dir/awk1.awk/awk/code deleted file mode 100644 index 71a4dcb..0000000 --- a/test/expected_dir/awk1.awk/awk/code +++ /dev/null @@ -1,45 +0,0 @@ -BEGIN { -FS = "\t" -dashes = sp45 = sprintf("%45s", " ") -gsub(/ /, "-", dashes) # to protect the payee -"date" | getline date # get today's date -split(date, d, " ") -date = d[2] " " d[3] ", " d[6] -initnum() # set up tables for number conversion -} -NF != 3 || $2 >= 1000000 { # illegal data -printf("\nline %d illegal:\n%s\n\nVOID\nVOID\n\n\n", NR, $0) -next # no check printed -} -{ printf("\n") # nothing on line 1 -printf("%s%s\n", sp45, $1) # number, indented 45 spaces -printf("%s%s\n", sp45, date) # date, indented 45 spaces -amt = sprintf("%.2f", $2) # formatted amount -printf("Pay to %45.45s $%s\n", $3 dashes, amt) # line 4 -printf("the sum of %s\n", numtowords(amt)) # line 5 -printf("\n\n\n") # lines 6, 7 and 8 -} -function numtowords(n, cents, dols) { # n has 2 decimal places -cents = substr(n, length(n)-1, 2) -dols = substr(n, 1, length(n)-3) -if (dols == 0) -return "zero dollars and " cents " cents exactly" -return intowords(dols) " dollars and " cents " cents exactly" -} -function intowords(n) { -n = int(n) -if (n >= 1000) -return intowords(n/1000) " thousand " intowords(n%1000) -if (n >= 100) -return intowords(n/100) " hundred " intowords(n%100) -if (n >= 20) -return tens[int(n/10)] " " intowords(n%10) -return nums[n] -} -function initnum() { -split("one two three four five six seven eight nine " \ -prchecks "ten eleven twelve thirteen fourteen fifteen " \ -prchecks "sixteen seventeen eighteen nineteen", nums, " ") -split("ten twenty thirty forty fifty sixty " \ -prchecks "seventy eighty ninety", tens, " ") -} diff --git a/test/expected_dir/awk1.awk/awk/comment b/test/expected_dir/awk1.awk/awk/comment deleted file mode 100644 index 362dc64..0000000 --- a/test/expected_dir/awk1.awk/awk/comment +++ /dev/null @@ -1,3 +0,0 @@ -# prchecks - print formatted checks -# input: number \t amount \t payee -# output: eight lines of text for preprinted check forms diff --git a/test/expected_dir/bat1.bat b/test/expected_dir/bat1.bat new file mode 100644 index 0000000..037c64d --- /dev/null +++ b/test/expected_dir/bat1.bat @@ -0,0 +1,6 @@ +bat comment REM comment 1 +bat comment rem comment 2 +bat comment rEm comment 3 +bat blank +bat code echo not a rem comment! +bat blank diff --git a/test/expected_dir/bat1.bat/bat/blanks b/test/expected_dir/bat1.bat/bat/blanks deleted file mode 100644 index d8263ee..0000000 --- a/test/expected_dir/bat1.bat/bat/blanks +++ /dev/null @@ -1 +0,0 @@ -2 \ No newline at end of file diff --git a/test/expected_dir/bat1.bat/bat/code b/test/expected_dir/bat1.bat/bat/code deleted file mode 100644 index 36802a0..0000000 --- a/test/expected_dir/bat1.bat/bat/code +++ /dev/null @@ -1 +0,0 @@ -echo not a rem comment! diff --git a/test/expected_dir/bat1.bat/bat/comment b/test/expected_dir/bat1.bat/bat/comment deleted file mode 100644 index 49a153e..0000000 --- a/test/expected_dir/bat1.bat/bat/comment +++ /dev/null @@ -1,3 +0,0 @@ -REM comment 1 -rem comment 2 -rEm comment 3 diff --git a/test/expected_dir/boo1.boo b/test/expected_dir/boo1.boo new file mode 100644 index 0000000..083d373 --- /dev/null +++ b/test/expected_dir/boo1.boo @@ -0,0 +1,112 @@ +boo code import System +boo code import System.IO +boo code import Gtk from "gtk-sharp" +boo code import Gdk from "gdk-sharp" +boo code import Glade from "glade-sharp" +boo blank +boo code class StuffBrowser(): +boo code public static final phile = """stuffbrowser.glade""" +boo blank +boo comment //Unfortunately, Gtk does not provide a builtin "IsSupported" function for images. +boo code public static final supportedExtensions = ( ".png", ".jpeg", ".jpg", ".gif", ".tga", ".bmp", ".ico", ".tiff" ) +boo blank +boo code def constructor(): +boo comment //Connect event handlers and mainStuff, aboutDialog, etc, to their respective methods/handlers. +boo code for widget in ("mainStuff", "aboutDialog", "directorySelector"): +boo code gxml = Glade.XML(phile, widget, null) +boo code gxml.Autoconnect(self) +boo blank +boo code def OnStuffClose(sender as object, e as DeleteEventArgs): +boo comment """The user is leaving the application via the Big Red 'X'""" +boo code Application.Quit() +boo blank +boo code def OnStuffQuit(sender as object, e as EventArgs): +boo comment """The user is leaving the application via File-->Quit""" +boo code Application.Quit() +boo blank +boo code def OnAboutActivate(sender as object, e as EventArgs): +boo comment """The user is trying to view the about dialog""" +boo code aboutDialog.Show() +boo blank +boo code def OnAboutDelete(sender as object, e as DeleteEventArgs): +boo code e.RetVal = true +boo code aboutDialog.Hide() +boo blank +boo code def OnAboutResponse(sender as object, e as ResponseArgs): +boo code if e.ResponseId == ResponseType.Close: +boo code aboutDialog.Hide() +boo blank +boo code def OnOpenDirectory(sender as object, e as EventArgs): +boo comment #changed +boo code directorySelector.FileList.Sensitive = false +boo code directorySelector.Show() +boo blank +boo code def OnDirectoryDelete(sender as object, e as DeleteEventArgs): +boo code e.RetVal = true +boo code directorySelector.Hide() //Don't worry, the "Destroy" event will kill it. +boo blank +boo code def OnDirectoryResponse(sender as object, args as ResponseArgs): +boo code directorySelector.Hide() +boo comment #changed +boo code if args.ResponseId == ResponseType.Ok and directorySelector.Filename.Length != 0: +boo code LoadDirectory(directorySelector.Filename) +boo blank +boo code private def LoadDirectory(path as string): +boo comment //Create a new store that has two columns; the first is a Pixbuf (image) the second, a string. +boo code store = ListStore( (Gdk.Pixbuf, string) ) +boo code stuffThumbs.Model = store +boo code cell = CellRendererPixbuf() +boo code column = TreeViewColumn() +boo code column.PackStart(cell, false) +boo blank +boo comment //Bind the element in column 0 of the store to the pixbuf property in this column's CellRendererPixbuf! +boo code column.AddAttribute(cell, "pixbuf", 0) +boo code column.Title = path +boo blank +boo comment //Detach the old column. +boo code if stuffThumbs.GetColumn(0) is not null: +boo code stuffThumbs.RemoveColumn(stuffThumbs.GetColumn(0)) +boo blank +boo comment //Finally, attach the new column so it will be updated in real time. +boo code stuffThumbs.AppendColumn(column) +boo code files = Directory.GetFiles(path) +boo code validFiles = e for e as string in files if System.IO.FileInfo(e).Extension in StuffBrowser.supportedExtensions +boo code parse = do(): +boo code for i as int, file as string in enumerate(validFiles): +boo comment //The using construct ensures that the program's memory size does not inflate wildly out of control. +boo comment //Having these "image" floating around afterwards ensures lots of memory consuming havoc until garbaged collected! +boo comment #changed +boo comment // If we couldn't read a file pass over it. +boo code try: +boo code using image = Gdk.Pixbuf(file): +boo code store.AppendValues( (image.ScaleSimple(128, 128, InterpType.Bilinear), file ) ) +boo code except e: +boo code print " Couldn't read file ${file} " +boo blank +boo code print "Indexing start: ${DateTime.Now}" +boo comment //Update the treeview in real time by starting an asynchronous operation. +boo code parse.BeginInvoke( { print "Indexing complete: ${DateTime.Now}" } ) //Spin off a new thread; fill the progress bar. +boo blank +boo code def OnPictureActivated(sender as object, args as RowActivatedArgs): +boo comment //Grabs the TreeIter object that represents the currently selected node -- icky stuff with "ref" keyword. ;( +boo code x as TreeIter +boo code stuffThumbs.Model.GetIter(x, args.Path) +boo blank +boo comment //In the second column we've stored the filename that represents the thumbnail image in the treeview. +boo comment //Grab this filename and then use it to inform the user what file he's viewing, as well as loading it. +boo code image = stuffThumbs.Model.GetValue(x, 1) as string +boo code stuffImage.Pixbuf = Gdk.Pixbuf(image) +boo code imageName.Text = Path.GetFileName(image) +boo blank +boo comment //All of the widgets we want Autoconnect to hook up to Glade-created widgets in stuffBrowser.glade +boo code [Glade.Widget] aboutDialog as Gtk.Dialog +boo code [Glade.Widget] mainStuff as Gtk.Window +boo code [Glade.Widget] directorySelector as Gtk.FileSelection +boo code [Glade.Widget] stuffImage as Gtk.Image +boo code [Glade.Widget] stuffThumbs as Gtk.TreeView +boo code [Glade.Widget] imageName as Gtk.Label +boo blank +boo comment //Run the application. +boo code Application.Init() +boo code StuffBrowser() +boo code Application.Run() diff --git a/test/expected_dir/boo1.boo/boo/blanks b/test/expected_dir/boo1.boo/boo/blanks deleted file mode 100644 index 2edeafb..0000000 --- a/test/expected_dir/boo1.boo/boo/blanks +++ /dev/null @@ -1 +0,0 @@ -20 \ No newline at end of file diff --git a/test/expected_dir/boo1.boo/boo/code b/test/expected_dir/boo1.boo/boo/code deleted file mode 100644 index eef601b..0000000 --- a/test/expected_dir/boo1.boo/boo/code +++ /dev/null @@ -1,71 +0,0 @@ -import System -import System.IO -import Gtk from "gtk-sharp" -import Gdk from "gdk-sharp" -import Glade from "glade-sharp" -class StuffBrowser(): -public static final phile = """stuffbrowser.glade""" -public static final supportedExtensions = ( ".png", ".jpeg", ".jpg", ".gif", ".tga", ".bmp", ".ico", ".tiff" ) -def constructor(): -for widget in ("mainStuff", "aboutDialog", "directorySelector"): -gxml = Glade.XML(phile, widget, null) -gxml.Autoconnect(self) -def OnStuffClose(sender as object, e as DeleteEventArgs): -Application.Quit() -def OnStuffQuit(sender as object, e as EventArgs): -Application.Quit() -def OnAboutActivate(sender as object, e as EventArgs): -aboutDialog.Show() -def OnAboutDelete(sender as object, e as DeleteEventArgs): -e.RetVal = true -aboutDialog.Hide() -def OnAboutResponse(sender as object, e as ResponseArgs): -if e.ResponseId == ResponseType.Close: -aboutDialog.Hide() -def OnOpenDirectory(sender as object, e as EventArgs): -directorySelector.FileList.Sensitive = false -directorySelector.Show() -def OnDirectoryDelete(sender as object, e as DeleteEventArgs): -e.RetVal = true -directorySelector.Hide() //Don't worry, the "Destroy" event will kill it. -def OnDirectoryResponse(sender as object, args as ResponseArgs): -directorySelector.Hide() -if args.ResponseId == ResponseType.Ok and directorySelector.Filename.Length != 0: -LoadDirectory(directorySelector.Filename) -private def LoadDirectory(path as string): -store = ListStore( (Gdk.Pixbuf, string) ) -stuffThumbs.Model = store -cell = CellRendererPixbuf() -column = TreeViewColumn() -column.PackStart(cell, false) -column.AddAttribute(cell, "pixbuf", 0) -column.Title = path -if stuffThumbs.GetColumn(0) is not null: -stuffThumbs.RemoveColumn(stuffThumbs.GetColumn(0)) -stuffThumbs.AppendColumn(column) -files = Directory.GetFiles(path) -validFiles = e for e as string in files if System.IO.FileInfo(e).Extension in StuffBrowser.supportedExtensions -parse = do(): -for i as int, file as string in enumerate(validFiles): -try: -using image = Gdk.Pixbuf(file): -store.AppendValues( (image.ScaleSimple(128, 128, InterpType.Bilinear), file ) ) -except e: -print " Couldn't read file ${file} " -print "Indexing start: ${DateTime.Now}" -parse.BeginInvoke( { print "Indexing complete: ${DateTime.Now}" } ) //Spin off a new thread; fill the progress bar. -def OnPictureActivated(sender as object, args as RowActivatedArgs): -x as TreeIter -stuffThumbs.Model.GetIter(x, args.Path) -image = stuffThumbs.Model.GetValue(x, 1) as string -stuffImage.Pixbuf = Gdk.Pixbuf(image) -imageName.Text = Path.GetFileName(image) -[Glade.Widget] aboutDialog as Gtk.Dialog -[Glade.Widget] mainStuff as Gtk.Window -[Glade.Widget] directorySelector as Gtk.FileSelection -[Glade.Widget] stuffImage as Gtk.Image -[Glade.Widget] stuffThumbs as Gtk.TreeView -[Glade.Widget] imageName as Gtk.Label -Application.Init() -StuffBrowser() -Application.Run() diff --git a/test/expected_dir/boo1.boo/boo/comment b/test/expected_dir/boo1.boo/boo/comment deleted file mode 100644 index 1852bbc..0000000 --- a/test/expected_dir/boo1.boo/boo/comment +++ /dev/null @@ -1,21 +0,0 @@ -//Unfortunately, Gtk does not provide a builtin "IsSupported" function for images. -//Connect event handlers and mainStuff, aboutDialog, etc, to their respective methods/handlers. -"""The user is leaving the application via the Big Red 'X'""" -"""The user is leaving the application via File-->Quit""" -"""The user is trying to view the about dialog""" -#changed -#changed -//Create a new store that has two columns; the first is a Pixbuf (image) the second, a string. -//Bind the element in column 0 of the store to the pixbuf property in this column's CellRendererPixbuf! -//Detach the old column. -//Finally, attach the new column so it will be updated in real time. -//The using construct ensures that the program's memory size does not inflate wildly out of control. -//Having these "image" floating around afterwards ensures lots of memory consuming havoc until garbaged collected! -#changed -// If we couldn't read a file pass over it. -//Update the treeview in real time by starting an asynchronous operation. -//Grabs the TreeIter object that represents the currently selected node -- icky stuff with "ref" keyword. ;( -//In the second column we've stored the filename that represents the thumbnail image in the treeview. -//Grab this filename and then use it to inform the user what file he's viewing, as well as loading it. -//All of the widgets we want Autoconnect to hook up to Glade-created widgets in stuffBrowser.glade -//Run the application. diff --git a/test/expected_dir/c1.c b/test/expected_dir/c1.c new file mode 100644 index 0000000..f9a91ec --- /dev/null +++ b/test/expected_dir/c1.c @@ -0,0 +1,70 @@ +c code #include /* MQ API header file */ +c comment // +c blank +c code #define NUMBEROFSELECTORS 2 +c blank +c code const MQHCONN Hconn = MQHC_DEF_HCONN; +c blank +c blank +c code static void InquireGetAndPut(char *Message, +c code PMQHOBJ pHobj, +c code char *Object) +c code { +c comment /* Declare local variables */ +c comment /* */ +c code MQLONG SelectorCount = NUMBEROFSELECTORS; +c comment /* Number of selectors */ +c code MQLONG IntAttrCount = NUMBEROFSELECTORS; +c comment /* Number of int attrs */ +c code MQLONG CharAttrLength = 0; +c comment /* Length of char attribute buffer */ +c code MQCHAR *CharAttrs ; +c comment /* Character attribute buffer */ +c code MQLONG SelectorsTable[NUMBEROFSELECTORS]; +c comment /* attribute selectors */ +c code MQLONG IntAttrsTable[NUMBEROFSELECTORS]; +c comment /* integer attributes */ +c code MQLONG CompCode; /* Completion code */ +c code MQLONG Reason; /* Qualifying reason */ +c comment /* */ +c comment /* Open the queue. If successful, do the inquire */ +c comment /* call. */ +c comment /* */ +c comment /* */ +c comment /* Initialize the variables for the inquire */ +c comment /* call: */ +c comment /* - Set SelectorsTable to the attributes whose */ +c comment /* status is */ +c comment /* required */ +c comment /* - All other variables are already set */ +c comment /* */ +c code SelectorsTable[0] = MQIA_INHIBIT_GET; +c code SelectorsTable[1] = MQIA_INHIBIT_PUT; +c comment /* */ +c comment /* Issue the inquire call */ +c comment /* Test the output of the inquire call. If the */ +c comment /* call failed, display an error message */ +c comment /* showing the completion code and reason code,*/ +c comment /* otherwise display the status of the */ +c comment /* INHIBIT-GET and INHIBIT-PUT attributes */ +c comment /* */ +c code MQINQ(Hconn, +c code *pHobj, +c code SelectorCount, +c code SelectorsTable, +c code IntAttrCount, +c code IntAttrsTable, +c code CharAttrLength, +c code CharAttrs, +c code &CompCode, +c code &Reason); +c code if (CompCode != MQCC_OK) +c code { +c code sprintf(Message, MESSAGE_4_E, +c code ERROR_IN_MQINQ, CompCode, Reason); +c code SetMsg(Message); +c code } +c code else +c code { +c comment /* Process the changes */ +c code } /* end if CompCode */ diff --git a/test/expected_dir/c1.c/c/blanks b/test/expected_dir/c1.c/c/blanks deleted file mode 100644 index bf0d87a..0000000 --- a/test/expected_dir/c1.c/c/blanks +++ /dev/null @@ -1 +0,0 @@ -4 \ No newline at end of file diff --git a/test/expected_dir/c1.c/c/code b/test/expected_dir/c1.c/c/code deleted file mode 100644 index b024045..0000000 --- a/test/expected_dir/c1.c/c/code +++ /dev/null @@ -1,36 +0,0 @@ -#include /* MQ API header file */ -#define NUMBEROFSELECTORS 2 -const MQHCONN Hconn = MQHC_DEF_HCONN; -static void InquireGetAndPut(char *Message, -PMQHOBJ pHobj, -char *Object) -{ -MQLONG SelectorCount = NUMBEROFSELECTORS; -MQLONG IntAttrCount = NUMBEROFSELECTORS; -MQLONG CharAttrLength = 0; -MQCHAR *CharAttrs ; -MQLONG SelectorsTable[NUMBEROFSELECTORS]; -MQLONG IntAttrsTable[NUMBEROFSELECTORS]; -MQLONG CompCode; /* Completion code */ -MQLONG Reason; /* Qualifying reason */ -SelectorsTable[0] = MQIA_INHIBIT_GET; -SelectorsTable[1] = MQIA_INHIBIT_PUT; -MQINQ(Hconn, -*pHobj, -SelectorCount, -SelectorsTable, -IntAttrCount, -IntAttrsTable, -CharAttrLength, -CharAttrs, -&CompCode, -&Reason); -if (CompCode != MQCC_OK) -{ -sprintf(Message, MESSAGE_4_E, -ERROR_IN_MQINQ, CompCode, Reason); -SetMsg(Message); -} -else -{ -} /* end if CompCode */ diff --git a/test/expected_dir/c1.c/c/comment b/test/expected_dir/c1.c/c/comment deleted file mode 100644 index e0faeb6..0000000 --- a/test/expected_dir/c1.c/c/comment +++ /dev/null @@ -1,30 +0,0 @@ -// -/* Declare local variables */ -/* */ -/* Number of selectors */ -/* Number of int attrs */ -/* Length of char attribute buffer */ -/* Character attribute buffer */ -/* attribute selectors */ -/* integer attributes */ -/* */ -/* Open the queue. If successful, do the inquire */ -/* call. */ -/* */ -/* */ -/* Initialize the variables for the inquire */ -/* call: */ -/* - Set SelectorsTable to the attributes whose */ -/* status is */ -/* required */ -/* - All other variables are already set */ -/* */ -/* */ -/* Issue the inquire call */ -/* Test the output of the inquire call. If the */ -/* call failed, display an error message */ -/* showing the completion code and reason code,*/ -/* otherwise display the status of the */ -/* INHIBIT-GET and INHIBIT-PUT attributes */ -/* */ -/* Process the changes */ diff --git a/test/expected_dir/c2.h.in b/test/expected_dir/c2.h.in new file mode 100644 index 0000000..f2ee2b0 --- /dev/null +++ b/test/expected_dir/c2.h.in @@ -0,0 +1,15 @@ +c comment /* c2.h.in. */ +c blank +c code #ifndef C2_H +c code #define C2_H +c blank +c comment /* Define to 1 if you have the header file. */ +c code #undef HAVE_INTTYPES_H +c blank +c comment /* Define to 1 if you have the `m' library (-lm). */ +c code #undef HAVE_LIBM +c blank +c comment /* Define to 1 if you have the ANSI C header files. */ +c code #undef STDC_HEADERS +c blank +c code #endif diff --git a/test/expected_dir/c2.h.in/c/blanks b/test/expected_dir/c2.h.in/c/blanks deleted file mode 100644 index 7813681..0000000 --- a/test/expected_dir/c2.h.in/c/blanks +++ /dev/null @@ -1 +0,0 @@ -5 \ No newline at end of file diff --git a/test/expected_dir/c2.h.in/c/code b/test/expected_dir/c2.h.in/c/code deleted file mode 100644 index e256d23..0000000 --- a/test/expected_dir/c2.h.in/c/code +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef C2_H -#define C2_H -#undef HAVE_INTTYPES_H -#undef HAVE_LIBM -#undef STDC_HEADERS -#endif diff --git a/test/expected_dir/c2.h.in/c/comment b/test/expected_dir/c2.h.in/c/comment deleted file mode 100644 index 58f7049..0000000 --- a/test/expected_dir/c2.h.in/c/comment +++ /dev/null @@ -1,4 +0,0 @@ -/* c2.h.in. */ -/* Define to 1 if you have the header file. */ -/* Define to 1 if you have the `m' library (-lm). */ -/* Define to 1 if you have the ANSI C header files. */ diff --git a/test/expected_dir/c_str.c b/test/expected_dir/c_str.c new file mode 100644 index 0000000..d2b92d6 --- /dev/null +++ b/test/expected_dir/c_str.c @@ -0,0 +1,2 @@ +c code p = '"'; +c comment /* this should be a comment */ diff --git a/test/expected_dir/c_str.c/c/blanks b/test/expected_dir/c_str.c/c/blanks deleted file mode 100644 index c227083..0000000 --- a/test/expected_dir/c_str.c/c/blanks +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/test/expected_dir/c_str.c/c/code b/test/expected_dir/c_str.c/c/code deleted file mode 100644 index 4382036..0000000 --- a/test/expected_dir/c_str.c/c/code +++ /dev/null @@ -1 +0,0 @@ -p = '"'; diff --git a/test/expected_dir/c_str.c/c/comment b/test/expected_dir/c_str.c/c/comment deleted file mode 100644 index 1b8db72..0000000 --- a/test/expected_dir/c_str.c/c/comment +++ /dev/null @@ -1 +0,0 @@ -/* this should be a comment */ diff --git a/test/expected_dir/classic_basic.b b/test/expected_dir/classic_basic.b new file mode 100644 index 0000000..9ada6cb --- /dev/null +++ b/test/expected_dir/classic_basic.b @@ -0,0 +1,19 @@ +classic_basic code 10 INPUT "What is your name: "; U$ +classic_basic code 20 PRINT "Hello "; U$ +classic_basic comment 30 REM Test +classic_basic code 40 INPUT "How many stars do you want: "; N +classic_basic code 50 S$ = "" +classic_basic code 60 FOR I = 1 TO N +classic_basic code 70 S$ = S$ + "*" +classic_basic code 80 NEXT I +classic_basic code 90 PRINT S$ +classic_basic comment 100 REM +classic_basic code 110 INPUT "Do you want more stars? "; A$ +classic_basic code 120 IF LEN(A$) = 0 THEN GOTO 110 +classic_basic code 130 A$ = LEFT$(A$, 1) +classic_basic code 140 IF (A$ = "Y") OR (A$ = "y") THEN GOTO 40 +classic_basic code 150 PRINT "Goodbye "; +classic_basic code 160 FOR I = 1 TO 200 +classic_basic code 170 PRINT U$; " "; +classic_basic code 180 NEXT I +classic_basic code 190 PRINT diff --git a/test/expected_dir/classic_basic.b/classic_basic/blanks b/test/expected_dir/classic_basic.b/classic_basic/blanks deleted file mode 100644 index c227083..0000000 --- a/test/expected_dir/classic_basic.b/classic_basic/blanks +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/test/expected_dir/classic_basic.b/classic_basic/code b/test/expected_dir/classic_basic.b/classic_basic/code deleted file mode 100644 index 4ed7d0f..0000000 --- a/test/expected_dir/classic_basic.b/classic_basic/code +++ /dev/null @@ -1,17 +0,0 @@ -10 INPUT "What is your name: "; U$ -20 PRINT "Hello "; U$ -40 INPUT "How many stars do you want: "; N -50 S$ = "" -60 FOR I = 1 TO N -70 S$ = S$ + "*" -80 NEXT I -90 PRINT S$ -110 INPUT "Do you want more stars? "; A$ -120 IF LEN(A$) = 0 THEN GOTO 110 -130 A$ = LEFT$(A$, 1) -140 IF (A$ = "Y") OR (A$ = "y") THEN GOTO 40 -150 PRINT "Goodbye "; -160 FOR I = 1 TO 200 -170 PRINT U$; " "; -180 NEXT I -190 PRINT diff --git a/test/expected_dir/classic_basic.b/classic_basic/comment b/test/expected_dir/classic_basic.b/classic_basic/comment deleted file mode 100644 index e642e19..0000000 --- a/test/expected_dir/classic_basic.b/classic_basic/comment +++ /dev/null @@ -1,2 +0,0 @@ -30 REM Test -100 REM diff --git a/test/expected_dir/classic_basic.bas b/test/expected_dir/classic_basic.bas new file mode 100644 index 0000000..156aef5 --- /dev/null +++ b/test/expected_dir/classic_basic.bas @@ -0,0 +1,20 @@ +classic_basic code 10 INPUT "What is your name: "; U$ +classic_basic code 20 PRINT "Hello "; U$ +classic_basic comment 30 REM Test +classic_basic code 40 INPUT "How many stars do you want: "; N +classic_basic code 50 S$ = "" +classic_basic code 60 FOR I = 1 TO N +classic_basic code 70 S$ = S$ + "*" +classic_basic code 80 NEXT I +classic_basic code 90 PRINT S$ +classic_basic blank +classic_basic comment 100 REM +classic_basic code 110 INPUT "Do you want more stars? "; A$ +classic_basic code 120 IF LEN(A$) = 0 THEN GOTO 110 +classic_basic code 130 A$ = LEFT$(A$, 1) +classic_basic code 140 IF (A$ = "Y") OR (A$ = "y") THEN GOTO 40 +classic_basic code 150 PRINT "Goodbye "; +classic_basic code 160 FOR I = 1 TO 200 +classic_basic code 170 PRINT U$; " "; +classic_basic code 180 NEXT I +classic_basic code 190 PRINT diff --git a/test/expected_dir/classic_basic.bas/classic_basic/blanks b/test/expected_dir/classic_basic.bas/classic_basic/blanks deleted file mode 100644 index 56a6051..0000000 --- a/test/expected_dir/classic_basic.bas/classic_basic/blanks +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/test/expected_dir/classic_basic.bas/classic_basic/code b/test/expected_dir/classic_basic.bas/classic_basic/code deleted file mode 100644 index 4ed7d0f..0000000 --- a/test/expected_dir/classic_basic.bas/classic_basic/code +++ /dev/null @@ -1,17 +0,0 @@ -10 INPUT "What is your name: "; U$ -20 PRINT "Hello "; U$ -40 INPUT "How many stars do you want: "; N -50 S$ = "" -60 FOR I = 1 TO N -70 S$ = S$ + "*" -80 NEXT I -90 PRINT S$ -110 INPUT "Do you want more stars? "; A$ -120 IF LEN(A$) = 0 THEN GOTO 110 -130 A$ = LEFT$(A$, 1) -140 IF (A$ = "Y") OR (A$ = "y") THEN GOTO 40 -150 PRINT "Goodbye "; -160 FOR I = 1 TO 200 -170 PRINT U$; " "; -180 NEXT I -190 PRINT diff --git a/test/expected_dir/classic_basic.bas/classic_basic/comment b/test/expected_dir/classic_basic.bas/classic_basic/comment deleted file mode 100644 index e642e19..0000000 --- a/test/expected_dir/classic_basic.bas/classic_basic/comment +++ /dev/null @@ -1,2 +0,0 @@ -30 REM Test -100 REM diff --git a/test/expected_dir/clearsilver_template1.cs/html/comment b/test/expected_dir/classic_basic1.classic_basic similarity index 100% rename from test/expected_dir/clearsilver_template1.cs/html/comment rename to test/expected_dir/classic_basic1.classic_basic diff --git a/test/expected_dir/classic_basic1.classic_basic/basic/code b/test/expected_dir/classic_basic1.classic_basic/basic/code deleted file mode 100644 index 4ed7d0f..0000000 --- a/test/expected_dir/classic_basic1.classic_basic/basic/code +++ /dev/null @@ -1,17 +0,0 @@ -10 INPUT "What is your name: "; U$ -20 PRINT "Hello "; U$ -40 INPUT "How many stars do you want: "; N -50 S$ = "" -60 FOR I = 1 TO N -70 S$ = S$ + "*" -80 NEXT I -90 PRINT S$ -110 INPUT "Do you want more stars? "; A$ -120 IF LEN(A$) = 0 THEN GOTO 110 -130 A$ = LEFT$(A$, 1) -140 IF (A$ = "Y") OR (A$ = "y") THEN GOTO 40 -150 PRINT "Goodbye "; -160 FOR I = 1 TO 200 -170 PRINT U$; " "; -180 NEXT I -190 PRINT diff --git a/test/expected_dir/classic_basic1.classic_basic/basic/comment b/test/expected_dir/classic_basic1.classic_basic/basic/comment deleted file mode 100644 index 9f42a86..0000000 --- a/test/expected_dir/classic_basic1.classic_basic/basic/comment +++ /dev/null @@ -1,2 +0,0 @@ -30 REM -100 REM diff --git a/test/expected_dir/clearsilver_template1.cs b/test/expected_dir/clearsilver_template1.cs new file mode 100644 index 0000000..7f82392 --- /dev/null +++ b/test/expected_dir/clearsilver_template1.cs @@ -0,0 +1,6 @@ +html code +html code +clearsilver comment

+clearsilver code

+html code +html code diff --git a/test/expected_dir/clearsilver_template1.cs/clearsilver/blanks b/test/expected_dir/clearsilver_template1.cs/clearsilver/blanks deleted file mode 100644 index c227083..0000000 --- a/test/expected_dir/clearsilver_template1.cs/clearsilver/blanks +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/test/expected_dir/clearsilver_template1.cs/clearsilver/code b/test/expected_dir/clearsilver_template1.cs/clearsilver/code deleted file mode 100644 index 369aaed..0000000 --- a/test/expected_dir/clearsilver_template1.cs/clearsilver/code +++ /dev/null @@ -1 +0,0 @@ -

diff --git a/test/expected_dir/clearsilver_template1.cs/clearsilver/comment b/test/expected_dir/clearsilver_template1.cs/clearsilver/comment deleted file mode 100644 index 387f33b..0000000 --- a/test/expected_dir/clearsilver_template1.cs/clearsilver/comment +++ /dev/null @@ -1 +0,0 @@ -

diff --git a/test/expected_dir/clearsilver_template1.cs/html/blanks b/test/expected_dir/clearsilver_template1.cs/html/blanks deleted file mode 100644 index c227083..0000000 --- a/test/expected_dir/clearsilver_template1.cs/html/blanks +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/test/expected_dir/clearsilver_template1.cs/html/code b/test/expected_dir/clearsilver_template1.cs/html/code deleted file mode 100644 index 7879e1c..0000000 --- a/test/expected_dir/clearsilver_template1.cs/html/code +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/test/expected_dir/css1.css/css/comment b/test/expected_dir/cobol1.cbl similarity index 100% rename from test/expected_dir/css1.css/css/comment rename to test/expected_dir/cobol1.cbl diff --git a/test/expected_dir/cobol1.cbl/cobol/blank b/test/expected_dir/cobol1.cbl/cobol/blank deleted file mode 100644 index d36ff3a..0000000 --- a/test/expected_dir/cobol1.cbl/cobol/blank +++ /dev/null @@ -1,4 +0,0 @@ -000100 -000180 -000187 -000210 diff --git a/test/expected_dir/cobol1.cbl/cobol/code b/test/expected_dir/cobol1.cbl/cobol/code deleted file mode 100644 index 7be8d98..0000000 --- a/test/expected_dir/cobol1.cbl/cobol/code +++ /dev/null @@ -1,13 +0,0 @@ -000010 IDENTIFICATION DIVISION. -000020 PROGRAM-ID. LINE-NO-PROG. -000030 AUTHOR. TIM R P BROWN. -000110 ENVIRONMENT DIVISION. -000120 INPUT-OUTPUT SECTION. -000130 FILE-CONTROL. -000140 SELECT IN-FILE ASSIGN TO 'INPUT.TXT' -000150 ORGANIZATION IS LINE SEQUENTIAL. -000160 SELECT OUT-FILE ASSIGN TO 'OUTPUT.COB' -000170 ORGANIZATION IS LINE SEQUENTIAL. -000190 DATA DIVISION. -000200 FILE SECTION. -000220 FD IN-FILE. diff --git a/test/expected_dir/cobol1.cbl/cobol/comment b/test/expected_dir/cobol1.cbl/cobol/comment deleted file mode 100644 index 24658c2..0000000 --- a/test/expected_dir/cobol1.cbl/cobol/comment +++ /dev/null @@ -1,7 +0,0 @@ -000040**************************************************** -000050* Program to add line numbers to typed code * -000060* Allows for comment asterisk, solidus, or hyphen ,* -000070* moving it into position 7. * -000080* * -000090**************************************************** -000185***************************************************** diff --git a/test/expected_dir/configure.ac b/test/expected_dir/configure.ac new file mode 100644 index 0000000..37df68d --- /dev/null +++ b/test/expected_dir/configure.ac @@ -0,0 +1,5 @@ +autoconf comment dnl This is an autoconf file. +autoconf blank +autoconf code AC_INIT([giant-space-monkey], [0.0]) +autoconf code AC_PREREQ(2.5) +autoconf blank diff --git a/test/expected_dir/configure.ac/autoconf/blanks b/test/expected_dir/configure.ac/autoconf/blanks deleted file mode 100644 index d8263ee..0000000 --- a/test/expected_dir/configure.ac/autoconf/blanks +++ /dev/null @@ -1 +0,0 @@ -2 \ No newline at end of file diff --git a/test/expected_dir/configure.ac/autoconf/code b/test/expected_dir/configure.ac/autoconf/code deleted file mode 100644 index 1f28c76..0000000 --- a/test/expected_dir/configure.ac/autoconf/code +++ /dev/null @@ -1,2 +0,0 @@ -AC_INIT([giant-space-monkey], [0.0]) -AC_PREREQ(2.5) diff --git a/test/expected_dir/configure.ac/autoconf/comment b/test/expected_dir/configure.ac/autoconf/comment deleted file mode 100644 index 14007b5..0000000 --- a/test/expected_dir/configure.ac/autoconf/comment +++ /dev/null @@ -1 +0,0 @@ -dnl This is an autoconf file. diff --git a/test/expected_dir/cs1.cs b/test/expected_dir/cs1.cs new file mode 100644 index 0000000..9071c79 --- /dev/null +++ b/test/expected_dir/cs1.cs @@ -0,0 +1,55 @@ +csharp comment // The Delegate declaration which defines the signature of methods which can be invoked +csharp code public delegate void ScoreChangeEventHandler (int newScore, ref bool cancel); +csharp blank +csharp comment // Class which makes the event +csharp code public class Game { +csharp comment // Note the use of the event keyword +csharp code public event ScoreChangeEventHandler ScoreChange; +csharp blank +csharp code int score; +csharp blank +csharp comment // Score Property +csharp code public int Score { +csharp code get { +csharp code return score; +csharp code } +csharp code set { +csharp code if (score != value) { +csharp code bool cancel = false; +csharp code ScoreChange (value, ref cancel); +csharp code if (! cancel) +csharp code score = value; +csharp code } +csharp code } +csharp code } +csharp code } +csharp blank +csharp comment // Class which handles the event +csharp code public class Referee +csharp code { +csharp code public Referee (Game game) { +csharp comment // Monitor when a score changes in the game +csharp code game.ScoreChange += new ScoreChangeEventHandler (game_ScoreChange); +csharp code } +csharp blank +csharp comment // Notice how this method signature matches the ScoreChangeEventHandler's signature +csharp code private void game_ScoreChange (int newScore, ref bool cancel) { +csharp code if (newScore < 100) +csharp code System.Console.WriteLine ("Good Score"); +csharp code else { +csharp code cancel = true; +csharp code System.Console.WriteLine ("No Score can be that high!"); +csharp code } +csharp code } +csharp code } +csharp blank +csharp comment // Class to test it all +csharp code public class GameTest +csharp code { +csharp code public static void Main () { +csharp code Game game = new Game (); +csharp code Referee referee = new Referee (game); +csharp code game.Score = 70; +csharp code game.Score = 110; +csharp code } +csharp code } diff --git a/test/expected_dir/cs1.cs/csharp/blanks b/test/expected_dir/cs1.cs/csharp/blanks deleted file mode 100644 index 62f9457..0000000 --- a/test/expected_dir/cs1.cs/csharp/blanks +++ /dev/null @@ -1 +0,0 @@ -6 \ No newline at end of file diff --git a/test/expected_dir/cs1.cs/csharp/code b/test/expected_dir/cs1.cs/csharp/code deleted file mode 100644 index e99a696..0000000 --- a/test/expected_dir/cs1.cs/csharp/code +++ /dev/null @@ -1,41 +0,0 @@ -public delegate void ScoreChangeEventHandler (int newScore, ref bool cancel); -public class Game { -public event ScoreChangeEventHandler ScoreChange; -int score; -public int Score { -get { -return score; -} -set { -if (score != value) { -bool cancel = false; -ScoreChange (value, ref cancel); -if (! cancel) -score = value; -} -} -} -} -public class Referee -{ -public Referee (Game game) { -game.ScoreChange += new ScoreChangeEventHandler (game_ScoreChange); -} -private void game_ScoreChange (int newScore, ref bool cancel) { -if (newScore < 100) -System.Console.WriteLine ("Good Score"); -else { -cancel = true; -System.Console.WriteLine ("No Score can be that high!"); -} -} -} -public class GameTest -{ -public static void Main () { -Game game = new Game (); -Referee referee = new Referee (game); -game.Score = 70; -game.Score = 110; -} -} diff --git a/test/expected_dir/cs1.cs/csharp/comment b/test/expected_dir/cs1.cs/csharp/comment deleted file mode 100644 index b0c67fb..0000000 --- a/test/expected_dir/cs1.cs/csharp/comment +++ /dev/null @@ -1,8 +0,0 @@ -// The Delegate declaration which defines the signature of methods which can be invoked -// Class which makes the event -// Note the use of the event keyword -// Score Property -// Class which handles the event -// Monitor when a score changes in the game -// Notice how this method signature matches the ScoreChangeEventHandler's signature -// Class to test it all diff --git a/test/expected_dir/css1.css b/test/expected_dir/css1.css new file mode 100644 index 0000000..e428549 --- /dev/null +++ b/test/expected_dir/css1.css @@ -0,0 +1,3 @@ +css code .foo { +css code padding: 10px; +css code } diff --git a/test/expected_dir/css1.css/css/blanks b/test/expected_dir/css1.css/css/blanks deleted file mode 100644 index c227083..0000000 --- a/test/expected_dir/css1.css/css/blanks +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/test/expected_dir/css1.css/css/code b/test/expected_dir/css1.css/css/code deleted file mode 100644 index 433f13a..0000000 --- a/test/expected_dir/css1.css/css/code +++ /dev/null @@ -1,3 +0,0 @@ -.foo { -padding: 10px; -} diff --git a/test/expected_dir/d1.d b/test/expected_dir/d1.d new file mode 100644 index 0000000..982efc4 --- /dev/null +++ b/test/expected_dir/d1.d @@ -0,0 +1,26 @@ +dmd comment /* comment block */ +dmd comment // single-line comment +dmd code int main(char[][] args) +dmd code { +dmd code int w_total; // a comment and code on the same line +dmd blank +dmd comment /+ begin a nestable comment block +dmd comment /* this comment is nested within another */ +dmd comment this_code_is_commented_out(); +dmd comment +/ +dmd blank +dmd comment /* when inside a c-style block comment, /+ does not start a nested comment */ +dmd code this_line_is_code(); +dmd blank +dmd comment // when inside a line comment, /+ does not start a nested comment +dmd code this_line_is_also_code(); +dmd blank +dmd comment /+ when inside a nestable comment, /+ does begin a nested comment +dmd comment now we close the inner comment +/ +dmd comment This line is still part of the outer comment +dmd comment now we close the outer comment +/ +dmd blank +dmd code x = `when inside a backtick string, /+ does not begin a nested comment`; +dmd code y = `when inside a backtick string, /* does not begin a nested comment`; +dmd code z = `when inside a backtick string, // does not begin a nested comment`; +dmd code } diff --git a/test/expected_dir/d1.d/dmd/blanks b/test/expected_dir/d1.d/dmd/blanks deleted file mode 100644 index 7813681..0000000 --- a/test/expected_dir/d1.d/dmd/blanks +++ /dev/null @@ -1 +0,0 @@ -5 \ No newline at end of file diff --git a/test/expected_dir/d1.d/dmd/code b/test/expected_dir/d1.d/dmd/code deleted file mode 100644 index 160cd23..0000000 --- a/test/expected_dir/d1.d/dmd/code +++ /dev/null @@ -1,9 +0,0 @@ -int main(char[][] args) -{ -int w_total; // a comment and code on the same line -this_line_is_code(); -this_line_is_also_code(); -x = `when inside a backtick string, /+ does not begin a nested comment`; -y = `when inside a backtick string, /* does not begin a nested comment`; -z = `when inside a backtick string, // does not begin a nested comment`; -} diff --git a/test/expected_dir/d1.d/dmd/comment b/test/expected_dir/d1.d/dmd/comment deleted file mode 100644 index f5c5aad..0000000 --- a/test/expected_dir/d1.d/dmd/comment +++ /dev/null @@ -1,12 +0,0 @@ -/* comment block */ -// single-line comment -/+ begin a nestable comment block -/* this comment is nested within another */ -this_code_is_commented_out(); -+/ -/* when inside a c-style block comment, /+ does not start a nested comment */ -// when inside a line comment, /+ does not start a nested comment -/+ when inside a nestable comment, /+ does begin a nested comment -now we close the inner comment +/ -This line is still part of the outer comment -now we close the outer comment +/ diff --git a/test/expected_dir/dcl.com b/test/expected_dir/dcl.com new file mode 100644 index 0000000..7f5cf6a --- /dev/null +++ b/test/expected_dir/dcl.com @@ -0,0 +1,12 @@ +dcl comment $! Test file for DCL parser +dcl comment $ ! Written by Camiel Vanderhoeven +dcl blank +dcl blank +dcl code $ SET VERIFY +dcl code $ WRITE SYS$SYSTEM +dcl code This is some text +dcl blank +dcl code $ EXIT +dcl comment $! This is comment again +dcl comment $! +dcl blank diff --git a/test/expected_dir/dcl.com/dcl/blanks b/test/expected_dir/dcl.com/dcl/blanks deleted file mode 100644 index bf0d87a..0000000 --- a/test/expected_dir/dcl.com/dcl/blanks +++ /dev/null @@ -1 +0,0 @@ -4 \ No newline at end of file diff --git a/test/expected_dir/dcl.com/dcl/code b/test/expected_dir/dcl.com/dcl/code deleted file mode 100644 index e7fbdec..0000000 --- a/test/expected_dir/dcl.com/dcl/code +++ /dev/null @@ -1,4 +0,0 @@ -$ SET VERIFY -$ WRITE SYS$SYSTEM -This is some text -$ EXIT diff --git a/test/expected_dir/dcl.com/dcl/comment b/test/expected_dir/dcl.com/dcl/comment deleted file mode 100644 index 0fa7ca6..0000000 --- a/test/expected_dir/dcl.com/dcl/comment +++ /dev/null @@ -1,4 +0,0 @@ -$! Test file for DCL parser -$ ! Written by Camiel Vanderhoeven -$! This is comment again -$! diff --git a/test/expected_dir/diff1_new.html b/test/expected_dir/diff1_new.html new file mode 100644 index 0000000..207af65 --- /dev/null +++ b/test/expected_dir/diff1_new.html @@ -0,0 +1,11 @@ +html code +html code +html code +html code +html code +html code new +html code diff --git a/test/expected_dir/diff1_old.html b/test/expected_dir/diff1_old.html new file mode 100644 index 0000000..8e6d912 --- /dev/null +++ b/test/expected_dir/diff1_old.html @@ -0,0 +1,11 @@ +html code +html code +html code +html code +html code +html code old +html code diff --git a/test/expected_dir/diff2_new.c b/test/expected_dir/diff2_new.c new file mode 100644 index 0000000..7ba80e9 --- /dev/null +++ b/test/expected_dir/diff2_new.c @@ -0,0 +1,7 @@ +c comment /* new */ +c code #include 'foo.c' +c comment /* common */ +c code int do_stuff(old_code) { +c code int common; +c code int new_var; +c code } diff --git a/test/expected_dir/diff2_old.c b/test/expected_dir/diff2_old.c new file mode 100644 index 0000000..906e6f0 --- /dev/null +++ b/test/expected_dir/diff2_old.c @@ -0,0 +1,7 @@ +c comment /* old */ +c code #include 'foo.c' +c comment /* common */ +c code int do_stuff(old_code) { +c code int common; +c code int old_var; +c code } diff --git a/test/expected_dir/diff3_new.xml b/test/expected_dir/diff3_new.xml new file mode 100644 index 0000000..b01c982 --- /dev/null +++ b/test/expected_dir/diff3_new.xml @@ -0,0 +1,3 @@ +xml code +xml code new +xml code diff --git a/test/expected_dir/diff3_old.xml b/test/expected_dir/diff3_old.xml new file mode 100644 index 0000000..145f963 --- /dev/null +++ b/test/expected_dir/diff3_old.xml @@ -0,0 +1,3 @@ +xml code +xml code old +xml code diff --git a/test/expected_dir/dylan1.dylan b/test/expected_dir/dylan1.dylan new file mode 100644 index 0000000..4fcf478 --- /dev/null +++ b/test/expected_dir/dylan1.dylan @@ -0,0 +1,17 @@ +dylan comment // random program i found +dylan code define function describe-list(my-list :: , #key verbose?) => () +dylan code format(*standard-output*, "{a , size: %d", my-list.size); +dylan code if (verbose?) +dylan code format(*standard-output*, ", elements:"); +dylan code for (item in my-list) +dylan code format(*standard-output*, " %=", item); +dylan code end for; +dylan code end if; +dylan code format(*standard-output*, "}"); +dylan code end function; +dylan blank +dylan code describe-list(#(1, 2, 3, 4, 5, 6)); +dylan comment // prints "{a , size: 6}" +dylan blank +dylan code describe-list(#(5, 7, 3), verbose?: #t); +dylan comment // prints "{a , size: 3, elements: 5 7 3}" diff --git a/test/expected_dir/dylan1.dylan/dylan/blanks b/test/expected_dir/dylan1.dylan/dylan/blanks deleted file mode 100644 index d8263ee..0000000 --- a/test/expected_dir/dylan1.dylan/dylan/blanks +++ /dev/null @@ -1 +0,0 @@ -2 \ No newline at end of file diff --git a/test/expected_dir/dylan1.dylan/dylan/code b/test/expected_dir/dylan1.dylan/dylan/code deleted file mode 100644 index cbeac86..0000000 --- a/test/expected_dir/dylan1.dylan/dylan/code +++ /dev/null @@ -1,12 +0,0 @@ -define function describe-list(my-list :: , #key verbose?) => () -format(*standard-output*, "{a , size: %d", my-list.size); -if (verbose?) -format(*standard-output*, ", elements:"); -for (item in my-list) -format(*standard-output*, " %=", item); -end for; -end if; -format(*standard-output*, "}"); -end function; -describe-list(#(1, 2, 3, 4, 5, 6)); -describe-list(#(5, 7, 3), verbose?: #t); diff --git a/test/expected_dir/dylan1.dylan/dylan/comment b/test/expected_dir/dylan1.dylan/dylan/comment deleted file mode 100644 index 6687ac5..0000000 --- a/test/expected_dir/dylan1.dylan/dylan/comment +++ /dev/null @@ -1,3 +0,0 @@ -// random program i found -// prints "{a , size: 6}" -// prints "{a , size: 3, elements: 5 7 3}" diff --git a/test/expected_dir/eiffel.e b/test/expected_dir/eiffel.e new file mode 100644 index 0000000..e90c775 --- /dev/null +++ b/test/expected_dir/eiffel.e @@ -0,0 +1,13 @@ +eiffel code class +eiffel code HELLO_WORLD +eiffel code create +eiffel code make +eiffel code feature +eiffel code make +eiffel code do +eiffel comment -- prints "Hello world!" and starts new line +eiffel blank +eiffel code print ("Hello, world!%N") +eiffel blank +eiffel code end +eiffel code end diff --git a/test/expected_dir/eiffel.e/eiffel/blanks b/test/expected_dir/eiffel.e/eiffel/blanks deleted file mode 100644 index d8263ee..0000000 --- a/test/expected_dir/eiffel.e/eiffel/blanks +++ /dev/null @@ -1 +0,0 @@ -2 \ No newline at end of file diff --git a/test/expected_dir/eiffel.e/eiffel/code b/test/expected_dir/eiffel.e/eiffel/code deleted file mode 100644 index 5c4b96c..0000000 --- a/test/expected_dir/eiffel.e/eiffel/code +++ /dev/null @@ -1,10 +0,0 @@ -class -HELLO_WORLD -create -make -feature -make -do -print ("Hello, world!%N") -end -end diff --git a/test/expected_dir/eiffel.e/eiffel/comment b/test/expected_dir/eiffel.e/eiffel/comment deleted file mode 100644 index 734b783..0000000 --- a/test/expected_dir/eiffel.e/eiffel/comment +++ /dev/null @@ -1 +0,0 @@ --- prints "Hello world!" and starts new line diff --git a/test/expected_dir/el1.el b/test/expected_dir/el1.el new file mode 100644 index 0000000..ba7de4c --- /dev/null +++ b/test/expected_dir/el1.el @@ -0,0 +1,22 @@ +emacslisp code (if (string-equal "21" (substring (emacs-version) 10 12)) +emacslisp code (progn +emacslisp code (blink-cursor-mode 0) +emacslisp comment ;; Insert newline when you press `C-n' (next-line) +emacslisp comment ;; at the end of the buffer +emacslisp blank +emacslisp code (setq next-line-add-newlines t) +emacslisp comment ;; Turn on image viewing +emacslisp code (auto-image-file-mode t) +emacslisp comment ;; Turn on menu bar (this bar has text) +emacslisp comment ;; (Use numeric argument to turn on) +emacslisp code (menu-bar-mode 1) +emacslisp comment ;; Turn off tool bar (this bar has icons) +emacslisp comment ;; (Use numeric argument to turn on) +emacslisp code (tool-bar-mode nil) +emacslisp comment ;; Turn off tooltip mode for tool bar +emacslisp comment ;; (This mode causes icon explanations to pop up) +emacslisp comment ;; (Use numeric argument to turn on) +emacslisp code (tooltip-mode nil) +emacslisp comment ;; If tooltips turned on, make tips appear promptly +emacslisp code (setq tooltip-delay 0.1) ; default is one second +emacslisp code )) diff --git a/test/expected_dir/el1.el/emacslisp/blanks b/test/expected_dir/el1.el/emacslisp/blanks deleted file mode 100644 index 56a6051..0000000 --- a/test/expected_dir/el1.el/emacslisp/blanks +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/test/expected_dir/el1.el/emacslisp/code b/test/expected_dir/el1.el/emacslisp/code deleted file mode 100644 index 967f65b..0000000 --- a/test/expected_dir/el1.el/emacslisp/code +++ /dev/null @@ -1,10 +0,0 @@ -(if (string-equal "21" (substring (emacs-version) 10 12)) -(progn -(blink-cursor-mode 0) -(setq next-line-add-newlines t) -(auto-image-file-mode t) -(menu-bar-mode 1) -(tool-bar-mode nil) -(tooltip-mode nil) -(setq tooltip-delay 0.1) ; default is one second -)) diff --git a/test/expected_dir/el1.el/emacslisp/comment b/test/expected_dir/el1.el/emacslisp/comment deleted file mode 100644 index 59bffd7..0000000 --- a/test/expected_dir/el1.el/emacslisp/comment +++ /dev/null @@ -1,11 +0,0 @@ -;; Insert newline when you press `C-n' (next-line) -;; at the end of the buffer -;; Turn on image viewing -;; Turn on menu bar (this bar has text) -;; (Use numeric argument to turn on) -;; Turn off tool bar (this bar has icons) -;; (Use numeric argument to turn on) -;; Turn off tooltip mode for tool bar -;; (This mode causes icon explanations to pop up) -;; (Use numeric argument to turn on) -;; If tooltips turned on, make tips appear promptly diff --git a/test/expected_dir/erl1.erl b/test/expected_dir/erl1.erl new file mode 100644 index 0000000..43da9d3 --- /dev/null +++ b/test/expected_dir/erl1.erl @@ -0,0 +1,189 @@ +erlang comment %%%---------------------------------------------------------------------- +erlang comment %%% File : erl1.erl +erlang comment %%% Author : Jason Allen - kinda - just repurposing random code +erlang comment %%% Purpose : Test out the erlang parsing +erlang comment %%% Created : 1/17/2007 by Jason Allen +erlang comment %%% Id : $Id: erl1.erl 1 2007-17-01 jason $ +erlang comment %%%---------------------------------------------------------------------- +erlang blank +erlang code -module(erl1). +erlang code -author('jason@ohloh.net'). +erlang code -vsn('$Revision: 1 $ '). +erlang blank +erlang comment %% External exports +erlang code -export([import_file/1, +erlang code import_dir/1]). +erlang blank +erlang code -include("random.hrl"). +erlang code -include("more_random.hrl"). +erlang blank +erlang comment %%%---------------------------------------------------------------------- +erlang comment %%% API +erlang comment %%%---------------------------------------------------------------------- +erlang blank +erlang code import_file(File) -> +erlang code User = filename:rootname(filename:basename(File)), +erlang code Server = filename:basename(filename:dirname(File)), +erlang code case (jlib:nodeprep(User) /= error) andalso +erlang code (jlib:nameprep(Server) /= error) of +erlang code true -> +erlang code case file:read_file(File) of +erlang code {ok, Text} -> +erlang code case xml_stream:parse_element(Text) of +erlang code El when element(1, El) == xmlelement -> +erlang code case catch process_xdb(User, Server, El) of +erlang code {'EXIT', Reason} -> +erlang code ?ERROR_MSG( +erlang code "Error while processing file \"~s\": ~p~n", +erlang code [File, Reason]), +erlang code {error, Reason}; +erlang code _ -> +erlang code ok +erlang code end; +erlang code {error, Reason} -> +erlang code ?ERROR_MSG("Can't parse file \"~s\": ~p~n", +erlang code [File, Reason]), +erlang code {error, Reason} +erlang code end; +erlang code {error, Reason} -> +erlang code ?ERROR_MSG("Can't read file \"~s\": ~p~n", [File, Reason]), +erlang code {error, Reason} +erlang code end; +erlang code false -> +erlang code ?ERROR_MSG("Illegal user/server name in file \"~s\"~n", [File]), +erlang code {error, "illegal user/server"} +erlang code end. +erlang blank +erlang blank +erlang code import_dir(Dir) -> +erlang code {ok, Files} = file:list_dir(Dir), +erlang code MsgFiles = lists:filter( +erlang code fun(FN) -> +erlang code case string:len(FN) > 4 of +erlang code true -> +erlang code string:substr(FN, +erlang code string:len(FN) - 3) == ".xml"; +erlang code _ -> +erlang code false +erlang code end +erlang code end, Files), +erlang code lists:foldl( +erlang code fun(FN, A) -> +erlang code Res = import_file(filename:join([Dir, FN])), +erlang code case {A, Res} of +erlang code {ok, ok} -> ok; +erlang code {ok, _} -> {error, "see aoabberd log for details"}; +erlang code _ -> A +erlang code end +erlang code end, ok, MsgFiles). +erlang blank +erlang comment %%%---------------------------------------------------------------------- +erlang comment %%% Internal functions +erlang comment %%%---------------------------------------------------------------------- +erlang blank +erlang code process_xdb(User, Server, {xmlelement, Name, _Attrs, Els}) -> +erlang code case Name of +erlang code "xdb" -> +erlang code lists:foreach( +erlang code fun(El) -> +erlang code xdb_data(User, Server, El) +erlang code end, Els); +erlang code _ -> +erlang code ok +erlang code end. +erlang blank +erlang blank +erlang code xdb_data(User, Server, {xmlcdata, _CData}) -> +erlang code ok; +erlang code xdb_data(User, Server, {xmlelement, _Name, Attrs, _Els} = El) -> +erlang code From = jlib:make_jid(User, Server, ""), +erlang code LServer = jlib:nameprep(Server), +erlang code case xml:get_attr_s("xmlns", Attrs) of +erlang code ?NS_AUTH -> +erlang code Password = xml:get_tag_cdata(El), +erlang code ejabberd_auth:set_password(User, Server, Password), +erlang code ok; +erlang code ?NS_ROSTER -> +erlang code case lists:member(mod_roster_odbc, +erlang code gen_mod:loaded_modules(LServer)) of +erlang code true -> +erlang code catch mod_roster_odbc:set_items(User, Server, El); +erlang code false -> +erlang code catch mod_roster:set_items(User, Server, El) +erlang code end, +erlang code ok; +erlang code ?NS_LAST -> +erlang code TimeStamp = xml:get_attr_s("last", Attrs), +erlang code Status = xml:get_tag_cdata(El), +erlang code case lists:member(mod_last_odbc, +erlang code gen_mod:loaded_modules(LServer)) of +erlang code true -> +erlang code catch mod_last_odbc:store_last_info( +erlang code User, +erlang code Server, +erlang code list_to_integer(TimeStamp), +erlang code Status); +erlang code false -> +erlang code catch mod_last:store_last_info( +erlang code User, +erlang code Server, +erlang code list_to_integer(TimeStamp), +erlang code Status) +erlang code end, +erlang code ok; +erlang code ?NS_VCARD -> +erlang code case lists:member(mod_vcard_odbc, +erlang code gen_mod:loaded_modules(LServer)) of +erlang code true -> +erlang code catch mod_vcard_odbc:process_sm_iq( +erlang code From, +erlang code jlib:make_jid("", Server, ""), +erlang code #iq{type = set, xmlns = ?NS_VCARD, sub_el = El}); +erlang code false -> +erlang code catch mod_vcard:process_sm_iq( +erlang code From, +erlang code jlib:make_jid("", Server, ""), +erlang code #iq{type = set, xmlns = ?NS_VCARD, sub_el = El}) +erlang code end, +erlang code ok; +erlang code "jabber:x:offline" -> +erlang code process_offline(Server, From, El), +erlang code ok; +erlang code XMLNS -> +erlang code case xml:get_attr_s("j_private_flag", Attrs) of +erlang code "1" -> +erlang code catch mod_private:process_sm_iq( +erlang code From, +erlang code jlib:make_jid("", Server, ""), +erlang code #iq{type = set, xmlns = ?NS_PRIVATE, +erlang code sub_el = {xmlelement, "query", [], +erlang code [jlib:remove_attr( +erlang code "j_private_flag", +erlang code jlib:remove_attr("xdbns", El))]}}); +erlang code _ -> +erlang code ?DEBUG("jd2ejd: Unknown namespace \"~s\"~n", [XMLNS]) +erlang code end, +erlang code ok +erlang code end. +erlang blank +erlang blank +erlang code process_offline(Server, To, {xmlelement, _, _, Els}) -> +erlang code LServer = jlib:nameprep(Server), +erlang code lists:foreach(fun({xmlelement, _, Attrs, _} = El) -> +erlang code FromS = xml:get_attr_s("from", Attrs), +erlang code From = case FromS of +erlang code "" -> +erlang code jlib:make_jid("", Server, ""); +erlang code _ -> +erlang code jlib:string_to_jid(FromS) +erlang code end, +erlang code case From of +erlang code error -> +erlang code ok; +erlang code _ -> +erlang code ejabberd_hooks:run(offline_message_hook, +erlang code LServer, +erlang code [From, To, El]) +erlang code end +erlang code end, Els). +erlang blank diff --git a/test/expected_dir/erl1.erl/erlang/blanks b/test/expected_dir/erl1.erl/erlang/blanks deleted file mode 100644 index da2d398..0000000 --- a/test/expected_dir/erl1.erl/erlang/blanks +++ /dev/null @@ -1 +0,0 @@ -14 \ No newline at end of file diff --git a/test/expected_dir/erl1.erl/erlang/code b/test/expected_dir/erl1.erl/erlang/code deleted file mode 100644 index 3057191..0000000 --- a/test/expected_dir/erl1.erl/erlang/code +++ /dev/null @@ -1,161 +0,0 @@ --module(erl1). --author('jason@ohloh.net'). --vsn('$Revision: 1 $ '). --export([import_file/1, -import_dir/1]). --include("random.hrl"). --include("more_random.hrl"). -import_file(File) -> -User = filename:rootname(filename:basename(File)), -Server = filename:basename(filename:dirname(File)), -case (jlib:nodeprep(User) /= error) andalso -(jlib:nameprep(Server) /= error) of -true -> -case file:read_file(File) of -{ok, Text} -> -case xml_stream:parse_element(Text) of -El when element(1, El) == xmlelement -> -case catch process_xdb(User, Server, El) of -{'EXIT', Reason} -> -?ERROR_MSG( -"Error while processing file \"~s\": ~p~n", -[File, Reason]), -{error, Reason}; -_ -> -ok -end; -{error, Reason} -> -?ERROR_MSG("Can't parse file \"~s\": ~p~n", -[File, Reason]), -{error, Reason} -end; -{error, Reason} -> -?ERROR_MSG("Can't read file \"~s\": ~p~n", [File, Reason]), -{error, Reason} -end; -false -> -?ERROR_MSG("Illegal user/server name in file \"~s\"~n", [File]), -{error, "illegal user/server"} -end. -import_dir(Dir) -> -{ok, Files} = file:list_dir(Dir), -MsgFiles = lists:filter( -fun(FN) -> -case string:len(FN) > 4 of -true -> -string:substr(FN, -string:len(FN) - 3) == ".xml"; -_ -> -false -end -end, Files), -lists:foldl( -fun(FN, A) -> -Res = import_file(filename:join([Dir, FN])), -case {A, Res} of -{ok, ok} -> ok; -{ok, _} -> {error, "see aoabberd log for details"}; -_ -> A -end -end, ok, MsgFiles). -process_xdb(User, Server, {xmlelement, Name, _Attrs, Els}) -> -case Name of -"xdb" -> -lists:foreach( -fun(El) -> -xdb_data(User, Server, El) -end, Els); -_ -> -ok -end. -xdb_data(User, Server, {xmlcdata, _CData}) -> -ok; -xdb_data(User, Server, {xmlelement, _Name, Attrs, _Els} = El) -> -From = jlib:make_jid(User, Server, ""), -LServer = jlib:nameprep(Server), -case xml:get_attr_s("xmlns", Attrs) of -?NS_AUTH -> -Password = xml:get_tag_cdata(El), -ejabberd_auth:set_password(User, Server, Password), -ok; -?NS_ROSTER -> -case lists:member(mod_roster_odbc, -gen_mod:loaded_modules(LServer)) of -true -> -catch mod_roster_odbc:set_items(User, Server, El); -false -> -catch mod_roster:set_items(User, Server, El) -end, -ok; -?NS_LAST -> -TimeStamp = xml:get_attr_s("last", Attrs), -Status = xml:get_tag_cdata(El), -case lists:member(mod_last_odbc, -gen_mod:loaded_modules(LServer)) of -true -> -catch mod_last_odbc:store_last_info( -User, -Server, -list_to_integer(TimeStamp), -Status); -false -> -catch mod_last:store_last_info( -User, -Server, -list_to_integer(TimeStamp), -Status) -end, -ok; -?NS_VCARD -> -case lists:member(mod_vcard_odbc, -gen_mod:loaded_modules(LServer)) of -true -> -catch mod_vcard_odbc:process_sm_iq( -From, -jlib:make_jid("", Server, ""), -#iq{type = set, xmlns = ?NS_VCARD, sub_el = El}); -false -> -catch mod_vcard:process_sm_iq( -From, -jlib:make_jid("", Server, ""), -#iq{type = set, xmlns = ?NS_VCARD, sub_el = El}) -end, -ok; -"jabber:x:offline" -> -process_offline(Server, From, El), -ok; -XMLNS -> -case xml:get_attr_s("j_private_flag", Attrs) of -"1" -> -catch mod_private:process_sm_iq( -From, -jlib:make_jid("", Server, ""), -#iq{type = set, xmlns = ?NS_PRIVATE, -sub_el = {xmlelement, "query", [], -[jlib:remove_attr( -"j_private_flag", -jlib:remove_attr("xdbns", El))]}}); -_ -> -?DEBUG("jd2ejd: Unknown namespace \"~s\"~n", [XMLNS]) -end, -ok -end. -process_offline(Server, To, {xmlelement, _, _, Els}) -> -LServer = jlib:nameprep(Server), -lists:foreach(fun({xmlelement, _, Attrs, _} = El) -> -FromS = xml:get_attr_s("from", Attrs), -From = case FromS of -"" -> -jlib:make_jid("", Server, ""); -_ -> -jlib:string_to_jid(FromS) -end, -case From of -error -> -ok; -_ -> -ejabberd_hooks:run(offline_message_hook, -LServer, -[From, To, El]) -end -end, Els). diff --git a/test/expected_dir/erl1.erl/erlang/comment b/test/expected_dir/erl1.erl/erlang/comment deleted file mode 100644 index 5a8848b..0000000 --- a/test/expected_dir/erl1.erl/erlang/comment +++ /dev/null @@ -1,14 +0,0 @@ -%%%---------------------------------------------------------------------- -%%% File : erl1.erl -%%% Author : Jason Allen - kinda - just repurposing random code -%%% Purpose : Test out the erlang parsing -%%% Created : 1/17/2007 by Jason Allen -%%% Id : $Id: erl1.erl 1 2007-17-01 jason $ -%%%---------------------------------------------------------------------- -%% External exports -%%%---------------------------------------------------------------------- -%%% API -%%%---------------------------------------------------------------------- -%%%---------------------------------------------------------------------- -%%% Internal functions -%%%---------------------------------------------------------------------- diff --git a/test/expected_dir/example.xsl b/test/expected_dir/example.xsl new file mode 100644 index 0000000..be18ba2 --- /dev/null +++ b/test/expected_dir/example.xsl @@ -0,0 +1,17 @@ +xslt code +xslt code +xslt blank +xslt comment +xslt code +xslt code +xslt code +xslt code sample webpage +xslt code +xslt code +xslt code +xslt comment +xslt code comment in HTML +xslt code +xslt code +xslt code +xslt code diff --git a/test/expected_dir/example.xsl/xslt/blanks b/test/expected_dir/example.xsl/xslt/blanks deleted file mode 100644 index 56a6051..0000000 --- a/test/expected_dir/example.xsl/xslt/blanks +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/test/expected_dir/example.xsl/xslt/code b/test/expected_dir/example.xsl/xslt/code deleted file mode 100644 index 21b2504..0000000 --- a/test/expected_dir/example.xsl/xslt/code +++ /dev/null @@ -1,14 +0,0 @@ - - - - - -sample webpage - - - - comment in HTML - - - - diff --git a/test/expected_dir/example.xsl/xslt/comment b/test/expected_dir/example.xsl/xslt/comment deleted file mode 100644 index a82f20c..0000000 --- a/test/expected_dir/example.xsl/xslt/comment +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/test/expected_dir/factor1.factor b/test/expected_dir/factor1.factor new file mode 100644 index 0000000..a6c1180 --- /dev/null +++ b/test/expected_dir/factor1.factor @@ -0,0 +1,14 @@ +factor comment ! This is a comment +factor comment ! Factor syntax is very simple, it just contains words separated by spaces +factor comment ! '!' is a line comment word +factor comment ! "whatever" is a string word +factor code USING: kernel io ; ! This is a vocabulary inclusion word +factor code IN: testing +factor blank +factor code : test-string ( -- ) +factor code "this is a string" print ; +factor blank +factor code : test ( x -- y ) ! Parenthesis define a stack effect declaration +factor code dup swap drop ; +factor blank +factor code MAIN: test diff --git a/test/expected_dir/factor1.factor/factor/blanks b/test/expected_dir/factor1.factor/factor/blanks deleted file mode 100644 index e440e5c..0000000 --- a/test/expected_dir/factor1.factor/factor/blanks +++ /dev/null @@ -1 +0,0 @@ -3 \ No newline at end of file diff --git a/test/expected_dir/factor1.factor/factor/code b/test/expected_dir/factor1.factor/factor/code deleted file mode 100644 index d0b7ee4..0000000 --- a/test/expected_dir/factor1.factor/factor/code +++ /dev/null @@ -1,7 +0,0 @@ -USING: kernel io ; ! This is a vocabulary inclusion word -IN: testing -: test-string ( -- ) -"this is a string" print ; -: test ( x -- y ) ! Parenthesis define a stack effect declaration -dup swap drop ; -MAIN: test diff --git a/test/expected_dir/factor1.factor/factor/comment b/test/expected_dir/factor1.factor/factor/comment deleted file mode 100644 index e23ee5f..0000000 --- a/test/expected_dir/factor1.factor/factor/comment +++ /dev/null @@ -1,4 +0,0 @@ -! This is a comment -! Factor syntax is very simple, it just contains words separated by spaces -! '!' is a line comment word -! "whatever" is a string word diff --git a/test/expected_dir/foo.ebuild b/test/expected_dir/foo.ebuild new file mode 100644 index 0000000..dbb6cca --- /dev/null +++ b/test/expected_dir/foo.ebuild @@ -0,0 +1,21 @@ +ebuild comment # This is an ebuild. +ebuild comment # Distributed under the terms of the GNU General Public License v2 +ebuild comment # $Header: $ +ebuild blank +ebuild code DESCRIPTION="An ebuild" +ebuild code HOMEPAGE="" +ebuild code SRC_URI="" +ebuild blank +ebuild code LICENSE="" +ebuild code SLOT="0" +ebuild code KEYWORDS="~x86" +ebuild code IUSE="" +ebuild blank +ebuild code DEPEND="" +ebuild code RDEPEND="" +ebuild blank +ebuild code pkg_setup() { +ebuild comment # This is foo +ebuild code einfo "This is foo" +ebuild code } +ebuild blank diff --git a/test/expected_dir/foo.ebuild/ebuild/blanks b/test/expected_dir/foo.ebuild/ebuild/blanks deleted file mode 100644 index 7813681..0000000 --- a/test/expected_dir/foo.ebuild/ebuild/blanks +++ /dev/null @@ -1 +0,0 @@ -5 \ No newline at end of file diff --git a/test/expected_dir/foo.ebuild/ebuild/code b/test/expected_dir/foo.ebuild/ebuild/code deleted file mode 100644 index 6f0809e..0000000 --- a/test/expected_dir/foo.ebuild/ebuild/code +++ /dev/null @@ -1,12 +0,0 @@ -DESCRIPTION="An ebuild" -HOMEPAGE="" -SRC_URI="" -LICENSE="" -SLOT="0" -KEYWORDS="~x86" -IUSE="" -DEPEND="" -RDEPEND="" -pkg_setup() { -einfo "This is foo" -} diff --git a/test/expected_dir/foo.ebuild/ebuild/comment b/test/expected_dir/foo.ebuild/ebuild/comment deleted file mode 100644 index a096ab8..0000000 --- a/test/expected_dir/foo.ebuild/ebuild/comment +++ /dev/null @@ -1,4 +0,0 @@ -# This is an ebuild. -# Distributed under the terms of the GNU General Public License v2 -# $Header: $ -# This is foo diff --git a/test/expected_dir/foo.exheres-0 b/test/expected_dir/foo.exheres-0 new file mode 100644 index 0000000..ff3e5a7 --- /dev/null +++ b/test/expected_dir/foo.exheres-0 @@ -0,0 +1,20 @@ +exheres comment # This is an exheres. +exheres blank +exheres code require subversion bash-completion eutils flag-o-matic +exheres blank +exheres code DESCRIPTION="An exheres" +exheres code HOMEPAGE="http://example.org/" +exheres code SRC_URI="" +exheres blank +exheres code MYOPTIONS="monkey" +exheres code LICENSE="GPL-2" +exheres code SLOT="0" +exheres code PLATFORMS="~amd64 ~ia64 ~x86" +exheres blank +exheres code DEPENDENCIES="" +exheres blank +exheres code src_prepare() { +exheres code default +exheres code ./autogen.bash || die "autogen.bash failed" +exheres code } +exheres blank diff --git a/test/expected_dir/foo.exheres-0/exheres/blanks b/test/expected_dir/foo.exheres-0/exheres/blanks deleted file mode 100644 index 62f9457..0000000 --- a/test/expected_dir/foo.exheres-0/exheres/blanks +++ /dev/null @@ -1 +0,0 @@ -6 \ No newline at end of file diff --git a/test/expected_dir/foo.exheres-0/exheres/code b/test/expected_dir/foo.exheres-0/exheres/code deleted file mode 100644 index 622f684..0000000 --- a/test/expected_dir/foo.exheres-0/exheres/code +++ /dev/null @@ -1,13 +0,0 @@ -require subversion bash-completion eutils flag-o-matic -DESCRIPTION="An exheres" -HOMEPAGE="http://example.org/" -SRC_URI="" -MYOPTIONS="monkey" -LICENSE="GPL-2" -SLOT="0" -PLATFORMS="~amd64 ~ia64 ~x86" -DEPENDENCIES="" -src_prepare() { -default -./autogen.bash || die "autogen.bash failed" -} diff --git a/test/expected_dir/foo.exheres-0/exheres/comment b/test/expected_dir/foo.exheres-0/exheres/comment deleted file mode 100644 index dbb04ce..0000000 --- a/test/expected_dir/foo.exheres-0/exheres/comment +++ /dev/null @@ -1 +0,0 @@ -# This is an exheres. diff --git a/test/expected_dir/foo.tex b/test/expected_dir/foo.tex new file mode 100644 index 0000000..2115445 --- /dev/null +++ b/test/expected_dir/foo.tex @@ -0,0 +1,8 @@ +tex code \begin{document} +tex code \texbf Hello world +tex blank +tex blank +tex comment % +tex comment % sample comment +tex blank +tex code \end{document} diff --git a/test/expected_dir/foo.tex/tex/blanks b/test/expected_dir/foo.tex/tex/blanks deleted file mode 100644 index e440e5c..0000000 --- a/test/expected_dir/foo.tex/tex/blanks +++ /dev/null @@ -1 +0,0 @@ -3 \ No newline at end of file diff --git a/test/expected_dir/foo.tex/tex/code b/test/expected_dir/foo.tex/tex/code deleted file mode 100644 index aec1334..0000000 --- a/test/expected_dir/foo.tex/tex/code +++ /dev/null @@ -1,3 +0,0 @@ -\begin{document} -\texbf Hello world -\end{document} diff --git a/test/expected_dir/foo.tex/tex/comment b/test/expected_dir/foo.tex/tex/comment deleted file mode 100644 index 1a8caa7..0000000 --- a/test/expected_dir/foo.tex/tex/comment +++ /dev/null @@ -1,2 +0,0 @@ -% -% sample comment diff --git a/test/expected_dir/foo.vim b/test/expected_dir/foo.vim new file mode 100644 index 0000000..4322100 --- /dev/null +++ b/test/expected_dir/foo.vim @@ -0,0 +1,21 @@ +vim comment " Vim syntax file +vim comment " Language: Test file for ohcount +vim comment " Author: Ciaran McCreesh +vim comment " +vim comment " This is a test vim syntax file for ohcount. +vim comment " +vim blank +vim code if &compatible || v:version < 700 +vim code finish +vim code endif +vim blank +vim code if exists("b:current_syntax") +vim code finish +vim code endif +vim blank +vim comment " This is a comment. There are many like it, but this one is mine. +vim code syn region GiantSpaceMonkey start=/^\s*#/ end=/$/ +vim code hi def link GiantSpaceMonkey Comment +vim blank +vim code let b:current_syntax = "ohcount-test" +vim blank diff --git a/test/expected_dir/foo.vim/vim/blanks b/test/expected_dir/foo.vim/vim/blanks deleted file mode 100644 index 7813681..0000000 --- a/test/expected_dir/foo.vim/vim/blanks +++ /dev/null @@ -1 +0,0 @@ -5 \ No newline at end of file diff --git a/test/expected_dir/foo.vim/vim/code b/test/expected_dir/foo.vim/vim/code deleted file mode 100644 index 8f97fe5..0000000 --- a/test/expected_dir/foo.vim/vim/code +++ /dev/null @@ -1,9 +0,0 @@ -if &compatible || v:version < 700 -finish -endif -if exists("b:current_syntax") -finish -endif -syn region GiantSpaceMonkey start=/^\s*#/ end=/$/ -hi def link GiantSpaceMonkey Comment -let b:current_syntax = "ohcount-test" diff --git a/test/expected_dir/foo.vim/vim/comment b/test/expected_dir/foo.vim/vim/comment deleted file mode 100644 index 6b55283..0000000 --- a/test/expected_dir/foo.vim/vim/comment +++ /dev/null @@ -1,7 +0,0 @@ -" Vim syntax file -" Language: Test file for ohcount -" Author: Ciaran McCreesh -" -" This is a test vim syntax file for ohcount. -" -" This is a comment. There are many like it, but this one is mine. diff --git a/test/expected_dir/fortranfixed.f b/test/expected_dir/fortranfixed.f new file mode 100644 index 0000000..0dfeb11 --- /dev/null +++ b/test/expected_dir/fortranfixed.f @@ -0,0 +1,12 @@ +fortranfixed comment C Just a comment, whee. +fortranfixed code program foo +fortranfixed blank +fortranfixed comment C Many languages seem to count split lines as multiple lines, +fortranfixed comment C so we should, too. +fortranfixed code write (*,*) 1 +fortranfixed code + + 1 +fortranfixed blank +fortranfixed comment C And I've never seen Fortran code that wraps strings; I'm +fortranfixed comment C not even sure fixed form allows it. +fortranfixed code write (*,*) 'So we don''t bother testing odd string foo.' +fortranfixed code end diff --git a/test/expected_dir/fortranfixed.f/fortranfixed/blanks b/test/expected_dir/fortranfixed.f/fortranfixed/blanks deleted file mode 100644 index d8263ee..0000000 --- a/test/expected_dir/fortranfixed.f/fortranfixed/blanks +++ /dev/null @@ -1 +0,0 @@ -2 \ No newline at end of file diff --git a/test/expected_dir/fortranfixed.f/fortranfixed/code b/test/expected_dir/fortranfixed.f/fortranfixed/code deleted file mode 100644 index 70b8166..0000000 --- a/test/expected_dir/fortranfixed.f/fortranfixed/code +++ /dev/null @@ -1,5 +0,0 @@ -program foo -write (*,*) 1 -+ + 1 -write (*,*) 'So we don''t bother testing odd string foo.' -end diff --git a/test/expected_dir/fortranfixed.f/fortranfixed/comment b/test/expected_dir/fortranfixed.f/fortranfixed/comment deleted file mode 100644 index df99f9c..0000000 --- a/test/expected_dir/fortranfixed.f/fortranfixed/comment +++ /dev/null @@ -1,5 +0,0 @@ -C Just a comment, whee. -C Many languages seem to count split lines as multiple lines, -C so we should, too. -C And I've never seen Fortran code that wraps strings; I'm -C not even sure fixed form allows it. diff --git a/test/expected_dir/fortranfree.f b/test/expected_dir/fortranfree.f new file mode 100644 index 0000000..cee279b --- /dev/null +++ b/test/expected_dir/fortranfree.f @@ -0,0 +1,18 @@ +fortranfree comment ! -*- F90 -*- +fortranfree comment ! Just a comment, whee. +fortranfree code program foofree +fortranfree code integer:: c +fortranfree blank +fortranfree comment ! Many languages seem to count split lines as multiple lines, +fortranfree comment ! so we should, too. +fortranfree code write (*,*) 1 & +fortranfree code & + 1 +fortranfree blank +fortranfree code C = 1 ! Not a comment. +fortranfree blank +fortranfree comment ! And I've never seen Fortran code that wraps strings; I'm +fortranfree comment ! not even sure fixed form allows it. +fortranfree code write (*,*) 'But we might as well test for it in& +fortranfree code & free format.' +fortranfree blank +fortranfree code end diff --git a/test/expected_dir/fortranfree.f/fortranfree/blanks b/test/expected_dir/fortranfree.f/fortranfree/blanks deleted file mode 100644 index bf0d87a..0000000 --- a/test/expected_dir/fortranfree.f/fortranfree/blanks +++ /dev/null @@ -1 +0,0 @@ -4 \ No newline at end of file diff --git a/test/expected_dir/fortranfree.f/fortranfree/code b/test/expected_dir/fortranfree.f/fortranfree/code deleted file mode 100644 index 7f06fd1..0000000 --- a/test/expected_dir/fortranfree.f/fortranfree/code +++ /dev/null @@ -1,8 +0,0 @@ -program foofree -integer:: c -write (*,*) 1 & -& + 1 -C = 1 ! Not a comment. -write (*,*) 'But we might as well test for it in& -& free format.' -end diff --git a/test/expected_dir/fortranfree.f/fortranfree/comment b/test/expected_dir/fortranfree.f/fortranfree/comment deleted file mode 100644 index 1fc32e7..0000000 --- a/test/expected_dir/fortranfree.f/fortranfree/comment +++ /dev/null @@ -1,6 +0,0 @@ -! -*- F90 -*- -! Just a comment, whee. -! Many languages seem to count split lines as multiple lines, -! so we should, too. -! And I've never seen Fortran code that wraps strings; I'm -! not even sure fixed form allows it. diff --git a/test/expected_dir/frx1.frx b/test/expected_dir/frx1.frx new file mode 100644 index 0000000..c8331c6 --- /dev/null +++ b/test/expected_dir/frx1.frx @@ -0,0 +1,60 @@ +visualbasic code VERSION 5.00 +visualbasic code Object = "{67397AA1-7FB1-11D0-B148-00A0C922E820}#6.0#0"; "MSADODC.OCX" +visualbasic code Object = "{BDC217C8-ED16-11CD-956C-0000C04E4C0A}#1.1#0"; "TABCTL32.OCX" +visualbasic code Object = "{CDE57A40-8B86-11D0-B3C6-00A0C90AEA82}#1.0#0"; "MSDATGRD.OCX" +visualbasic code Object = "{0ECD9B60-23AA-11D0-B351-00A0C9055D8E}#6.0#0"; "MSHFLXGD.OCX" +visualbasic code Object = "{831FDD16-0C5C-11D2-A9FC-0000F8754DA1}#2.0#0"; "MSCOMCTL.OCX" +visualbasic code Begin VB.Form frmMain +visualbasic code BorderStyle = 1 'Fixed Single +visualbasic code ClientHeight = 6555 +visualbasic code ClientLeft = 150 +visualbasic code ClientTop = 435 +visualbasic code ClientWidth = 10620 +visualbasic code LinkTopic = "Form1" +visualbasic code MaxButton = 0 'False +visualbasic code MinButton = 0 'False +visualbasic code ScaleHeight = 6555 +visualbasic code ScaleWidth = 10620 +visualbasic code StartUpPosition = 3 'Windows Default +visualbasic code Attribute VB_Name = "frmMain" +visualbasic code Attribute VB_GlobalNameSpace = False +visualbasic code Attribute VB_Creatable = False +visualbasic code Attribute VB_PredeclaredId = True +visualbasic code Attribute VB_Exposed = False +visualbasic comment '--------------------------------------------------------------------------- +visualbasic comment ' +visualbasic comment ' SOURCE FILE NAME: Demo.frm +visualbasic comment ' +visualbasic comment ' SAMPLE: Visual Basic Demo with user interface for the sample modules +visualbasic comment ' +visualbasic comment ' For more information about samples, refer to the README file. +visualbasic comment ' +visualbasic comment '--------------------------------------------------------------------------- +visualbasic blank +visualbasic code Option Explicit +visualbasic blank +visualbasic code Private con As ADODB.Connection +visualbasic code Private rst As ADODB.Recordset +visualbasic code Private strMsgText As String +visualbasic code Private wShowInstructions As Integer +visualbasic blank +visualbasic comment 'This procedure calls ConnectOLEDB() in the module dbConn to get +visualbasic comment 'a connection object. +visualbasic code Private Sub cmdConnectOLEDB_Click() +visualbasic comment 'define the error handler +visualbasic comment ' On Error GoTo cmdConnectOLEDB_Error +visualbasic blank +visualbasic comment 'connect to database +visualbasic code Set con = ConnectOLEDB() +visualbasic blank +visualbasic comment 'generate a message of success +visualbasic code sbrStatus.Panels(1).Text = "Connect to sample database succeeded!" +visualbasic blank +visualbasic comment 'config status of the buttons +visualbasic code EnableButtons +visualbasic blank +visualbasic comment 'show instructions +visualbasic code If wShowInstructions = vbYes Then +visualbasic code ShowConnectionInstruction +visualbasic code End If +visualbasic code End Sub diff --git a/test/expected_dir/frx1.frx/visualbasic/blanks b/test/expected_dir/frx1.frx/visualbasic/blanks deleted file mode 100644 index c793025..0000000 --- a/test/expected_dir/frx1.frx/visualbasic/blanks +++ /dev/null @@ -1 +0,0 @@ -7 \ No newline at end of file diff --git a/test/expected_dir/frx1.frx/visualbasic/code b/test/expected_dir/frx1.frx/visualbasic/code deleted file mode 100644 index d0fa5b8..0000000 --- a/test/expected_dir/frx1.frx/visualbasic/code +++ /dev/null @@ -1,36 +0,0 @@ -VERSION 5.00 -Object = "{67397AA1-7FB1-11D0-B148-00A0C922E820}#6.0#0"; "MSADODC.OCX" -Object = "{BDC217C8-ED16-11CD-956C-0000C04E4C0A}#1.1#0"; "TABCTL32.OCX" -Object = "{CDE57A40-8B86-11D0-B3C6-00A0C90AEA82}#1.0#0"; "MSDATGRD.OCX" -Object = "{0ECD9B60-23AA-11D0-B351-00A0C9055D8E}#6.0#0"; "MSHFLXGD.OCX" -Object = "{831FDD16-0C5C-11D2-A9FC-0000F8754DA1}#2.0#0"; "MSCOMCTL.OCX" -Begin VB.Form frmMain -BorderStyle = 1 'Fixed Single -ClientHeight = 6555 -ClientLeft = 150 -ClientTop = 435 -ClientWidth = 10620 -LinkTopic = "Form1" -MaxButton = 0 'False -MinButton = 0 'False -ScaleHeight = 6555 -ScaleWidth = 10620 -StartUpPosition = 3 'Windows Default -Attribute VB_Name = "frmMain" -Attribute VB_GlobalNameSpace = False -Attribute VB_Creatable = False -Attribute VB_PredeclaredId = True -Attribute VB_Exposed = False -Option Explicit -Private con As ADODB.Connection -Private rst As ADODB.Recordset -Private strMsgText As String -Private wShowInstructions As Integer -Private Sub cmdConnectOLEDB_Click() -Set con = ConnectOLEDB() -sbrStatus.Panels(1).Text = "Connect to sample database succeeded!" -EnableButtons -If wShowInstructions = vbYes Then -ShowConnectionInstruction -End If -End Sub diff --git a/test/expected_dir/frx1.frx/visualbasic/comment b/test/expected_dir/frx1.frx/visualbasic/comment deleted file mode 100644 index fc9649a..0000000 --- a/test/expected_dir/frx1.frx/visualbasic/comment +++ /dev/null @@ -1,17 +0,0 @@ -'--------------------------------------------------------------------------- -' -' SOURCE FILE NAME: Demo.frm -' -' SAMPLE: Visual Basic Demo with user interface for the sample modules -' -' For more information about samples, refer to the README file. -' -'--------------------------------------------------------------------------- -'This procedure calls ConnectOLEDB() in the module dbConn to get -'a connection object. -'define the error handler -' On Error GoTo cmdConnectOLEDB_Error -'connect to database -'generate a message of success -'config status of the buttons -'show instructions diff --git a/test/expected_dir/groovy1.groovy b/test/expected_dir/groovy1.groovy new file mode 100644 index 0000000..438f2b4 --- /dev/null +++ b/test/expected_dir/groovy1.groovy @@ -0,0 +1,9 @@ +groovy comment //hello.groovy +groovy code println "hello, world" +groovy code for (arg in this.args ) { +groovy code println "Argument:" + arg; +groovy code } +groovy comment // this is a comment +groovy comment /* a block comment, commenting out an alternative to above: +groovy comment this.args.each{ arg -> println "hello, ${arg}"} +groovy comment */ diff --git a/test/expected_dir/groovy1.groovy/groovy/blanks b/test/expected_dir/groovy1.groovy/groovy/blanks deleted file mode 100644 index c227083..0000000 --- a/test/expected_dir/groovy1.groovy/groovy/blanks +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/test/expected_dir/groovy1.groovy/groovy/code b/test/expected_dir/groovy1.groovy/groovy/code deleted file mode 100644 index b881b63..0000000 --- a/test/expected_dir/groovy1.groovy/groovy/code +++ /dev/null @@ -1,4 +0,0 @@ -println "hello, world" -for (arg in this.args ) { -println "Argument:" + arg; -} diff --git a/test/expected_dir/groovy1.groovy/groovy/comment b/test/expected_dir/groovy1.groovy/groovy/comment deleted file mode 100644 index a033d4b..0000000 --- a/test/expected_dir/groovy1.groovy/groovy/comment +++ /dev/null @@ -1,5 +0,0 @@ -//hello.groovy -// this is a comment -/* a block comment, commenting out an alternative to above: -this.args.each{ arg -> println "hello, ${arg}"} -*/ diff --git a/test/expected_dir/haml.haml b/test/expected_dir/haml.haml new file mode 100644 index 0000000..8613fde --- /dev/null +++ b/test/expected_dir/haml.haml @@ -0,0 +1,20 @@ +haml code %p +ruby code %p= "stuff" +haml comment / oneliner! +haml code %p +haml comment / +haml comment %p this won't render +haml comment %p it is a comment! +ruby code %p= "stuff" +haml code %p +ruby code - code +ruby code %p= "stuff" +haml code %p +haml blank +haml code \- not script! +haml comment -# silent comment +haml code %p +haml comment -# +haml comment silent +haml comment comment +haml code %br/ diff --git a/test/expected_dir/haml.haml/haml/blanks b/test/expected_dir/haml.haml/haml/blanks deleted file mode 100644 index 56a6051..0000000 --- a/test/expected_dir/haml.haml/haml/blanks +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/test/expected_dir/haml.haml/haml/code b/test/expected_dir/haml.haml/haml/code deleted file mode 100644 index 1c4e917..0000000 --- a/test/expected_dir/haml.haml/haml/code +++ /dev/null @@ -1,7 +0,0 @@ -%p -%p -%p -%p -\- not script! -%p -%br/ diff --git a/test/expected_dir/haml.haml/haml/comment b/test/expected_dir/haml.haml/haml/comment deleted file mode 100644 index 5d36be9..0000000 --- a/test/expected_dir/haml.haml/haml/comment +++ /dev/null @@ -1,8 +0,0 @@ -/ oneliner! -/ -%p this won't render -%p it is a comment! --# silent comment --# -silent -comment diff --git a/test/expected_dir/haml.haml/ruby/blanks b/test/expected_dir/haml.haml/ruby/blanks deleted file mode 100644 index c227083..0000000 --- a/test/expected_dir/haml.haml/ruby/blanks +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/test/expected_dir/haml.haml/ruby/code b/test/expected_dir/haml.haml/ruby/code deleted file mode 100644 index c3cb07e..0000000 --- a/test/expected_dir/haml.haml/ruby/code +++ /dev/null @@ -1,4 +0,0 @@ -%p= "stuff" -%p= "stuff" -- code -%p= "stuff" diff --git a/test/expected_dir/haml.haml/ruby/comment b/test/expected_dir/haml.haml/ruby/comment deleted file mode 100644 index e69de29..0000000 diff --git a/test/expected_dir/haskell1.hs b/test/expected_dir/haskell1.hs new file mode 100644 index 0000000..1f503ce --- /dev/null +++ b/test/expected_dir/haskell1.hs @@ -0,0 +1,108 @@ +haskell comment {-| +haskell comment This module contains some functions that are useful in several places in the +haskell comment program and don't belong to one specific other module. +haskell comment -} +haskell code module Gnutella.Misc where +haskell blank +haskell code import Data.ByteString(ByteString) +haskell code import qualified Data.ByteString as BS +haskell code import Data.Bits +haskell code import Data.Word +haskell code import Text.Read +haskell code import Data.Char(isNumber) +haskell code import Data.List(intersperse) +haskell code import Network +haskell code import Network.BSD(getHostByName, HostEntry(..)) +haskell code import Network.Socket(HostAddress(..)) +haskell code import Debug.Trace +haskell blank +haskell comment {-| +haskell comment Maakt van vier bytes een Word32. Gaat ervan uit dat die vier bytes little-endian achter elkaar +haskell comment staan. Als de gegeven string korter is dan 4 bytes, termineert de functie. Als de string langer +haskell comment is, worden alle bytes voorbij de vierde genegeerd. +haskell comment -} +haskell code composeWord32 :: ByteString -> Word32 +haskell code composeWord32 s = shiftL byte4 24 + shiftL byte3 16 + shiftL byte2 8 + byte1 +haskell code where byte1, byte2, byte3, byte4 :: Word32 +haskell code [byte1, byte2, byte3, byte4] = map fromIntegral $ BS.unpack (BS.take 4 s) +haskell blank +haskell comment {-| +haskell comment Turns a Word32 into a tuple of Word8s. The tuple is little-endian: the least +haskell comment significant octet comes first. +haskell comment -} +haskell code word32ToWord8s :: Word32 -> (Word8, Word8, Word8, Word8) +haskell code word32ToWord8s w = (fromIntegral (w .&. 0x000000ff) +haskell code ,fromIntegral (shiftR w 8 .&. 0x000000ff) +haskell code ,fromIntegral (shiftR w 16 .&. 0x000000ff) +haskell code ,fromIntegral (shiftR w 24 .&. 0x000000ff) +haskell code ) +haskell blank +haskell comment {-| +haskell comment Parses a host specification in the "name:12345"-style notation into a hostname +haskell comment and a port number. +haskell blank +haskell comment As a rather special feature, it returns 6346 as the port number when there is +haskell comment no port specified. When there is a port specified, but it is unparseable, it +haskell comment returns Nothing. +haskell comment -} +haskell code parseHostnameWithPort :: String -> IO (Maybe ((Word8, Word8, Word8, Word8) +haskell code ,PortNumber)) +haskell code parseHostnameWithPort str = do maybeHostName <- stringToIP hostNameStr +haskell code return $ (do portNum <- maybePortNum +haskell code hostName <- maybeHostName +haskell code return (hostName, portNum) +haskell code ) +haskell code where hostNameStr = takeWhile (/=':') str +haskell code maybePortNum = case tail (dropWhile (/=':') str) of +haskell code [] -> Just $ 6346 +haskell code s -> case reads s of +haskell code [] -> Nothing +haskell code (x:xs) -> Just $ fromIntegral $ fst x +haskell blank +haskell comment {-| +haskell comment Translates a string, representing an IP address, to a list of bytes. +haskell comment Returns Nothing when the string does not represent an IP address in xxx.xxx.xxx.xxx format +haskell comment -} +haskell code ipStringToBytes :: String -> Maybe (Word8, Word8, Word8, Word8) +haskell comment -- Again, hugs won't let us use regexes where they would be damn convenient +haskell code ipStringToBytes s = +haskell code let ipBytesStrings = splitAtDots s +haskell code in if all (all isNumber) ipBytesStrings +haskell code then let bytesList = map (fst . head . reads) ipBytesStrings +haskell code in Just (bytesList!!0 +haskell code ,bytesList!!1 +haskell code ,bytesList!!2 +haskell code ,bytesList!!3 +haskell code ) +haskell code else Nothing +haskell code where splitAtDots s = foldr (\c (n:nums) -> if c == '.' +haskell code then [] : n : nums +haskell code else (c:n) : nums +haskell code ) [[]] s +haskell blank +haskell comment {-| +haskell comment Translates a list of bytes representing an IP address (big endian) to a string +haskell comment in the xxx.xxx.xxx.xxx format. +haskell comment -} +haskell code ipBytesToString :: (Word8, Word8, Word8, Word8) -> String +haskell code ipBytesToString (b1, b2, b3, b4) = +haskell code concat $ intersperse "." $ map show [b1, b2, b3, b4] +haskell blank +haskell comment {-| +haskell comment Takes a String that's either an IP address or a hostname, and returns you the +haskell comment IP address as a list of 4 bytes (in big-endian byte order). It returns Nothing +haskell comment if there is no parse for the string as IP address and the hostname can't be +haskell comment found. +haskell comment -} +haskell code stringToIP :: String -> IO (Maybe (Word8, Word8, Word8, Word8)) +haskell code stringToIP hostName = case ipStringToBytes hostName of +haskell code Just a -> return (Just a) +haskell code Nothing -> do hostent <- getHostByName hostName +haskell code let ipWord32 = head (hostAddresses hostent) +haskell code ipWord8s = word32ToWord8s ipWord32 +haskell code return (Just ipWord8s) +haskell blank +haskell comment -- used in reading the hostcache +haskell code instance Read PortNumber where +haskell code readsPrec i = map (\(a, b) -> (fromIntegral a, b)) . (readsPrec i :: ReadS Word16) +haskell blank diff --git a/test/expected_dir/haskell1.hs/haskell/blanks b/test/expected_dir/haskell1.hs/haskell/blanks deleted file mode 100644 index 9a03714..0000000 --- a/test/expected_dir/haskell1.hs/haskell/blanks +++ /dev/null @@ -1 +0,0 @@ -10 \ No newline at end of file diff --git a/test/expected_dir/haskell1.hs/haskell/code b/test/expected_dir/haskell1.hs/haskell/code deleted file mode 100644 index d589023..0000000 --- a/test/expected_dir/haskell1.hs/haskell/code +++ /dev/null @@ -1,62 +0,0 @@ -module Gnutella.Misc where -import Data.ByteString(ByteString) -import qualified Data.ByteString as BS -import Data.Bits -import Data.Word -import Text.Read -import Data.Char(isNumber) -import Data.List(intersperse) -import Network -import Network.BSD(getHostByName, HostEntry(..)) -import Network.Socket(HostAddress(..)) -import Debug.Trace -composeWord32 :: ByteString -> Word32 -composeWord32 s = shiftL byte4 24 + shiftL byte3 16 + shiftL byte2 8 + byte1 -where byte1, byte2, byte3, byte4 :: Word32 -[byte1, byte2, byte3, byte4] = map fromIntegral $ BS.unpack (BS.take 4 s) -word32ToWord8s :: Word32 -> (Word8, Word8, Word8, Word8) -word32ToWord8s w = (fromIntegral (w .&. 0x000000ff) -,fromIntegral (shiftR w 8 .&. 0x000000ff) -,fromIntegral (shiftR w 16 .&. 0x000000ff) -,fromIntegral (shiftR w 24 .&. 0x000000ff) -) -parseHostnameWithPort :: String -> IO (Maybe ((Word8, Word8, Word8, Word8) -,PortNumber)) -parseHostnameWithPort str = do maybeHostName <- stringToIP hostNameStr -return $ (do portNum <- maybePortNum -hostName <- maybeHostName -return (hostName, portNum) -) -where hostNameStr = takeWhile (/=':') str -maybePortNum = case tail (dropWhile (/=':') str) of -[] -> Just $ 6346 -s -> case reads s of -[] -> Nothing -(x:xs) -> Just $ fromIntegral $ fst x -ipStringToBytes :: String -> Maybe (Word8, Word8, Word8, Word8) -ipStringToBytes s = -let ipBytesStrings = splitAtDots s -in if all (all isNumber) ipBytesStrings -then let bytesList = map (fst . head . reads) ipBytesStrings -in Just (bytesList!!0 -,bytesList!!1 -,bytesList!!2 -,bytesList!!3 -) -else Nothing -where splitAtDots s = foldr (\c (n:nums) -> if c == '.' -then [] : n : nums -else (c:n) : nums -) [[]] s -ipBytesToString :: (Word8, Word8, Word8, Word8) -> String -ipBytesToString (b1, b2, b3, b4) = -concat $ intersperse "." $ map show [b1, b2, b3, b4] -stringToIP :: String -> IO (Maybe (Word8, Word8, Word8, Word8)) -stringToIP hostName = case ipStringToBytes hostName of -Just a -> return (Just a) -Nothing -> do hostent <- getHostByName hostName -let ipWord32 = head (hostAddresses hostent) -ipWord8s = word32ToWord8s ipWord32 -return (Just ipWord8s) -instance Read PortNumber where -readsPrec i = map (\(a, b) -> (fromIntegral a, b)) . (readsPrec i :: ReadS Word16) diff --git a/test/expected_dir/haskell1.hs/haskell/comment b/test/expected_dir/haskell1.hs/haskell/comment deleted file mode 100644 index 497490f..0000000 --- a/test/expected_dir/haskell1.hs/haskell/comment +++ /dev/null @@ -1,36 +0,0 @@ -{-| -This module contains some functions that are useful in several places in the -program and don't belong to one specific other module. --} -{-| -Maakt van vier bytes een Word32. Gaat ervan uit dat die vier bytes little-endian achter elkaar -staan. Als de gegeven string korter is dan 4 bytes, termineert de functie. Als de string langer -is, worden alle bytes voorbij de vierde genegeerd. --} -{-| -Turns a Word32 into a tuple of Word8s. The tuple is little-endian: the least -significant octet comes first. --} -{-| -Parses a host specification in the "name:12345"-style notation into a hostname -and a port number. -As a rather special feature, it returns 6346 as the port number when there is -no port specified. When there is a port specified, but it is unparseable, it -returns Nothing. --} -{-| -Translates a string, representing an IP address, to a list of bytes. -Returns Nothing when the string does not represent an IP address in xxx.xxx.xxx.xxx format --} --- Again, hugs won't let us use regexes where they would be damn convenient -{-| -Translates a list of bytes representing an IP address (big endian) to a string -in the xxx.xxx.xxx.xxx format. --} -{-| -Takes a String that's either an IP address or a hostname, and returns you the -IP address as a list of 4 bytes (in big-endian byte order). It returns Nothing -if there is no parse for the string as IP address and the hostname can't be -found. --} --- used in reading the hostcache diff --git a/test/expected_dir/haskell2.hs b/test/expected_dir/haskell2.hs new file mode 100644 index 0000000..80b3dfc --- /dev/null +++ b/test/expected_dir/haskell2.hs @@ -0,0 +1,4 @@ +haskell comment {-| +haskell blank +haskell comment -} +haskell blank diff --git a/test/expected_dir/haskell2.hs/haskell/blanks b/test/expected_dir/haskell2.hs/haskell/blanks deleted file mode 100644 index d8263ee..0000000 --- a/test/expected_dir/haskell2.hs/haskell/blanks +++ /dev/null @@ -1 +0,0 @@ -2 \ No newline at end of file diff --git a/test/expected_dir/haskell2.hs/haskell/code b/test/expected_dir/haskell2.hs/haskell/code deleted file mode 100644 index e69de29..0000000 diff --git a/test/expected_dir/haskell2.hs/haskell/comment b/test/expected_dir/haskell2.hs/haskell/comment deleted file mode 100644 index f1158de..0000000 --- a/test/expected_dir/haskell2.hs/haskell/comment +++ /dev/null @@ -1,2 +0,0 @@ -{-| --} diff --git a/test/expected_dir/haskell3.hs b/test/expected_dir/haskell3.hs new file mode 100644 index 0000000..8d2c542 --- /dev/null +++ b/test/expected_dir/haskell3.hs @@ -0,0 +1,5 @@ +haskell comment {- +haskell comment {- 3 lines of comments total! -} +haskell blank +haskell comment -} +haskell blank diff --git a/test/expected_dir/haskell3.hs/haskell/blanks b/test/expected_dir/haskell3.hs/haskell/blanks deleted file mode 100644 index d8263ee..0000000 --- a/test/expected_dir/haskell3.hs/haskell/blanks +++ /dev/null @@ -1 +0,0 @@ -2 \ No newline at end of file diff --git a/test/expected_dir/haskell3.hs/haskell/code b/test/expected_dir/haskell3.hs/haskell/code deleted file mode 100644 index e69de29..0000000 diff --git a/test/expected_dir/haskell3.hs/haskell/comment b/test/expected_dir/haskell3.hs/haskell/comment deleted file mode 100644 index 3f50acf..0000000 --- a/test/expected_dir/haskell3.hs/haskell/comment +++ /dev/null @@ -1,3 +0,0 @@ -{- -{- 3 lines of comments total! -} --} diff --git a/test/expected_dir/html1.html b/test/expected_dir/html1.html new file mode 100644 index 0000000..29032bf --- /dev/null +++ b/test/expected_dir/html1.html @@ -0,0 +1,38 @@ +html code +html code +html code +html code foo +html code +html code +html code +html code +html code

+html code +html code not in comment +html code +html code italic?]]> +html code

+html comment +html code +html code diff --git a/test/expected_dir/html1.html/css/blanks b/test/expected_dir/html1.html/css/blanks deleted file mode 100644 index c227083..0000000 --- a/test/expected_dir/html1.html/css/blanks +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/test/expected_dir/html1.html/css/code b/test/expected_dir/html1.html/css/code deleted file mode 100644 index 014b64e..0000000 --- a/test/expected_dir/html1.html/css/code +++ /dev/null @@ -1,3 +0,0 @@ -p { -color: #444 -} diff --git a/test/expected_dir/html1.html/css/comment b/test/expected_dir/html1.html/css/comment deleted file mode 100644 index e69de29..0000000 diff --git a/test/expected_dir/html1.html/html/blanks b/test/expected_dir/html1.html/html/blanks deleted file mode 100644 index c227083..0000000 --- a/test/expected_dir/html1.html/html/blanks +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/test/expected_dir/html1.html/html/code b/test/expected_dir/html1.html/html/code deleted file mode 100644 index b5eca21..0000000 --- a/test/expected_dir/html1.html/html/code +++ /dev/null @@ -1,18 +0,0 @@ - - - -foo - - - - -

- -not in comment - -italic?]]> -

- - diff --git a/test/expected_dir/html1.html/html/comment b/test/expected_dir/html1.html/html/comment deleted file mode 100644 index 30c82f6..0000000 --- a/test/expected_dir/html1.html/html/comment +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/test/expected_dir/html1.html/javascript/blanks b/test/expected_dir/html1.html/javascript/blanks deleted file mode 100644 index c227083..0000000 --- a/test/expected_dir/html1.html/javascript/blanks +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/test/expected_dir/html1.html/javascript/code b/test/expected_dir/html1.html/javascript/code deleted file mode 100644 index 69671f1..0000000 --- a/test/expected_dir/html1.html/javascript/code +++ /dev/null @@ -1,13 +0,0 @@ - diff --git a/test/expected_dir/html1.html/javascript/comment b/test/expected_dir/html1.html/javascript/comment deleted file mode 100644 index ecd132d..0000000 --- a/test/expected_dir/html1.html/javascript/comment +++ /dev/null @@ -1 +0,0 @@ -// javascript comment diff --git a/test/expected_dir/java1.java b/test/expected_dir/java1.java new file mode 100644 index 0000000..77a4c28 --- /dev/null +++ b/test/expected_dir/java1.java @@ -0,0 +1,48 @@ +java comment // Program 11.6: A nicer sine wave +java code import java.applet.Applet; +java code import java.awt.Graphics; +java blank +java code public class SineApplet2 extends Applet { +java blank +java code public void paint(Graphics g) { +java blank +java code int i, j1, j2; +java blank +java code j1 = yvalue(0); +java code for (i = 0; i < size().width; i++) { +java code j2 = yvalue(i+1); +java code g.drawLine(i, j1 ,i+1, j2); +java code j1 = j2; +java code } +java blank +java code } +java blank +java comment // Given the xpoint we're given calculate the Cartesian equivalent +java code private int yvalue(int ivalue) { +java blank +java code double xmin = -10.0; +java code double xmax = 10.0; +java code double ymin = -1.0; +java code double ymax = 1.0; +java code double x, y; +java code int jvalue; +java blank +java code x = (ivalue * (xmax - xmin)/(size().width - 1)) + xmin; +java blank +java comment // Take the sine of that x +java code y = Math.sin(x); +java blank +java comment // Scale y into window coordinates +java code jvalue = (int) ((y - ymin)*(size().height - 1)/ +java code (ymax - ymin)); +java blank +java comment /* Switch jvalue from Cartesian coordinates +java comment to computer graphics coordinates */ +java code jvalue = size().height - jvalue; +java blank +java code return jvalue; +java blank +java code } +java blank +java code } +java blank diff --git a/test/expected_dir/java1.java/java/blanks b/test/expected_dir/java1.java/java/blanks deleted file mode 100644 index 3f10ffe..0000000 --- a/test/expected_dir/java1.java/java/blanks +++ /dev/null @@ -1 +0,0 @@ -15 \ No newline at end of file diff --git a/test/expected_dir/java1.java/java/code b/test/expected_dir/java1.java/java/code deleted file mode 100644 index 5966c9a..0000000 --- a/test/expected_dir/java1.java/java/code +++ /dev/null @@ -1,27 +0,0 @@ -import java.applet.Applet; -import java.awt.Graphics; -public class SineApplet2 extends Applet { -public void paint(Graphics g) { -int i, j1, j2; -j1 = yvalue(0); -for (i = 0; i < size().width; i++) { -j2 = yvalue(i+1); -g.drawLine(i, j1 ,i+1, j2); -j1 = j2; -} -} -private int yvalue(int ivalue) { -double xmin = -10.0; -double xmax = 10.0; -double ymin = -1.0; -double ymax = 1.0; -double x, y; -int jvalue; -x = (ivalue * (xmax - xmin)/(size().width - 1)) + xmin; -y = Math.sin(x); -jvalue = (int) ((y - ymin)*(size().height - 1)/ -(ymax - ymin)); -jvalue = size().height - jvalue; -return jvalue; -} -} diff --git a/test/expected_dir/java1.java/java/comment b/test/expected_dir/java1.java/java/comment deleted file mode 100644 index b628454..0000000 --- a/test/expected_dir/java1.java/java/comment +++ /dev/null @@ -1,6 +0,0 @@ -// Program 11.6: A nicer sine wave -// Given the xpoint we're given calculate the Cartesian equivalent -// Take the sine of that x -// Scale y into window coordinates -/* Switch jvalue from Cartesian coordinates -to computer graphics coordinates */ diff --git a/test/expected_dir/java2.java b/test/expected_dir/java2.java new file mode 100644 index 0000000..bf64cae --- /dev/null +++ b/test/expected_dir/java2.java @@ -0,0 +1,3 @@ +java comment /** +java comment */ +java blank diff --git a/test/expected_dir/java2.java/java/blanks b/test/expected_dir/java2.java/java/blanks deleted file mode 100644 index 56a6051..0000000 --- a/test/expected_dir/java2.java/java/blanks +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/test/expected_dir/java2.java/java/code b/test/expected_dir/java2.java/java/code deleted file mode 100644 index e69de29..0000000 diff --git a/test/expected_dir/java2.java/java/comment b/test/expected_dir/java2.java/java/comment deleted file mode 100644 index b3e6072..0000000 --- a/test/expected_dir/java2.java/java/comment +++ /dev/null @@ -1,2 +0,0 @@ -/** -*/ diff --git a/test/expected_dir/js1.js b/test/expected_dir/js1.js new file mode 100644 index 0000000..f7dabcb --- /dev/null +++ b/test/expected_dir/js1.js @@ -0,0 +1,1781 @@ +javascript comment /* Prototype JavaScript framework, version 1.4.0 +javascript comment * (c) 2005 Sam Stephenson +javascript comment * +javascript comment * Prototype is freely distributable under the terms of an MIT-style license. +javascript comment * For details, see the Prototype web site: http://prototype.conio.net/ +javascript comment * +javascript comment /*--------------------------------------------------------------------------*/ +javascript blank +javascript code var Prototype = { +javascript code Version: '1.4.0', +javascript code ScriptFragment: '(?:)((\n|\r|.)*?)(?:<\/script>)', +javascript blank +javascript code emptyFunction: function() {}, +javascript code K: function(x) {return x} +javascript code } +javascript blank +javascript code var Class = { +javascript code create: function() { +javascript code return function() { +javascript code this.initialize.apply(this, arguments); +javascript code } +javascript code } +javascript code } +javascript blank +javascript code var Abstract = new Object(); +javascript blank +javascript code Object.extend = function(destination, source) { +javascript code for (property in source) { +javascript code destination[property] = source[property]; +javascript code } +javascript code return destination; +javascript code } +javascript blank +javascript code Object.inspect = function(object) { +javascript code try { +javascript code if (object == undefined) return 'undefined'; +javascript code if (object == null) return 'null'; +javascript code return object.inspect ? object.inspect() : object.toString(); +javascript code } catch (e) { +javascript code if (e instanceof RangeError) return '...'; +javascript code throw e; +javascript code } +javascript code } +javascript blank +javascript code Function.prototype.bind = function() { +javascript code var __method = this, args = $A(arguments), object = args.shift(); +javascript code return function() { +javascript code return __method.apply(object, args.concat($A(arguments))); +javascript code } +javascript code } +javascript blank +javascript code Function.prototype.bindAsEventListener = function(object) { +javascript code var __method = this; +javascript code return function(event) { +javascript code return __method.call(object, event || window.event); +javascript code } +javascript code } +javascript blank +javascript code Object.extend(Number.prototype, { +javascript code toColorPart: function() { +javascript code var digits = this.toString(16); +javascript code if (this < 16) return '0' + digits; +javascript code return digits; +javascript code }, +javascript blank +javascript code succ: function() { +javascript code return this + 1; +javascript code }, +javascript blank +javascript code times: function(iterator) { +javascript code $R(0, this, true).each(iterator); +javascript code return this; +javascript code } +javascript code }); +javascript blank +javascript code var Try = { +javascript code these: function() { +javascript code var returnValue; +javascript blank +javascript code for (var i = 0; i < arguments.length; i++) { +javascript code var lambda = arguments[i]; +javascript code try { +javascript code returnValue = lambda(); +javascript code break; +javascript code } catch (e) {} +javascript code } +javascript blank +javascript code return returnValue; +javascript code } +javascript code } +javascript blank +javascript comment /*--------------------------------------------------------------------------*/ +javascript blank +javascript code var PeriodicalExecuter = Class.create(); +javascript code PeriodicalExecuter.prototype = { +javascript code initialize: function(callback, frequency) { +javascript code this.callback = callback; +javascript code this.frequency = frequency; +javascript code this.currentlyExecuting = false; +javascript blank +javascript code this.registerCallback(); +javascript code }, +javascript blank +javascript code registerCallback: function() { +javascript code setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); +javascript code }, +javascript blank +javascript code onTimerEvent: function() { +javascript code if (!this.currentlyExecuting) { +javascript code try { +javascript code this.currentlyExecuting = true; +javascript code this.callback(); +javascript code } finally { +javascript code this.currentlyExecuting = false; +javascript code } +javascript code } +javascript code } +javascript code } +javascript blank +javascript comment /*--------------------------------------------------------------------------*/ +javascript blank +javascript code function $() { +javascript code var elements = new Array(); +javascript blank +javascript code for (var i = 0; i < arguments.length; i++) { +javascript code var element = arguments[i]; +javascript code if (typeof element == 'string') +javascript code element = document.getElementById(element); +javascript blank +javascript code if (arguments.length == 1) +javascript code return element; +javascript blank +javascript code elements.push(element); +javascript code } +javascript blank +javascript code return elements; +javascript code } +javascript code Object.extend(String.prototype, { +javascript code stripTags: function() { +javascript code return this.replace(/<\/?[^>]+>/gi, ''); +javascript code }, +javascript blank +javascript code stripScripts: function() { +javascript code return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); +javascript code }, +javascript blank +javascript code extractScripts: function() { +javascript code var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); +javascript code var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); +javascript code return (this.match(matchAll) || []).map(function(scriptTag) { +javascript code return (scriptTag.match(matchOne) || ['', ''])[1]; +javascript code }); +javascript code }, +javascript blank +javascript code evalScripts: function() { +javascript code return this.extractScripts().map(eval); +javascript code }, +javascript blank +javascript code escapeHTML: function() { +javascript code var div = document.createElement('div'); +javascript code var text = document.createTextNode(this); +javascript code div.appendChild(text); +javascript code return div.innerHTML; +javascript code }, +javascript blank +javascript code unescapeHTML: function() { +javascript code var div = document.createElement('div'); +javascript code div.innerHTML = this.stripTags(); +javascript code return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; +javascript code }, +javascript blank +javascript code toQueryParams: function() { +javascript code var pairs = this.match(/^\??(.*)$/)[1].split('&'); +javascript code return pairs.inject({}, function(params, pairString) { +javascript code var pair = pairString.split('='); +javascript code params[pair[0]] = pair[1]; +javascript code return params; +javascript code }); +javascript code }, +javascript blank +javascript code toArray: function() { +javascript code return this.split(''); +javascript code }, +javascript blank +javascript code camelize: function() { +javascript code var oStringList = this.split('-'); +javascript code if (oStringList.length == 1) return oStringList[0]; +javascript blank +javascript code var camelizedString = this.indexOf('-') == 0 +javascript code ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) +javascript code : oStringList[0]; +javascript blank +javascript code for (var i = 1, len = oStringList.length; i < len; i++) { +javascript code var s = oStringList[i]; +javascript code camelizedString += s.charAt(0).toUpperCase() + s.substring(1); +javascript code } +javascript blank +javascript code return camelizedString; +javascript code }, +javascript blank +javascript code inspect: function() { +javascript code return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'"; +javascript code } +javascript code }); +javascript blank +javascript code String.prototype.parseQuery = String.prototype.toQueryParams; +javascript blank +javascript code var $break = new Object(); +javascript code var $continue = new Object(); +javascript blank +javascript code var Enumerable = { +javascript code each: function(iterator) { +javascript code var index = 0; +javascript code try { +javascript code this._each(function(value) { +javascript code try { +javascript code iterator(value, index++); +javascript code } catch (e) { +javascript code if (e != $continue) throw e; +javascript code } +javascript code }); +javascript code } catch (e) { +javascript code if (e != $break) throw e; +javascript code } +javascript code }, +javascript blank +javascript code all: function(iterator) { +javascript code var result = true; +javascript code this.each(function(value, index) { +javascript code result = result && !!(iterator || Prototype.K)(value, index); +javascript code if (!result) throw $break; +javascript code }); +javascript code return result; +javascript code }, +javascript blank +javascript code any: function(iterator) { +javascript code var result = true; +javascript code this.each(function(value, index) { +javascript code if (result = !!(iterator || Prototype.K)(value, index)) +javascript code throw $break; +javascript code }); +javascript code return result; +javascript code }, +javascript blank +javascript code collect: function(iterator) { +javascript code var results = []; +javascript code this.each(function(value, index) { +javascript code results.push(iterator(value, index)); +javascript code }); +javascript code return results; +javascript code }, +javascript blank +javascript code detect: function (iterator) { +javascript code var result; +javascript code this.each(function(value, index) { +javascript code if (iterator(value, index)) { +javascript code result = value; +javascript code throw $break; +javascript code } +javascript code }); +javascript code return result; +javascript code }, +javascript blank +javascript code findAll: function(iterator) { +javascript code var results = []; +javascript code this.each(function(value, index) { +javascript code if (iterator(value, index)) +javascript code results.push(value); +javascript code }); +javascript code return results; +javascript code }, +javascript blank +javascript code grep: function(pattern, iterator) { +javascript code var results = []; +javascript code this.each(function(value, index) { +javascript code var stringValue = value.toString(); +javascript code if (stringValue.match(pattern)) +javascript code results.push((iterator || Prototype.K)(value, index)); +javascript code }) +javascript code return results; +javascript code }, +javascript blank +javascript code include: function(object) { +javascript code var found = false; +javascript code this.each(function(value) { +javascript code if (value == object) { +javascript code found = true; +javascript code throw $break; +javascript code } +javascript code }); +javascript code return found; +javascript code }, +javascript blank +javascript code inject: function(memo, iterator) { +javascript code this.each(function(value, index) { +javascript code memo = iterator(memo, value, index); +javascript code }); +javascript code return memo; +javascript code }, +javascript blank +javascript code invoke: function(method) { +javascript code var args = $A(arguments).slice(1); +javascript code return this.collect(function(value) { +javascript code return value[method].apply(value, args); +javascript code }); +javascript code }, +javascript blank +javascript code max: function(iterator) { +javascript code var result; +javascript code this.each(function(value, index) { +javascript code value = (iterator || Prototype.K)(value, index); +javascript code if (value >= (result || value)) +javascript code result = value; +javascript code }); +javascript code return result; +javascript code }, +javascript blank +javascript code min: function(iterator) { +javascript code var result; +javascript code this.each(function(value, index) { +javascript code value = (iterator || Prototype.K)(value, index); +javascript code if (value <= (result || value)) +javascript code result = value; +javascript code }); +javascript code return result; +javascript code }, +javascript blank +javascript code partition: function(iterator) { +javascript code var trues = [], falses = []; +javascript code this.each(function(value, index) { +javascript code ((iterator || Prototype.K)(value, index) ? +javascript code trues : falses).push(value); +javascript code }); +javascript code return [trues, falses]; +javascript code }, +javascript blank +javascript code pluck: function(property) { +javascript code var results = []; +javascript code this.each(function(value, index) { +javascript code results.push(value[property]); +javascript code }); +javascript code return results; +javascript code }, +javascript blank +javascript code reject: function(iterator) { +javascript code var results = []; +javascript code this.each(function(value, index) { +javascript code if (!iterator(value, index)) +javascript code results.push(value); +javascript code }); +javascript code return results; +javascript code }, +javascript blank +javascript code sortBy: function(iterator) { +javascript code return this.collect(function(value, index) { +javascript code return {value: value, criteria: iterator(value, index)}; +javascript code }).sort(function(left, right) { +javascript code var a = left.criteria, b = right.criteria; +javascript code return a < b ? -1 : a > b ? 1 : 0; +javascript code }).pluck('value'); +javascript code }, +javascript blank +javascript code toArray: function() { +javascript code return this.collect(Prototype.K); +javascript code }, +javascript blank +javascript code zip: function() { +javascript code var iterator = Prototype.K, args = $A(arguments); +javascript code if (typeof args.last() == 'function') +javascript code iterator = args.pop(); +javascript blank +javascript code var collections = [this].concat(args).map($A); +javascript code return this.map(function(value, index) { +javascript code iterator(value = collections.pluck(index)); +javascript code return value; +javascript code }); +javascript code }, +javascript blank +javascript code inspect: function() { +javascript code return '#'; +javascript code } +javascript code } +javascript blank +javascript code Object.extend(Enumerable, { +javascript code map: Enumerable.collect, +javascript code find: Enumerable.detect, +javascript code select: Enumerable.findAll, +javascript code member: Enumerable.include, +javascript code entries: Enumerable.toArray +javascript code }); +javascript code var $A = Array.from = function(iterable) { +javascript code if (!iterable) return []; +javascript code if (iterable.toArray) { +javascript code return iterable.toArray(); +javascript code } else { +javascript code var results = []; +javascript code for (var i = 0; i < iterable.length; i++) +javascript code results.push(iterable[i]); +javascript code return results; +javascript code } +javascript code } +javascript blank +javascript code Object.extend(Array.prototype, Enumerable); +javascript blank +javascript code Array.prototype._reverse = Array.prototype.reverse; +javascript blank +javascript code Object.extend(Array.prototype, { +javascript code _each: function(iterator) { +javascript code for (var i = 0; i < this.length; i++) +javascript code iterator(this[i]); +javascript code }, +javascript blank +javascript code clear: function() { +javascript code this.length = 0; +javascript code return this; +javascript code }, +javascript blank +javascript code first: function() { +javascript code return this[0]; +javascript code }, +javascript blank +javascript code last: function() { +javascript code return this[this.length - 1]; +javascript code }, +javascript blank +javascript code compact: function() { +javascript code return this.select(function(value) { +javascript code return value != undefined || value != null; +javascript code }); +javascript code }, +javascript blank +javascript code flatten: function() { +javascript code return this.inject([], function(array, value) { +javascript code return array.concat(value.constructor == Array ? +javascript code value.flatten() : [value]); +javascript code }); +javascript code }, +javascript blank +javascript code without: function() { +javascript code var values = $A(arguments); +javascript code return this.select(function(value) { +javascript code return !values.include(value); +javascript code }); +javascript code }, +javascript blank +javascript code indexOf: function(object) { +javascript code for (var i = 0; i < this.length; i++) +javascript code if (this[i] == object) return i; +javascript code return -1; +javascript code }, +javascript blank +javascript code reverse: function(inline) { +javascript code return (inline !== false ? this : this.toArray())._reverse(); +javascript code }, +javascript blank +javascript code shift: function() { +javascript code var result = this[0]; +javascript code for (var i = 0; i < this.length - 1; i++) +javascript code this[i] = this[i + 1]; +javascript code this.length--; +javascript code return result; +javascript code }, +javascript blank +javascript code inspect: function() { +javascript code return '[' + this.map(Object.inspect).join(', ') + ']'; +javascript code } +javascript code }); +javascript code var Hash = { +javascript code _each: function(iterator) { +javascript code for (key in this) { +javascript code var value = this[key]; +javascript code if (typeof value == 'function') continue; +javascript blank +javascript code var pair = [key, value]; +javascript code pair.key = key; +javascript code pair.value = value; +javascript code iterator(pair); +javascript code } +javascript code }, +javascript blank +javascript code keys: function() { +javascript code return this.pluck('key'); +javascript code }, +javascript blank +javascript code values: function() { +javascript code return this.pluck('value'); +javascript code }, +javascript blank +javascript code merge: function(hash) { +javascript code return $H(hash).inject($H(this), function(mergedHash, pair) { +javascript code mergedHash[pair.key] = pair.value; +javascript code return mergedHash; +javascript code }); +javascript code }, +javascript blank +javascript code toQueryString: function() { +javascript code return this.map(function(pair) { +javascript code return pair.map(encodeURIComponent).join('='); +javascript code }).join('&'); +javascript code }, +javascript blank +javascript code inspect: function() { +javascript code return '#'; +javascript code } +javascript code } +javascript blank +javascript code function $H(object) { +javascript code var hash = Object.extend({}, object || {}); +javascript code Object.extend(hash, Enumerable); +javascript code Object.extend(hash, Hash); +javascript code return hash; +javascript code } +javascript code ObjectRange = Class.create(); +javascript code Object.extend(ObjectRange.prototype, Enumerable); +javascript code Object.extend(ObjectRange.prototype, { +javascript code initialize: function(start, end, exclusive) { +javascript code this.start = start; +javascript code this.end = end; +javascript code this.exclusive = exclusive; +javascript code }, +javascript blank +javascript code _each: function(iterator) { +javascript code var value = this.start; +javascript code do { +javascript code iterator(value); +javascript code value = value.succ(); +javascript code } while (this.include(value)); +javascript code }, +javascript blank +javascript code include: function(value) { +javascript code if (value < this.start) +javascript code return false; +javascript code if (this.exclusive) +javascript code return value < this.end; +javascript code return value <= this.end; +javascript code } +javascript code }); +javascript blank +javascript code var $R = function(start, end, exclusive) { +javascript code return new ObjectRange(start, end, exclusive); +javascript code } +javascript blank +javascript code var Ajax = { +javascript code getTransport: function() { +javascript code return Try.these( +javascript code function() {return new ActiveXObject('Msxml2.XMLHTTP')}, +javascript code function() {return new ActiveXObject('Microsoft.XMLHTTP')}, +javascript code function() {return new XMLHttpRequest()} +javascript code ) || false; +javascript code }, +javascript blank +javascript code activeRequestCount: 0 +javascript code } +javascript blank +javascript code Ajax.Responders = { +javascript code responders: [], +javascript blank +javascript code _each: function(iterator) { +javascript code this.responders._each(iterator); +javascript code }, +javascript blank +javascript code register: function(responderToAdd) { +javascript code if (!this.include(responderToAdd)) +javascript code this.responders.push(responderToAdd); +javascript code }, +javascript blank +javascript code unregister: function(responderToRemove) { +javascript code this.responders = this.responders.without(responderToRemove); +javascript code }, +javascript blank +javascript code dispatch: function(callback, request, transport, json) { +javascript code this.each(function(responder) { +javascript code if (responder[callback] && typeof responder[callback] == 'function') { +javascript code try { +javascript code responder[callback].apply(responder, [request, transport, json]); +javascript code } catch (e) {} +javascript code } +javascript code }); +javascript code } +javascript code }; +javascript blank +javascript code Object.extend(Ajax.Responders, Enumerable); +javascript blank +javascript code Ajax.Responders.register({ +javascript code onCreate: function() { +javascript code Ajax.activeRequestCount++; +javascript code }, +javascript blank +javascript code onComplete: function() { +javascript code Ajax.activeRequestCount--; +javascript code } +javascript code }); +javascript blank +javascript code Ajax.Base = function() {}; +javascript code Ajax.Base.prototype = { +javascript code setOptions: function(options) { +javascript code this.options = { +javascript code method: 'post', +javascript code asynchronous: true, +javascript code parameters: '' +javascript code } +javascript code Object.extend(this.options, options || {}); +javascript code }, +javascript blank +javascript code responseIsSuccess: function() { +javascript code return this.transport.status == undefined +javascript code || this.transport.status == 0 +javascript code || (this.transport.status >= 200 && this.transport.status < 300); +javascript code }, +javascript blank +javascript code responseIsFailure: function() { +javascript code return !this.responseIsSuccess(); +javascript code } +javascript code } +javascript blank +javascript code Ajax.Request = Class.create(); +javascript code Ajax.Request.Events = +javascript code ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; +javascript blank +javascript code Ajax.Request.prototype = Object.extend(new Ajax.Base(), { +javascript code initialize: function(url, options) { +javascript code this.transport = Ajax.getTransport(); +javascript code this.setOptions(options); +javascript code this.request(url); +javascript code }, +javascript blank +javascript code request: function(url) { +javascript code var parameters = this.options.parameters || ''; +javascript code if (parameters.length > 0) parameters += '&_='; +javascript blank +javascript code try { +javascript code this.url = url; +javascript code if (this.options.method == 'get' && parameters.length > 0) +javascript code this.url += (this.url.match(/\?/) ? '&' : '?') + parameters; +javascript blank +javascript code Ajax.Responders.dispatch('onCreate', this, this.transport); +javascript blank +javascript code this.transport.open(this.options.method, this.url, +javascript code this.options.asynchronous); +javascript blank +javascript code if (this.options.asynchronous) { +javascript code this.transport.onreadystatechange = this.onStateChange.bind(this); +javascript code setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); +javascript code } +javascript blank +javascript code this.setRequestHeaders(); +javascript blank +javascript code var body = this.options.postBody ? this.options.postBody : parameters; +javascript code this.transport.send(this.options.method == 'post' ? body : null); +javascript blank +javascript code } catch (e) { +javascript code this.dispatchException(e); +javascript code } +javascript code }, +javascript blank +javascript code setRequestHeaders: function() { +javascript code var requestHeaders = +javascript code ['X-Requested-With', 'XMLHttpRequest', +javascript code 'X-Prototype-Version', Prototype.Version]; +javascript blank +javascript code if (this.options.method == 'post') { +javascript code requestHeaders.push('Content-type', +javascript code 'application/x-www-form-urlencoded'); +javascript blank +javascript comment /* Force "Connection: close" for Mozilla browsers to work around +javascript comment * a bug where XMLHttpReqeuest sends an incorrect Content-length +javascript comment * header. See Mozilla Bugzilla #246651. +javascript comment */ +javascript code if (this.transport.overrideMimeType) +javascript code requestHeaders.push('Connection', 'close'); +javascript code } +javascript blank +javascript code if (this.options.requestHeaders) +javascript code requestHeaders.push.apply(requestHeaders, this.options.requestHeaders); +javascript blank +javascript code for (var i = 0; i < requestHeaders.length; i += 2) +javascript code this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]); +javascript code }, +javascript blank +javascript code onStateChange: function() { +javascript code var readyState = this.transport.readyState; +javascript code if (readyState != 1) +javascript code this.respondToReadyState(this.transport.readyState); +javascript code }, +javascript blank +javascript code header: function(name) { +javascript code try { +javascript code return this.transport.getResponseHeader(name); +javascript code } catch (e) {} +javascript code }, +javascript blank +javascript code evalJSON: function() { +javascript code try { +javascript code return eval(this.header('X-JSON')); +javascript code } catch (e) {} +javascript code }, +javascript blank +javascript code evalResponse: function() { +javascript code try { +javascript code return eval(this.transport.responseText); +javascript code } catch (e) { +javascript code this.dispatchException(e); +javascript code } +javascript code }, +javascript blank +javascript code respondToReadyState: function(readyState) { +javascript code var event = Ajax.Request.Events[readyState]; +javascript code var transport = this.transport, json = this.evalJSON(); +javascript blank +javascript code if (event == 'Complete') { +javascript code try { +javascript code (this.options['on' + this.transport.status] +javascript code || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] +javascript code || Prototype.emptyFunction)(transport, json); +javascript code } catch (e) { +javascript code this.dispatchException(e); +javascript code } +javascript blank +javascript code if ((this.header('Content-type') || '').match(/^text\/javascript/i)) +javascript code this.evalResponse(); +javascript code } +javascript blank +javascript code try { +javascript code (this.options['on' + event] || Prototype.emptyFunction)(transport, json); +javascript code Ajax.Responders.dispatch('on' + event, this, transport, json); +javascript code } catch (e) { +javascript code this.dispatchException(e); +javascript code } +javascript blank +javascript comment /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ +javascript code if (event == 'Complete') +javascript code this.transport.onreadystatechange = Prototype.emptyFunction; +javascript code }, +javascript blank +javascript code dispatchException: function(exception) { +javascript code (this.options.onException || Prototype.emptyFunction)(this, exception); +javascript code Ajax.Responders.dispatch('onException', this, exception); +javascript code } +javascript code }); +javascript blank +javascript code Ajax.Updater = Class.create(); +javascript blank +javascript code Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { +javascript code initialize: function(container, url, options) { +javascript code this.containers = { +javascript code success: container.success ? $(container.success) : $(container), +javascript code failure: container.failure ? $(container.failure) : +javascript code (container.success ? null : $(container)) +javascript code } +javascript blank +javascript code this.transport = Ajax.getTransport(); +javascript code this.setOptions(options); +javascript blank +javascript code var onComplete = this.options.onComplete || Prototype.emptyFunction; +javascript code this.options.onComplete = (function(transport, object) { +javascript code this.updateContent(); +javascript code onComplete(transport, object); +javascript code }).bind(this); +javascript blank +javascript code this.request(url); +javascript code }, +javascript blank +javascript code updateContent: function() { +javascript code var receiver = this.responseIsSuccess() ? +javascript code this.containers.success : this.containers.failure; +javascript code var response = this.transport.responseText; +javascript blank +javascript code if (!this.options.evalScripts) +javascript code response = response.stripScripts(); +javascript blank +javascript code if (receiver) { +javascript code if (this.options.insertion) { +javascript code new this.options.insertion(receiver, response); +javascript code } else { +javascript code Element.update(receiver, response); +javascript code } +javascript code } +javascript blank +javascript code if (this.responseIsSuccess()) { +javascript code if (this.onComplete) +javascript code setTimeout(this.onComplete.bind(this), 10); +javascript code } +javascript code } +javascript code }); +javascript blank +javascript code Ajax.PeriodicalUpdater = Class.create(); +javascript code Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { +javascript code initialize: function(container, url, options) { +javascript code this.setOptions(options); +javascript code this.onComplete = this.options.onComplete; +javascript blank +javascript code this.frequency = (this.options.frequency || 2); +javascript code this.decay = (this.options.decay || 1); +javascript blank +javascript code this.updater = {}; +javascript code this.container = container; +javascript code this.url = url; +javascript blank +javascript code this.start(); +javascript code }, +javascript blank +javascript code start: function() { +javascript code this.options.onComplete = this.updateComplete.bind(this); +javascript code this.onTimerEvent(); +javascript code }, +javascript blank +javascript code stop: function() { +javascript code this.updater.onComplete = undefined; +javascript code clearTimeout(this.timer); +javascript code (this.onComplete || Prototype.emptyFunction).apply(this, arguments); +javascript code }, +javascript blank +javascript code updateComplete: function(request) { +javascript code if (this.options.decay) { +javascript code this.decay = (request.responseText == this.lastText ? +javascript code this.decay * this.options.decay : 1); +javascript blank +javascript code this.lastText = request.responseText; +javascript code } +javascript code this.timer = setTimeout(this.onTimerEvent.bind(this), +javascript code this.decay * this.frequency * 1000); +javascript code }, +javascript blank +javascript code onTimerEvent: function() { +javascript code this.updater = new Ajax.Updater(this.container, this.url, this.options); +javascript code } +javascript code }); +javascript code document.getElementsByClassName = function(className, parentElement) { +javascript code var children = ($(parentElement) || document.body).getElementsByTagName('*'); +javascript code return $A(children).inject([], function(elements, child) { +javascript code if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) +javascript code elements.push(child); +javascript code return elements; +javascript code }); +javascript code } +javascript blank +javascript comment /*--------------------------------------------------------------------------*/ +javascript blank +javascript code if (!window.Element) { +javascript code var Element = new Object(); +javascript code } +javascript blank +javascript code Object.extend(Element, { +javascript code visible: function(element) { +javascript code return $(element).style.display != 'none'; +javascript code }, +javascript blank +javascript code toggle: function() { +javascript code for (var i = 0; i < arguments.length; i++) { +javascript code var element = $(arguments[i]); +javascript code Element[Element.visible(element) ? 'hide' : 'show'](element); +javascript code } +javascript code }, +javascript blank +javascript code hide: function() { +javascript code for (var i = 0; i < arguments.length; i++) { +javascript code var element = $(arguments[i]); +javascript code element.style.display = 'none'; +javascript code } +javascript code }, +javascript blank +javascript code show: function() { +javascript code for (var i = 0; i < arguments.length; i++) { +javascript code var element = $(arguments[i]); +javascript code element.style.display = ''; +javascript code } +javascript code }, +javascript blank +javascript code remove: function(element) { +javascript code element = $(element); +javascript code element.parentNode.removeChild(element); +javascript code }, +javascript blank +javascript code update: function(element, html) { +javascript code $(element).innerHTML = html.stripScripts(); +javascript code setTimeout(function() {html.evalScripts()}, 10); +javascript code }, +javascript blank +javascript code getHeight: function(element) { +javascript code element = $(element); +javascript code return element.offsetHeight; +javascript code }, +javascript blank +javascript code classNames: function(element) { +javascript code return new Element.ClassNames(element); +javascript code }, +javascript blank +javascript code hasClassName: function(element, className) { +javascript code if (!(element = $(element))) return; +javascript code return Element.classNames(element).include(className); +javascript code }, +javascript blank +javascript code addClassName: function(element, className) { +javascript code if (!(element = $(element))) return; +javascript code return Element.classNames(element).add(className); +javascript code }, +javascript blank +javascript code removeClassName: function(element, className) { +javascript code if (!(element = $(element))) return; +javascript code return Element.classNames(element).remove(className); +javascript code }, +javascript blank +javascript comment // removes whitespace-only text node children +javascript code cleanWhitespace: function(element) { +javascript code element = $(element); +javascript code for (var i = 0; i < element.childNodes.length; i++) { +javascript code var node = element.childNodes[i]; +javascript code if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) +javascript code Element.remove(node); +javascript code } +javascript code }, +javascript blank +javascript code empty: function(element) { +javascript code return $(element).innerHTML.match(/^\s*$/); +javascript code }, +javascript blank +javascript code scrollTo: function(element) { +javascript code element = $(element); +javascript code var x = element.x ? element.x : element.offsetLeft, +javascript code y = element.y ? element.y : element.offsetTop; +javascript code window.scrollTo(x, y); +javascript code }, +javascript blank +javascript code getStyle: function(element, style) { +javascript code element = $(element); +javascript code var value = element.style[style.camelize()]; +javascript code if (!value) { +javascript code if (document.defaultView && document.defaultView.getComputedStyle) { +javascript code var css = document.defaultView.getComputedStyle(element, null); +javascript code value = css ? css.getPropertyValue(style) : null; +javascript code } else if (element.currentStyle) { +javascript code value = element.currentStyle[style.camelize()]; +javascript code } +javascript code } +javascript blank +javascript code if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) +javascript code if (Element.getStyle(element, 'position') == 'static') value = 'auto'; +javascript blank +javascript code return value == 'auto' ? null : value; +javascript code }, +javascript blank +javascript code setStyle: function(element, style) { +javascript code element = $(element); +javascript code for (name in style) +javascript code element.style[name.camelize()] = style[name]; +javascript code }, +javascript blank +javascript code getDimensions: function(element) { +javascript code element = $(element); +javascript code if (Element.getStyle(element, 'display') != 'none') +javascript code return {width: element.offsetWidth, height: element.offsetHeight}; +javascript blank +javascript comment // All *Width and *Height properties give 0 on elements with display none, +javascript comment // so enable the element temporarily +javascript code var els = element.style; +javascript code var originalVisibility = els.visibility; +javascript code var originalPosition = els.position; +javascript code els.visibility = 'hidden'; +javascript code els.position = 'absolute'; +javascript code els.display = ''; +javascript code var originalWidth = element.clientWidth; +javascript code var originalHeight = element.clientHeight; +javascript code els.display = 'none'; +javascript code els.position = originalPosition; +javascript code els.visibility = originalVisibility; +javascript code return {width: originalWidth, height: originalHeight}; +javascript code }, +javascript blank +javascript code makePositioned: function(element) { +javascript code element = $(element); +javascript code var pos = Element.getStyle(element, 'position'); +javascript code if (pos == 'static' || !pos) { +javascript code element._madePositioned = true; +javascript code element.style.position = 'relative'; +javascript comment // Opera returns the offset relative to the positioning context, when an +javascript comment // element is position relative but top and left have not been defined +javascript code if (window.opera) { +javascript code element.style.top = 0; +javascript code element.style.left = 0; +javascript code } +javascript code } +javascript code }, +javascript blank +javascript code undoPositioned: function(element) { +javascript code element = $(element); +javascript code if (element._madePositioned) { +javascript code element._madePositioned = undefined; +javascript code element.style.position = +javascript code element.style.top = +javascript code element.style.left = +javascript code element.style.bottom = +javascript code element.style.right = ''; +javascript code } +javascript code }, +javascript blank +javascript code makeClipping: function(element) { +javascript code element = $(element); +javascript code if (element._overflow) return; +javascript code element._overflow = element.style.overflow; +javascript code if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') +javascript code element.style.overflow = 'hidden'; +javascript code }, +javascript blank +javascript code undoClipping: function(element) { +javascript code element = $(element); +javascript code if (element._overflow) return; +javascript code element.style.overflow = element._overflow; +javascript code element._overflow = undefined; +javascript code } +javascript code }); +javascript blank +javascript code var Toggle = new Object(); +javascript code Toggle.display = Element.toggle; +javascript blank +javascript comment /*--------------------------------------------------------------------------*/ +javascript blank +javascript code Abstract.Insertion = function(adjacency) { +javascript code this.adjacency = adjacency; +javascript code } +javascript blank +javascript code Abstract.Insertion.prototype = { +javascript code initialize: function(element, content) { +javascript code this.element = $(element); +javascript code this.content = content.stripScripts(); +javascript blank +javascript code if (this.adjacency && this.element.insertAdjacentHTML) { +javascript code try { +javascript code this.element.insertAdjacentHTML(this.adjacency, this.content); +javascript code } catch (e) { +javascript code if (this.element.tagName.toLowerCase() == 'tbody') { +javascript code this.insertContent(this.contentFromAnonymousTable()); +javascript code } else { +javascript code throw e; +javascript code } +javascript code } +javascript code } else { +javascript code this.range = this.element.ownerDocument.createRange(); +javascript code if (this.initializeRange) this.initializeRange(); +javascript code this.insertContent([this.range.createContextualFragment(this.content)]); +javascript code } +javascript blank +javascript code setTimeout(function() {content.evalScripts()}, 10); +javascript code }, +javascript blank +javascript code contentFromAnonymousTable: function() { +javascript code var div = document.createElement('div'); +javascript code div.innerHTML = '' + this.content + '
'; +javascript code return $A(div.childNodes[0].childNodes[0].childNodes); +javascript code } +javascript code } +javascript blank +javascript code var Insertion = new Object(); +javascript blank +javascript code Insertion.Before = Class.create(); +javascript code Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { +javascript code initializeRange: function() { +javascript code this.range.setStartBefore(this.element); +javascript code }, +javascript blank +javascript code insertContent: function(fragments) { +javascript code fragments.each((function(fragment) { +javascript code this.element.parentNode.insertBefore(fragment, this.element); +javascript code }).bind(this)); +javascript code } +javascript code }); +javascript blank +javascript code Insertion.Top = Class.create(); +javascript code Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { +javascript code initializeRange: function() { +javascript code this.range.selectNodeContents(this.element); +javascript code this.range.collapse(true); +javascript code }, +javascript blank +javascript code insertContent: function(fragments) { +javascript code fragments.reverse(false).each((function(fragment) { +javascript code this.element.insertBefore(fragment, this.element.firstChild); +javascript code }).bind(this)); +javascript code } +javascript code }); +javascript blank +javascript code Insertion.Bottom = Class.create(); +javascript code Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { +javascript code initializeRange: function() { +javascript code this.range.selectNodeContents(this.element); +javascript code this.range.collapse(this.element); +javascript code }, +javascript blank +javascript code insertContent: function(fragments) { +javascript code fragments.each((function(fragment) { +javascript code this.element.appendChild(fragment); +javascript code }).bind(this)); +javascript code } +javascript code }); +javascript blank +javascript code Insertion.After = Class.create(); +javascript code Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { +javascript code initializeRange: function() { +javascript code this.range.setStartAfter(this.element); +javascript code }, +javascript blank +javascript code insertContent: function(fragments) { +javascript code fragments.each((function(fragment) { +javascript code this.element.parentNode.insertBefore(fragment, +javascript code this.element.nextSibling); +javascript code }).bind(this)); +javascript code } +javascript code }); +javascript blank +javascript comment /*--------------------------------------------------------------------------*/ +javascript blank +javascript code Element.ClassNames = Class.create(); +javascript code Element.ClassNames.prototype = { +javascript code initialize: function(element) { +javascript code this.element = $(element); +javascript code }, +javascript blank +javascript code _each: function(iterator) { +javascript code this.element.className.split(/\s+/).select(function(name) { +javascript code return name.length > 0; +javascript code })._each(iterator); +javascript code }, +javascript blank +javascript code set: function(className) { +javascript code this.element.className = className; +javascript code }, +javascript blank +javascript code add: function(classNameToAdd) { +javascript code if (this.include(classNameToAdd)) return; +javascript code this.set(this.toArray().concat(classNameToAdd).join(' ')); +javascript code }, +javascript blank +javascript code remove: function(classNameToRemove) { +javascript code if (!this.include(classNameToRemove)) return; +javascript code this.set(this.select(function(className) { +javascript code return className != classNameToRemove; +javascript code }).join(' ')); +javascript code }, +javascript blank +javascript code toString: function() { +javascript code return this.toArray().join(' '); +javascript code } +javascript code } +javascript blank +javascript code Object.extend(Element.ClassNames.prototype, Enumerable); +javascript code var Field = { +javascript code clear: function() { +javascript code for (var i = 0; i < arguments.length; i++) +javascript code $(arguments[i]).value = ''; +javascript code }, +javascript blank +javascript code focus: function(element) { +javascript code $(element).focus(); +javascript code }, +javascript blank +javascript code present: function() { +javascript code for (var i = 0; i < arguments.length; i++) +javascript code if ($(arguments[i]).value == '') return false; +javascript code return true; +javascript code }, +javascript blank +javascript code select: function(element) { +javascript code $(element).select(); +javascript code }, +javascript blank +javascript code activate: function(element) { +javascript code element = $(element); +javascript code element.focus(); +javascript code if (element.select) +javascript code element.select(); +javascript code } +javascript code } +javascript blank +javascript comment /*--------------------------------------------------------------------------*/ +javascript blank +javascript code var Form = { +javascript code serialize: function(form) { +javascript code var elements = Form.getElements($(form)); +javascript code var queryComponents = new Array(); +javascript blank +javascript code for (var i = 0; i < elements.length; i++) { +javascript code var queryComponent = Form.Element.serialize(elements[i]); +javascript code if (queryComponent) +javascript code queryComponents.push(queryComponent); +javascript code } +javascript blank +javascript code return queryComponents.join('&'); +javascript code }, +javascript blank +javascript code getElements: function(form) { +javascript code form = $(form); +javascript code var elements = new Array(); +javascript blank +javascript code for (tagName in Form.Element.Serializers) { +javascript code var tagElements = form.getElementsByTagName(tagName); +javascript code for (var j = 0; j < tagElements.length; j++) +javascript code elements.push(tagElements[j]); +javascript code } +javascript code return elements; +javascript code }, +javascript blank +javascript code getInputs: function(form, typeName, name) { +javascript code form = $(form); +javascript code var inputs = form.getElementsByTagName('input'); +javascript blank +javascript code if (!typeName && !name) +javascript code return inputs; +javascript blank +javascript code var matchingInputs = new Array(); +javascript code for (var i = 0; i < inputs.length; i++) { +javascript code var input = inputs[i]; +javascript code if ((typeName && input.type != typeName) || +javascript code (name && input.name != name)) +javascript code continue; +javascript code matchingInputs.push(input); +javascript code } +javascript blank +javascript code return matchingInputs; +javascript code }, +javascript blank +javascript code disable: function(form) { +javascript code var elements = Form.getElements(form); +javascript code for (var i = 0; i < elements.length; i++) { +javascript code var element = elements[i]; +javascript code element.blur(); +javascript code element.disabled = 'true'; +javascript code } +javascript code }, +javascript blank +javascript code enable: function(form) { +javascript code var elements = Form.getElements(form); +javascript code for (var i = 0; i < elements.length; i++) { +javascript code var element = elements[i]; +javascript code element.disabled = ''; +javascript code } +javascript code }, +javascript blank +javascript code findFirstElement: function(form) { +javascript code return Form.getElements(form).find(function(element) { +javascript code return element.type != 'hidden' && !element.disabled && +javascript code ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); +javascript code }); +javascript code }, +javascript blank +javascript code focusFirstElement: function(form) { +javascript code Field.activate(Form.findFirstElement(form)); +javascript code }, +javascript blank +javascript code reset: function(form) { +javascript code $(form).reset(); +javascript code } +javascript code } +javascript blank +javascript code Form.Element = { +javascript code serialize: function(element) { +javascript code element = $(element); +javascript code var method = element.tagName.toLowerCase(); +javascript code var parameter = Form.Element.Serializers[method](element); +javascript blank +javascript code if (parameter) { +javascript code var key = encodeURIComponent(parameter[0]); +javascript code if (key.length == 0) return; +javascript blank +javascript code if (parameter[1].constructor != Array) +javascript code parameter[1] = [parameter[1]]; +javascript blank +javascript code return parameter[1].map(function(value) { +javascript code return key + '=' + encodeURIComponent(value); +javascript code }).join('&'); +javascript code } +javascript code }, +javascript blank +javascript code getValue: function(element) { +javascript code element = $(element); +javascript code var method = element.tagName.toLowerCase(); +javascript code var parameter = Form.Element.Serializers[method](element); +javascript blank +javascript code if (parameter) +javascript code return parameter[1]; +javascript code } +javascript code } +javascript blank +javascript code Form.Element.Serializers = { +javascript code input: function(element) { +javascript code switch (element.type.toLowerCase()) { +javascript code case 'submit': +javascript code case 'hidden': +javascript code case 'password': +javascript code case 'text': +javascript code return Form.Element.Serializers.textarea(element); +javascript code case 'checkbox': +javascript code case 'radio': +javascript code return Form.Element.Serializers.inputSelector(element); +javascript code } +javascript code return false; +javascript code }, +javascript blank +javascript code inputSelector: function(element) { +javascript code if (element.checked) +javascript code return [element.name, element.value]; +javascript code }, +javascript blank +javascript code textarea: function(element) { +javascript code return [element.name, element.value]; +javascript code }, +javascript blank +javascript code select: function(element) { +javascript code return Form.Element.Serializers[element.type == 'select-one' ? +javascript code 'selectOne' : 'selectMany'](element); +javascript code }, +javascript blank +javascript code selectOne: function(element) { +javascript code var value = '', opt, index = element.selectedIndex; +javascript code if (index >= 0) { +javascript code opt = element.options[index]; +javascript code value = opt.value; +javascript code if (!value && !('value' in opt)) +javascript code value = opt.text; +javascript code } +javascript code return [element.name, value]; +javascript code }, +javascript blank +javascript code selectMany: function(element) { +javascript code var value = new Array(); +javascript code for (var i = 0; i < element.length; i++) { +javascript code var opt = element.options[i]; +javascript code if (opt.selected) { +javascript code var optValue = opt.value; +javascript code if (!optValue && !('value' in opt)) +javascript code optValue = opt.text; +javascript code value.push(optValue); +javascript code } +javascript code } +javascript code return [element.name, value]; +javascript code } +javascript code } +javascript blank +javascript comment /*--------------------------------------------------------------------------*/ +javascript blank +javascript code var $F = Form.Element.getValue; +javascript blank +javascript comment /*--------------------------------------------------------------------------*/ +javascript blank +javascript code Abstract.TimedObserver = function() {} +javascript code Abstract.TimedObserver.prototype = { +javascript code initialize: function(element, frequency, callback) { +javascript code this.frequency = frequency; +javascript code this.element = $(element); +javascript code this.callback = callback; +javascript blank +javascript code this.lastValue = this.getValue(); +javascript code this.registerCallback(); +javascript code }, +javascript blank +javascript code registerCallback: function() { +javascript code setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); +javascript code }, +javascript blank +javascript code onTimerEvent: function() { +javascript code var value = this.getValue(); +javascript code if (this.lastValue != value) { +javascript code this.callback(this.element, value); +javascript code this.lastValue = value; +javascript code } +javascript code } +javascript code } +javascript blank +javascript code Form.Element.Observer = Class.create(); +javascript code Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { +javascript code getValue: function() { +javascript code return Form.Element.getValue(this.element); +javascript code } +javascript code }); +javascript blank +javascript code Form.Observer = Class.create(); +javascript code Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { +javascript code getValue: function() { +javascript code return Form.serialize(this.element); +javascript code } +javascript code }); +javascript blank +javascript comment /*--------------------------------------------------------------------------*/ +javascript blank +javascript code Abstract.EventObserver = function() {} +javascript code Abstract.EventObserver.prototype = { +javascript code initialize: function(element, callback) { +javascript code this.element = $(element); +javascript code this.callback = callback; +javascript blank +javascript code this.lastValue = this.getValue(); +javascript code if (this.element.tagName.toLowerCase() == 'form') +javascript code this.registerFormCallbacks(); +javascript code else +javascript code this.registerCallback(this.element); +javascript code }, +javascript blank +javascript code onElementEvent: function() { +javascript code var value = this.getValue(); +javascript code if (this.lastValue != value) { +javascript code this.callback(this.element, value); +javascript code this.lastValue = value; +javascript code } +javascript code }, +javascript blank +javascript code registerFormCallbacks: function() { +javascript code var elements = Form.getElements(this.element); +javascript code for (var i = 0; i < elements.length; i++) +javascript code this.registerCallback(elements[i]); +javascript code }, +javascript blank +javascript code registerCallback: function(element) { +javascript code if (element.type) { +javascript code switch (element.type.toLowerCase()) { +javascript code case 'checkbox': +javascript code case 'radio': +javascript code Event.observe(element, 'click', this.onElementEvent.bind(this)); +javascript code break; +javascript code case 'password': +javascript code case 'text': +javascript code case 'textarea': +javascript code case 'select-one': +javascript code case 'select-multiple': +javascript code Event.observe(element, 'change', this.onElementEvent.bind(this)); +javascript code break; +javascript code } +javascript code } +javascript code } +javascript code } +javascript blank +javascript code Form.Element.EventObserver = Class.create(); +javascript code Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { +javascript code getValue: function() { +javascript code return Form.Element.getValue(this.element); +javascript code } +javascript code }); +javascript blank +javascript code Form.EventObserver = Class.create(); +javascript code Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { +javascript code getValue: function() { +javascript code return Form.serialize(this.element); +javascript code } +javascript code }); +javascript code if (!window.Event) { +javascript code var Event = new Object(); +javascript code } +javascript blank +javascript code Object.extend(Event, { +javascript code KEY_BACKSPACE: 8, +javascript code KEY_TAB: 9, +javascript code KEY_RETURN: 13, +javascript code KEY_ESC: 27, +javascript code KEY_LEFT: 37, +javascript code KEY_UP: 38, +javascript code KEY_RIGHT: 39, +javascript code KEY_DOWN: 40, +javascript code KEY_DELETE: 46, +javascript blank +javascript code element: function(event) { +javascript code return event.target || event.srcElement; +javascript code }, +javascript blank +javascript code isLeftClick: function(event) { +javascript code return (((event.which) && (event.which == 1)) || +javascript code ((event.button) && (event.button == 1))); +javascript code }, +javascript blank +javascript code pointerX: function(event) { +javascript code return event.pageX || (event.clientX + +javascript code (document.documentElement.scrollLeft || document.body.scrollLeft)); +javascript code }, +javascript blank +javascript code pointerY: function(event) { +javascript code return event.pageY || (event.clientY + +javascript code (document.documentElement.scrollTop || document.body.scrollTop)); +javascript code }, +javascript blank +javascript code stop: function(event) { +javascript code if (event.preventDefault) { +javascript code event.preventDefault(); +javascript code event.stopPropagation(); +javascript code } else { +javascript code event.returnValue = false; +javascript code event.cancelBubble = true; +javascript code } +javascript code }, +javascript blank +javascript comment // find the first node with the given tagName, starting from the +javascript comment // node the event was triggered on; traverses the DOM upwards +javascript code findElement: function(event, tagName) { +javascript code var element = Event.element(event); +javascript code while (element.parentNode && (!element.tagName || +javascript code (element.tagName.toUpperCase() != tagName.toUpperCase()))) +javascript code element = element.parentNode; +javascript code return element; +javascript code }, +javascript blank +javascript code observers: false, +javascript blank +javascript code _observeAndCache: function(element, name, observer, useCapture) { +javascript code if (!this.observers) this.observers = []; +javascript code if (element.addEventListener) { +javascript code this.observers.push([element, name, observer, useCapture]); +javascript code element.addEventListener(name, observer, useCapture); +javascript code } else if (element.attachEvent) { +javascript code this.observers.push([element, name, observer, useCapture]); +javascript code element.attachEvent('on' + name, observer); +javascript code } +javascript code }, +javascript blank +javascript code unloadCache: function() { +javascript code if (!Event.observers) return; +javascript code for (var i = 0; i < Event.observers.length; i++) { +javascript code Event.stopObserving.apply(this, Event.observers[i]); +javascript code Event.observers[i][0] = null; +javascript code } +javascript code Event.observers = false; +javascript code }, +javascript blank +javascript code observe: function(element, name, observer, useCapture) { +javascript code var element = $(element); +javascript code useCapture = useCapture || false; +javascript blank +javascript code if (name == 'keypress' && +javascript code (navigator.appVersion.match(/Konqueror|Safari|KHTML/) +javascript code || element.attachEvent)) +javascript code name = 'keydown'; +javascript blank +javascript code this._observeAndCache(element, name, observer, useCapture); +javascript code }, +javascript blank +javascript code stopObserving: function(element, name, observer, useCapture) { +javascript code var element = $(element); +javascript code useCapture = useCapture || false; +javascript blank +javascript code if (name == 'keypress' && +javascript code (navigator.appVersion.match(/Konqueror|Safari|KHTML/) +javascript code || element.detachEvent)) +javascript code name = 'keydown'; +javascript blank +javascript code if (element.removeEventListener) { +javascript code element.removeEventListener(name, observer, useCapture); +javascript code } else if (element.detachEvent) { +javascript code element.detachEvent('on' + name, observer); +javascript code } +javascript code } +javascript code }); +javascript blank +javascript comment /* prevent memory leaks in IE */ +javascript code Event.observe(window, 'unload', Event.unloadCache, false); +javascript code var Position = { +javascript comment // set to true if needed, warning: firefox performance problems +javascript comment // NOT neeeded for page scrolling, only if draggable contained in +javascript comment // scrollable elements +javascript code includeScrollOffsets: false, +javascript blank +javascript comment // must be called before calling withinIncludingScrolloffset, every time the +javascript comment // page is scrolled +javascript code prepare: function() { +javascript code this.deltaX = window.pageXOffset +javascript code || document.documentElement.scrollLeft +javascript code || document.body.scrollLeft +javascript code || 0; +javascript code this.deltaY = window.pageYOffset +javascript code || document.documentElement.scrollTop +javascript code || document.body.scrollTop +javascript code || 0; +javascript code }, +javascript blank +javascript code realOffset: function(element) { +javascript code var valueT = 0, valueL = 0; +javascript code do { +javascript code valueT += element.scrollTop || 0; +javascript code valueL += element.scrollLeft || 0; +javascript code element = element.parentNode; +javascript code } while (element); +javascript code return [valueL, valueT]; +javascript code }, +javascript blank +javascript code cumulativeOffset: function(element) { +javascript code var valueT = 0, valueL = 0; +javascript code do { +javascript code valueT += element.offsetTop || 0; +javascript code valueL += element.offsetLeft || 0; +javascript code element = element.offsetParent; +javascript code } while (element); +javascript code return [valueL, valueT]; +javascript code }, +javascript blank +javascript code positionedOffset: function(element) { +javascript code var valueT = 0, valueL = 0; +javascript code do { +javascript code valueT += element.offsetTop || 0; +javascript code valueL += element.offsetLeft || 0; +javascript code element = element.offsetParent; +javascript code if (element) { +javascript code p = Element.getStyle(element, 'position'); +javascript code if (p == 'relative' || p == 'absolute') break; +javascript code } +javascript code } while (element); +javascript code return [valueL, valueT]; +javascript code }, +javascript blank +javascript code offsetParent: function(element) { +javascript code if (element.offsetParent) return element.offsetParent; +javascript code if (element == document.body) return element; +javascript blank +javascript code while ((element = element.parentNode) && element != document.body) +javascript code if (Element.getStyle(element, 'position') != 'static') +javascript code return element; +javascript blank +javascript code return document.body; +javascript code }, +javascript blank +javascript comment // caches x/y coordinate pair to use with overlap +javascript code within: function(element, x, y) { +javascript code if (this.includeScrollOffsets) +javascript code return this.withinIncludingScrolloffsets(element, x, y); +javascript code this.xcomp = x; +javascript code this.ycomp = y; +javascript code this.offset = this.cumulativeOffset(element); +javascript blank +javascript code return (y >= this.offset[1] && +javascript code y < this.offset[1] + element.offsetHeight && +javascript code x >= this.offset[0] && +javascript code x < this.offset[0] + element.offsetWidth); +javascript code }, +javascript blank +javascript code withinIncludingScrolloffsets: function(element, x, y) { +javascript code var offsetcache = this.realOffset(element); +javascript blank +javascript code this.xcomp = x + offsetcache[0] - this.deltaX; +javascript code this.ycomp = y + offsetcache[1] - this.deltaY; +javascript code this.offset = this.cumulativeOffset(element); +javascript blank +javascript code return (this.ycomp >= this.offset[1] && +javascript code this.ycomp < this.offset[1] + element.offsetHeight && +javascript code this.xcomp >= this.offset[0] && +javascript code this.xcomp < this.offset[0] + element.offsetWidth); +javascript code }, +javascript blank +javascript comment // within must be called directly before +javascript code overlap: function(mode, element) { +javascript code if (!mode) return 0; +javascript code if (mode == 'vertical') +javascript code return ((this.offset[1] + element.offsetHeight) - this.ycomp) / +javascript code element.offsetHeight; +javascript code if (mode == 'horizontal') +javascript code return ((this.offset[0] + element.offsetWidth) - this.xcomp) / +javascript code element.offsetWidth; +javascript code }, +javascript blank +javascript code clone: function(source, target) { +javascript code source = $(source); +javascript code target = $(target); +javascript code target.style.position = 'absolute'; +javascript code var offsets = this.cumulativeOffset(source); +javascript code target.style.top = offsets[1] + 'px'; +javascript code target.style.left = offsets[0] + 'px'; +javascript code target.style.width = source.offsetWidth + 'px'; +javascript code target.style.height = source.offsetHeight + 'px'; +javascript code }, +javascript blank +javascript code page: function(forElement) { +javascript code var valueT = 0, valueL = 0; +javascript blank +javascript code var element = forElement; +javascript code do { +javascript code valueT += element.offsetTop || 0; +javascript code valueL += element.offsetLeft || 0; +javascript blank +javascript comment // Safari fix +javascript code if (element.offsetParent==document.body) +javascript code if (Element.getStyle(element,'position')=='absolute') break; +javascript blank +javascript code } while (element = element.offsetParent); +javascript blank +javascript code element = forElement; +javascript code do { +javascript code valueT -= element.scrollTop || 0; +javascript code valueL -= element.scrollLeft || 0; +javascript code } while (element = element.parentNode); +javascript blank +javascript code return [valueL, valueT]; +javascript code }, +javascript blank +javascript code clone: function(source, target) { +javascript code var options = Object.extend({ +javascript code setLeft: true, +javascript code setTop: true, +javascript code setWidth: true, +javascript code setHeight: true, +javascript code offsetTop: 0, +javascript code offsetLeft: 0 +javascript code }, arguments[2] || {}) +javascript blank +javascript comment // find page position of source +javascript code source = $(source); +javascript code var p = Position.page(source); +javascript blank +javascript comment // find coordinate system to use +javascript code target = $(target); +javascript code var delta = [0, 0]; +javascript code var parent = null; +javascript comment // delta [0,0] will do fine with position: fixed elements, +javascript comment // position:absolute needs offsetParent deltas +javascript code if (Element.getStyle(target,'position') == 'absolute') { +javascript code parent = Position.offsetParent(target); +javascript code delta = Position.page(parent); +javascript code } +javascript blank +javascript comment // correct by body offsets (fixes Safari) +javascript code if (parent == document.body) { +javascript code delta[0] -= document.body.offsetLeft; +javascript code delta[1] -= document.body.offsetTop; +javascript code } +javascript blank +javascript comment // set position +javascript code if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; +javascript code if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; +javascript code if(options.setWidth) target.style.width = source.offsetWidth + 'px'; +javascript code if(options.setHeight) target.style.height = source.offsetHeight + 'px'; +javascript code }, +javascript blank +javascript code absolutize: function(element) { +javascript code element = $(element); +javascript code if (element.style.position == 'absolute') return; +javascript code Position.prepare(); +javascript blank +javascript code var offsets = Position.positionedOffset(element); +javascript code var top = offsets[1]; +javascript code var left = offsets[0]; +javascript code var width = element.clientWidth; +javascript code var height = element.clientHeight; +javascript blank +javascript code element._originalLeft = left - parseFloat(element.style.left || 0); +javascript code element._originalTop = top - parseFloat(element.style.top || 0); +javascript code element._originalWidth = element.style.width; +javascript code element._originalHeight = element.style.height; +javascript blank +javascript code element.style.position = 'absolute'; +javascript code element.style.top = top + 'px';; +javascript code element.style.left = left + 'px';; +javascript code element.style.width = width + 'px';; +javascript code element.style.height = height + 'px';; +javascript code }, +javascript blank +javascript code relativize: function(element) { +javascript code element = $(element); +javascript code if (element.style.position == 'relative') return; +javascript code Position.prepare(); +javascript blank +javascript code element.style.position = 'relative'; +javascript code var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); +javascript code var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); +javascript blank +javascript code element.style.top = top + 'px'; +javascript code element.style.left = left + 'px'; +javascript code element.style.height = element._originalHeight; +javascript code element.style.width = element._originalWidth; +javascript code } +javascript code } +javascript blank +javascript comment // Safari returns margins on body which is incorrect if the child is absolutely +javascript comment // positioned. For performance reasons, redefine Position.cumulativeOffset for +javascript comment // KHTML/WebKit only. +javascript code if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { +javascript code Position.cumulativeOffset = function(element) { +javascript code var valueT = 0, valueL = 0; +javascript code do { +javascript code valueT += element.offsetTop || 0; +javascript code valueL += element.offsetLeft || 0; +javascript code if (element.offsetParent == document.body) +javascript code if (Element.getStyle(element, 'position') == 'absolute') break; +javascript blank +javascript code element = element.offsetParent; +javascript code } while (element); +javascript blank +javascript code return [valueL, valueT]; +javascript code } +javascript code } diff --git a/test/expected_dir/js1.js/javascript/code b/test/expected_dir/js1.js/javascript/code deleted file mode 100644 index 134332a..0000000 --- a/test/expected_dir/js1.js/javascript/code +++ /dev/null @@ -1,1446 +0,0 @@ -var Prototype = { -Version: '1.4.0', -ScriptFragment: '(?:)((\n|\r|.)*?)(?:<\/script>)', -emptyFunction: function() {}, -K: function(x) {return x} -} -var Class = { -create: function() { -return function() { -this.initialize.apply(this, arguments); -} -} -} -var Abstract = new Object(); -Object.extend = function(destination, source) { -for (property in source) { -destination[property] = source[property]; -} -return destination; -} -Object.inspect = function(object) { -try { -if (object == undefined) return 'undefined'; -if (object == null) return 'null'; -return object.inspect ? object.inspect() : object.toString(); -} catch (e) { -if (e instanceof RangeError) return '...'; -throw e; -} -} -Function.prototype.bind = function() { -var __method = this, args = $A(arguments), object = args.shift(); -return function() { -return __method.apply(object, args.concat($A(arguments))); -} -} -Function.prototype.bindAsEventListener = function(object) { -var __method = this; -return function(event) { -return __method.call(object, event || window.event); -} -} -Object.extend(Number.prototype, { -toColorPart: function() { -var digits = this.toString(16); -if (this < 16) return '0' + digits; -return digits; -}, -succ: function() { -return this + 1; -}, -times: function(iterator) { -$R(0, this, true).each(iterator); -return this; -} -}); -var Try = { -these: function() { -var returnValue; -for (var i = 0; i < arguments.length; i++) { -var lambda = arguments[i]; -try { -returnValue = lambda(); -break; -} catch (e) {} -} -return returnValue; -} -} -var PeriodicalExecuter = Class.create(); -PeriodicalExecuter.prototype = { -initialize: function(callback, frequency) { -this.callback = callback; -this.frequency = frequency; -this.currentlyExecuting = false; -this.registerCallback(); -}, -registerCallback: function() { -setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); -}, -onTimerEvent: function() { -if (!this.currentlyExecuting) { -try { -this.currentlyExecuting = true; -this.callback(); -} finally { -this.currentlyExecuting = false; -} -} -} -} -function $() { -var elements = new Array(); -for (var i = 0; i < arguments.length; i++) { -var element = arguments[i]; -if (typeof element == 'string') -element = document.getElementById(element); -if (arguments.length == 1) -return element; -elements.push(element); -} -return elements; -} -Object.extend(String.prototype, { -stripTags: function() { -return this.replace(/<\/?[^>]+>/gi, ''); -}, -stripScripts: function() { -return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); -}, -extractScripts: function() { -var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); -var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); -return (this.match(matchAll) || []).map(function(scriptTag) { -return (scriptTag.match(matchOne) || ['', ''])[1]; -}); -}, -evalScripts: function() { -return this.extractScripts().map(eval); -}, -escapeHTML: function() { -var div = document.createElement('div'); -var text = document.createTextNode(this); -div.appendChild(text); -return div.innerHTML; -}, -unescapeHTML: function() { -var div = document.createElement('div'); -div.innerHTML = this.stripTags(); -return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; -}, -toQueryParams: function() { -var pairs = this.match(/^\??(.*)$/)[1].split('&'); -return pairs.inject({}, function(params, pairString) { -var pair = pairString.split('='); -params[pair[0]] = pair[1]; -return params; -}); -}, -toArray: function() { -return this.split(''); -}, -camelize: function() { -var oStringList = this.split('-'); -if (oStringList.length == 1) return oStringList[0]; -var camelizedString = this.indexOf('-') == 0 -? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) -: oStringList[0]; -for (var i = 1, len = oStringList.length; i < len; i++) { -var s = oStringList[i]; -camelizedString += s.charAt(0).toUpperCase() + s.substring(1); -} -return camelizedString; -}, -inspect: function() { -return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'"; -} -}); -String.prototype.parseQuery = String.prototype.toQueryParams; -var $break = new Object(); -var $continue = new Object(); -var Enumerable = { -each: function(iterator) { -var index = 0; -try { -this._each(function(value) { -try { -iterator(value, index++); -} catch (e) { -if (e != $continue) throw e; -} -}); -} catch (e) { -if (e != $break) throw e; -} -}, -all: function(iterator) { -var result = true; -this.each(function(value, index) { -result = result && !!(iterator || Prototype.K)(value, index); -if (!result) throw $break; -}); -return result; -}, -any: function(iterator) { -var result = true; -this.each(function(value, index) { -if (result = !!(iterator || Prototype.K)(value, index)) -throw $break; -}); -return result; -}, -collect: function(iterator) { -var results = []; -this.each(function(value, index) { -results.push(iterator(value, index)); -}); -return results; -}, -detect: function (iterator) { -var result; -this.each(function(value, index) { -if (iterator(value, index)) { -result = value; -throw $break; -} -}); -return result; -}, -findAll: function(iterator) { -var results = []; -this.each(function(value, index) { -if (iterator(value, index)) -results.push(value); -}); -return results; -}, -grep: function(pattern, iterator) { -var results = []; -this.each(function(value, index) { -var stringValue = value.toString(); -if (stringValue.match(pattern)) -results.push((iterator || Prototype.K)(value, index)); -}) -return results; -}, -include: function(object) { -var found = false; -this.each(function(value) { -if (value == object) { -found = true; -throw $break; -} -}); -return found; -}, -inject: function(memo, iterator) { -this.each(function(value, index) { -memo = iterator(memo, value, index); -}); -return memo; -}, -invoke: function(method) { -var args = $A(arguments).slice(1); -return this.collect(function(value) { -return value[method].apply(value, args); -}); -}, -max: function(iterator) { -var result; -this.each(function(value, index) { -value = (iterator || Prototype.K)(value, index); -if (value >= (result || value)) -result = value; -}); -return result; -}, -min: function(iterator) { -var result; -this.each(function(value, index) { -value = (iterator || Prototype.K)(value, index); -if (value <= (result || value)) -result = value; -}); -return result; -}, -partition: function(iterator) { -var trues = [], falses = []; -this.each(function(value, index) { -((iterator || Prototype.K)(value, index) ? -trues : falses).push(value); -}); -return [trues, falses]; -}, -pluck: function(property) { -var results = []; -this.each(function(value, index) { -results.push(value[property]); -}); -return results; -}, -reject: function(iterator) { -var results = []; -this.each(function(value, index) { -if (!iterator(value, index)) -results.push(value); -}); -return results; -}, -sortBy: function(iterator) { -return this.collect(function(value, index) { -return {value: value, criteria: iterator(value, index)}; -}).sort(function(left, right) { -var a = left.criteria, b = right.criteria; -return a < b ? -1 : a > b ? 1 : 0; -}).pluck('value'); -}, -toArray: function() { -return this.collect(Prototype.K); -}, -zip: function() { -var iterator = Prototype.K, args = $A(arguments); -if (typeof args.last() == 'function') -iterator = args.pop(); -var collections = [this].concat(args).map($A); -return this.map(function(value, index) { -iterator(value = collections.pluck(index)); -return value; -}); -}, -inspect: function() { -return '#'; -} -} -Object.extend(Enumerable, { -map: Enumerable.collect, -find: Enumerable.detect, -select: Enumerable.findAll, -member: Enumerable.include, -entries: Enumerable.toArray -}); -var $A = Array.from = function(iterable) { -if (!iterable) return []; -if (iterable.toArray) { -return iterable.toArray(); -} else { -var results = []; -for (var i = 0; i < iterable.length; i++) -results.push(iterable[i]); -return results; -} -} -Object.extend(Array.prototype, Enumerable); -Array.prototype._reverse = Array.prototype.reverse; -Object.extend(Array.prototype, { -_each: function(iterator) { -for (var i = 0; i < this.length; i++) -iterator(this[i]); -}, -clear: function() { -this.length = 0; -return this; -}, -first: function() { -return this[0]; -}, -last: function() { -return this[this.length - 1]; -}, -compact: function() { -return this.select(function(value) { -return value != undefined || value != null; -}); -}, -flatten: function() { -return this.inject([], function(array, value) { -return array.concat(value.constructor == Array ? -value.flatten() : [value]); -}); -}, -without: function() { -var values = $A(arguments); -return this.select(function(value) { -return !values.include(value); -}); -}, -indexOf: function(object) { -for (var i = 0; i < this.length; i++) -if (this[i] == object) return i; -return -1; -}, -reverse: function(inline) { -return (inline !== false ? this : this.toArray())._reverse(); -}, -shift: function() { -var result = this[0]; -for (var i = 0; i < this.length - 1; i++) -this[i] = this[i + 1]; -this.length--; -return result; -}, -inspect: function() { -return '[' + this.map(Object.inspect).join(', ') + ']'; -} -}); -var Hash = { -_each: function(iterator) { -for (key in this) { -var value = this[key]; -if (typeof value == 'function') continue; -var pair = [key, value]; -pair.key = key; -pair.value = value; -iterator(pair); -} -}, -keys: function() { -return this.pluck('key'); -}, -values: function() { -return this.pluck('value'); -}, -merge: function(hash) { -return $H(hash).inject($H(this), function(mergedHash, pair) { -mergedHash[pair.key] = pair.value; -return mergedHash; -}); -}, -toQueryString: function() { -return this.map(function(pair) { -return pair.map(encodeURIComponent).join('='); -}).join('&'); -}, -inspect: function() { -return '#'; -} -} -function $H(object) { -var hash = Object.extend({}, object || {}); -Object.extend(hash, Enumerable); -Object.extend(hash, Hash); -return hash; -} -ObjectRange = Class.create(); -Object.extend(ObjectRange.prototype, Enumerable); -Object.extend(ObjectRange.prototype, { -initialize: function(start, end, exclusive) { -this.start = start; -this.end = end; -this.exclusive = exclusive; -}, -_each: function(iterator) { -var value = this.start; -do { -iterator(value); -value = value.succ(); -} while (this.include(value)); -}, -include: function(value) { -if (value < this.start) -return false; -if (this.exclusive) -return value < this.end; -return value <= this.end; -} -}); -var $R = function(start, end, exclusive) { -return new ObjectRange(start, end, exclusive); -} -var Ajax = { -getTransport: function() { -return Try.these( -function() {return new ActiveXObject('Msxml2.XMLHTTP')}, -function() {return new ActiveXObject('Microsoft.XMLHTTP')}, -function() {return new XMLHttpRequest()} -) || false; -}, -activeRequestCount: 0 -} -Ajax.Responders = { -responders: [], -_each: function(iterator) { -this.responders._each(iterator); -}, -register: function(responderToAdd) { -if (!this.include(responderToAdd)) -this.responders.push(responderToAdd); -}, -unregister: function(responderToRemove) { -this.responders = this.responders.without(responderToRemove); -}, -dispatch: function(callback, request, transport, json) { -this.each(function(responder) { -if (responder[callback] && typeof responder[callback] == 'function') { -try { -responder[callback].apply(responder, [request, transport, json]); -} catch (e) {} -} -}); -} -}; -Object.extend(Ajax.Responders, Enumerable); -Ajax.Responders.register({ -onCreate: function() { -Ajax.activeRequestCount++; -}, -onComplete: function() { -Ajax.activeRequestCount--; -} -}); -Ajax.Base = function() {}; -Ajax.Base.prototype = { -setOptions: function(options) { -this.options = { -method: 'post', -asynchronous: true, -parameters: '' -} -Object.extend(this.options, options || {}); -}, -responseIsSuccess: function() { -return this.transport.status == undefined -|| this.transport.status == 0 -|| (this.transport.status >= 200 && this.transport.status < 300); -}, -responseIsFailure: function() { -return !this.responseIsSuccess(); -} -} -Ajax.Request = Class.create(); -Ajax.Request.Events = -['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; -Ajax.Request.prototype = Object.extend(new Ajax.Base(), { -initialize: function(url, options) { -this.transport = Ajax.getTransport(); -this.setOptions(options); -this.request(url); -}, -request: function(url) { -var parameters = this.options.parameters || ''; -if (parameters.length > 0) parameters += '&_='; -try { -this.url = url; -if (this.options.method == 'get' && parameters.length > 0) -this.url += (this.url.match(/\?/) ? '&' : '?') + parameters; -Ajax.Responders.dispatch('onCreate', this, this.transport); -this.transport.open(this.options.method, this.url, -this.options.asynchronous); -if (this.options.asynchronous) { -this.transport.onreadystatechange = this.onStateChange.bind(this); -setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); -} -this.setRequestHeaders(); -var body = this.options.postBody ? this.options.postBody : parameters; -this.transport.send(this.options.method == 'post' ? body : null); -} catch (e) { -this.dispatchException(e); -} -}, -setRequestHeaders: function() { -var requestHeaders = -['X-Requested-With', 'XMLHttpRequest', -'X-Prototype-Version', Prototype.Version]; -if (this.options.method == 'post') { -requestHeaders.push('Content-type', -'application/x-www-form-urlencoded'); -if (this.transport.overrideMimeType) -requestHeaders.push('Connection', 'close'); -} -if (this.options.requestHeaders) -requestHeaders.push.apply(requestHeaders, this.options.requestHeaders); -for (var i = 0; i < requestHeaders.length; i += 2) -this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]); -}, -onStateChange: function() { -var readyState = this.transport.readyState; -if (readyState != 1) -this.respondToReadyState(this.transport.readyState); -}, -header: function(name) { -try { -return this.transport.getResponseHeader(name); -} catch (e) {} -}, -evalJSON: function() { -try { -return eval(this.header('X-JSON')); -} catch (e) {} -}, -evalResponse: function() { -try { -return eval(this.transport.responseText); -} catch (e) { -this.dispatchException(e); -} -}, -respondToReadyState: function(readyState) { -var event = Ajax.Request.Events[readyState]; -var transport = this.transport, json = this.evalJSON(); -if (event == 'Complete') { -try { -(this.options['on' + this.transport.status] -|| this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] -|| Prototype.emptyFunction)(transport, json); -} catch (e) { -this.dispatchException(e); -} -if ((this.header('Content-type') || '').match(/^text\/javascript/i)) -this.evalResponse(); -} -try { -(this.options['on' + event] || Prototype.emptyFunction)(transport, json); -Ajax.Responders.dispatch('on' + event, this, transport, json); -} catch (e) { -this.dispatchException(e); -} -if (event == 'Complete') -this.transport.onreadystatechange = Prototype.emptyFunction; -}, -dispatchException: function(exception) { -(this.options.onException || Prototype.emptyFunction)(this, exception); -Ajax.Responders.dispatch('onException', this, exception); -} -}); -Ajax.Updater = Class.create(); -Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { -initialize: function(container, url, options) { -this.containers = { -success: container.success ? $(container.success) : $(container), -failure: container.failure ? $(container.failure) : -(container.success ? null : $(container)) -} -this.transport = Ajax.getTransport(); -this.setOptions(options); -var onComplete = this.options.onComplete || Prototype.emptyFunction; -this.options.onComplete = (function(transport, object) { -this.updateContent(); -onComplete(transport, object); -}).bind(this); -this.request(url); -}, -updateContent: function() { -var receiver = this.responseIsSuccess() ? -this.containers.success : this.containers.failure; -var response = this.transport.responseText; -if (!this.options.evalScripts) -response = response.stripScripts(); -if (receiver) { -if (this.options.insertion) { -new this.options.insertion(receiver, response); -} else { -Element.update(receiver, response); -} -} -if (this.responseIsSuccess()) { -if (this.onComplete) -setTimeout(this.onComplete.bind(this), 10); -} -} -}); -Ajax.PeriodicalUpdater = Class.create(); -Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { -initialize: function(container, url, options) { -this.setOptions(options); -this.onComplete = this.options.onComplete; -this.frequency = (this.options.frequency || 2); -this.decay = (this.options.decay || 1); -this.updater = {}; -this.container = container; -this.url = url; -this.start(); -}, -start: function() { -this.options.onComplete = this.updateComplete.bind(this); -this.onTimerEvent(); -}, -stop: function() { -this.updater.onComplete = undefined; -clearTimeout(this.timer); -(this.onComplete || Prototype.emptyFunction).apply(this, arguments); -}, -updateComplete: function(request) { -if (this.options.decay) { -this.decay = (request.responseText == this.lastText ? -this.decay * this.options.decay : 1); -this.lastText = request.responseText; -} -this.timer = setTimeout(this.onTimerEvent.bind(this), -this.decay * this.frequency * 1000); -}, -onTimerEvent: function() { -this.updater = new Ajax.Updater(this.container, this.url, this.options); -} -}); -document.getElementsByClassName = function(className, parentElement) { -var children = ($(parentElement) || document.body).getElementsByTagName('*'); -return $A(children).inject([], function(elements, child) { -if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) -elements.push(child); -return elements; -}); -} -if (!window.Element) { -var Element = new Object(); -} -Object.extend(Element, { -visible: function(element) { -return $(element).style.display != 'none'; -}, -toggle: function() { -for (var i = 0; i < arguments.length; i++) { -var element = $(arguments[i]); -Element[Element.visible(element) ? 'hide' : 'show'](element); -} -}, -hide: function() { -for (var i = 0; i < arguments.length; i++) { -var element = $(arguments[i]); -element.style.display = 'none'; -} -}, -show: function() { -for (var i = 0; i < arguments.length; i++) { -var element = $(arguments[i]); -element.style.display = ''; -} -}, -remove: function(element) { -element = $(element); -element.parentNode.removeChild(element); -}, -update: function(element, html) { -$(element).innerHTML = html.stripScripts(); -setTimeout(function() {html.evalScripts()}, 10); -}, -getHeight: function(element) { -element = $(element); -return element.offsetHeight; -}, -classNames: function(element) { -return new Element.ClassNames(element); -}, -hasClassName: function(element, className) { -if (!(element = $(element))) return; -return Element.classNames(element).include(className); -}, -addClassName: function(element, className) { -if (!(element = $(element))) return; -return Element.classNames(element).add(className); -}, -removeClassName: function(element, className) { -if (!(element = $(element))) return; -return Element.classNames(element).remove(className); -}, -cleanWhitespace: function(element) { -element = $(element); -for (var i = 0; i < element.childNodes.length; i++) { -var node = element.childNodes[i]; -if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) -Element.remove(node); -} -}, -empty: function(element) { -return $(element).innerHTML.match(/^\s*$/); -}, -scrollTo: function(element) { -element = $(element); -var x = element.x ? element.x : element.offsetLeft, -y = element.y ? element.y : element.offsetTop; -window.scrollTo(x, y); -}, -getStyle: function(element, style) { -element = $(element); -var value = element.style[style.camelize()]; -if (!value) { -if (document.defaultView && document.defaultView.getComputedStyle) { -var css = document.defaultView.getComputedStyle(element, null); -value = css ? css.getPropertyValue(style) : null; -} else if (element.currentStyle) { -value = element.currentStyle[style.camelize()]; -} -} -if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) -if (Element.getStyle(element, 'position') == 'static') value = 'auto'; -return value == 'auto' ? null : value; -}, -setStyle: function(element, style) { -element = $(element); -for (name in style) -element.style[name.camelize()] = style[name]; -}, -getDimensions: function(element) { -element = $(element); -if (Element.getStyle(element, 'display') != 'none') -return {width: element.offsetWidth, height: element.offsetHeight}; -var els = element.style; -var originalVisibility = els.visibility; -var originalPosition = els.position; -els.visibility = 'hidden'; -els.position = 'absolute'; -els.display = ''; -var originalWidth = element.clientWidth; -var originalHeight = element.clientHeight; -els.display = 'none'; -els.position = originalPosition; -els.visibility = originalVisibility; -return {width: originalWidth, height: originalHeight}; -}, -makePositioned: function(element) { -element = $(element); -var pos = Element.getStyle(element, 'position'); -if (pos == 'static' || !pos) { -element._madePositioned = true; -element.style.position = 'relative'; -if (window.opera) { -element.style.top = 0; -element.style.left = 0; -} -} -}, -undoPositioned: function(element) { -element = $(element); -if (element._madePositioned) { -element._madePositioned = undefined; -element.style.position = -element.style.top = -element.style.left = -element.style.bottom = -element.style.right = ''; -} -}, -makeClipping: function(element) { -element = $(element); -if (element._overflow) return; -element._overflow = element.style.overflow; -if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') -element.style.overflow = 'hidden'; -}, -undoClipping: function(element) { -element = $(element); -if (element._overflow) return; -element.style.overflow = element._overflow; -element._overflow = undefined; -} -}); -var Toggle = new Object(); -Toggle.display = Element.toggle; -Abstract.Insertion = function(adjacency) { -this.adjacency = adjacency; -} -Abstract.Insertion.prototype = { -initialize: function(element, content) { -this.element = $(element); -this.content = content.stripScripts(); -if (this.adjacency && this.element.insertAdjacentHTML) { -try { -this.element.insertAdjacentHTML(this.adjacency, this.content); -} catch (e) { -if (this.element.tagName.toLowerCase() == 'tbody') { -this.insertContent(this.contentFromAnonymousTable()); -} else { -throw e; -} -} -} else { -this.range = this.element.ownerDocument.createRange(); -if (this.initializeRange) this.initializeRange(); -this.insertContent([this.range.createContextualFragment(this.content)]); -} -setTimeout(function() {content.evalScripts()}, 10); -}, -contentFromAnonymousTable: function() { -var div = document.createElement('div'); -div.innerHTML = '' + this.content + '
'; -return $A(div.childNodes[0].childNodes[0].childNodes); -} -} -var Insertion = new Object(); -Insertion.Before = Class.create(); -Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { -initializeRange: function() { -this.range.setStartBefore(this.element); -}, -insertContent: function(fragments) { -fragments.each((function(fragment) { -this.element.parentNode.insertBefore(fragment, this.element); -}).bind(this)); -} -}); -Insertion.Top = Class.create(); -Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { -initializeRange: function() { -this.range.selectNodeContents(this.element); -this.range.collapse(true); -}, -insertContent: function(fragments) { -fragments.reverse(false).each((function(fragment) { -this.element.insertBefore(fragment, this.element.firstChild); -}).bind(this)); -} -}); -Insertion.Bottom = Class.create(); -Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { -initializeRange: function() { -this.range.selectNodeContents(this.element); -this.range.collapse(this.element); -}, -insertContent: function(fragments) { -fragments.each((function(fragment) { -this.element.appendChild(fragment); -}).bind(this)); -} -}); -Insertion.After = Class.create(); -Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { -initializeRange: function() { -this.range.setStartAfter(this.element); -}, -insertContent: function(fragments) { -fragments.each((function(fragment) { -this.element.parentNode.insertBefore(fragment, -this.element.nextSibling); -}).bind(this)); -} -}); -Element.ClassNames = Class.create(); -Element.ClassNames.prototype = { -initialize: function(element) { -this.element = $(element); -}, -_each: function(iterator) { -this.element.className.split(/\s+/).select(function(name) { -return name.length > 0; -})._each(iterator); -}, -set: function(className) { -this.element.className = className; -}, -add: function(classNameToAdd) { -if (this.include(classNameToAdd)) return; -this.set(this.toArray().concat(classNameToAdd).join(' ')); -}, -remove: function(classNameToRemove) { -if (!this.include(classNameToRemove)) return; -this.set(this.select(function(className) { -return className != classNameToRemove; -}).join(' ')); -}, -toString: function() { -return this.toArray().join(' '); -} -} -Object.extend(Element.ClassNames.prototype, Enumerable); -var Field = { -clear: function() { -for (var i = 0; i < arguments.length; i++) -$(arguments[i]).value = ''; -}, -focus: function(element) { -$(element).focus(); -}, -present: function() { -for (var i = 0; i < arguments.length; i++) -if ($(arguments[i]).value == '') return false; -return true; -}, -select: function(element) { -$(element).select(); -}, -activate: function(element) { -element = $(element); -element.focus(); -if (element.select) -element.select(); -} -} -var Form = { -serialize: function(form) { -var elements = Form.getElements($(form)); -var queryComponents = new Array(); -for (var i = 0; i < elements.length; i++) { -var queryComponent = Form.Element.serialize(elements[i]); -if (queryComponent) -queryComponents.push(queryComponent); -} -return queryComponents.join('&'); -}, -getElements: function(form) { -form = $(form); -var elements = new Array(); -for (tagName in Form.Element.Serializers) { -var tagElements = form.getElementsByTagName(tagName); -for (var j = 0; j < tagElements.length; j++) -elements.push(tagElements[j]); -} -return elements; -}, -getInputs: function(form, typeName, name) { -form = $(form); -var inputs = form.getElementsByTagName('input'); -if (!typeName && !name) -return inputs; -var matchingInputs = new Array(); -for (var i = 0; i < inputs.length; i++) { -var input = inputs[i]; -if ((typeName && input.type != typeName) || -(name && input.name != name)) -continue; -matchingInputs.push(input); -} -return matchingInputs; -}, -disable: function(form) { -var elements = Form.getElements(form); -for (var i = 0; i < elements.length; i++) { -var element = elements[i]; -element.blur(); -element.disabled = 'true'; -} -}, -enable: function(form) { -var elements = Form.getElements(form); -for (var i = 0; i < elements.length; i++) { -var element = elements[i]; -element.disabled = ''; -} -}, -findFirstElement: function(form) { -return Form.getElements(form).find(function(element) { -return element.type != 'hidden' && !element.disabled && -['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); -}); -}, -focusFirstElement: function(form) { -Field.activate(Form.findFirstElement(form)); -}, -reset: function(form) { -$(form).reset(); -} -} -Form.Element = { -serialize: function(element) { -element = $(element); -var method = element.tagName.toLowerCase(); -var parameter = Form.Element.Serializers[method](element); -if (parameter) { -var key = encodeURIComponent(parameter[0]); -if (key.length == 0) return; -if (parameter[1].constructor != Array) -parameter[1] = [parameter[1]]; -return parameter[1].map(function(value) { -return key + '=' + encodeURIComponent(value); -}).join('&'); -} -}, -getValue: function(element) { -element = $(element); -var method = element.tagName.toLowerCase(); -var parameter = Form.Element.Serializers[method](element); -if (parameter) -return parameter[1]; -} -} -Form.Element.Serializers = { -input: function(element) { -switch (element.type.toLowerCase()) { -case 'submit': -case 'hidden': -case 'password': -case 'text': -return Form.Element.Serializers.textarea(element); -case 'checkbox': -case 'radio': -return Form.Element.Serializers.inputSelector(element); -} -return false; -}, -inputSelector: function(element) { -if (element.checked) -return [element.name, element.value]; -}, -textarea: function(element) { -return [element.name, element.value]; -}, -select: function(element) { -return Form.Element.Serializers[element.type == 'select-one' ? -'selectOne' : 'selectMany'](element); -}, -selectOne: function(element) { -var value = '', opt, index = element.selectedIndex; -if (index >= 0) { -opt = element.options[index]; -value = opt.value; -if (!value && !('value' in opt)) -value = opt.text; -} -return [element.name, value]; -}, -selectMany: function(element) { -var value = new Array(); -for (var i = 0; i < element.length; i++) { -var opt = element.options[i]; -if (opt.selected) { -var optValue = opt.value; -if (!optValue && !('value' in opt)) -optValue = opt.text; -value.push(optValue); -} -} -return [element.name, value]; -} -} -var $F = Form.Element.getValue; -Abstract.TimedObserver = function() {} -Abstract.TimedObserver.prototype = { -initialize: function(element, frequency, callback) { -this.frequency = frequency; -this.element = $(element); -this.callback = callback; -this.lastValue = this.getValue(); -this.registerCallback(); -}, -registerCallback: function() { -setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); -}, -onTimerEvent: function() { -var value = this.getValue(); -if (this.lastValue != value) { -this.callback(this.element, value); -this.lastValue = value; -} -} -} -Form.Element.Observer = Class.create(); -Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { -getValue: function() { -return Form.Element.getValue(this.element); -} -}); -Form.Observer = Class.create(); -Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { -getValue: function() { -return Form.serialize(this.element); -} -}); -Abstract.EventObserver = function() {} -Abstract.EventObserver.prototype = { -initialize: function(element, callback) { -this.element = $(element); -this.callback = callback; -this.lastValue = this.getValue(); -if (this.element.tagName.toLowerCase() == 'form') -this.registerFormCallbacks(); -else -this.registerCallback(this.element); -}, -onElementEvent: function() { -var value = this.getValue(); -if (this.lastValue != value) { -this.callback(this.element, value); -this.lastValue = value; -} -}, -registerFormCallbacks: function() { -var elements = Form.getElements(this.element); -for (var i = 0; i < elements.length; i++) -this.registerCallback(elements[i]); -}, -registerCallback: function(element) { -if (element.type) { -switch (element.type.toLowerCase()) { -case 'checkbox': -case 'radio': -Event.observe(element, 'click', this.onElementEvent.bind(this)); -break; -case 'password': -case 'text': -case 'textarea': -case 'select-one': -case 'select-multiple': -Event.observe(element, 'change', this.onElementEvent.bind(this)); -break; -} -} -} -} -Form.Element.EventObserver = Class.create(); -Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { -getValue: function() { -return Form.Element.getValue(this.element); -} -}); -Form.EventObserver = Class.create(); -Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { -getValue: function() { -return Form.serialize(this.element); -} -}); -if (!window.Event) { -var Event = new Object(); -} -Object.extend(Event, { -KEY_BACKSPACE: 8, -KEY_TAB: 9, -KEY_RETURN: 13, -KEY_ESC: 27, -KEY_LEFT: 37, -KEY_UP: 38, -KEY_RIGHT: 39, -KEY_DOWN: 40, -KEY_DELETE: 46, -element: function(event) { -return event.target || event.srcElement; -}, -isLeftClick: function(event) { -return (((event.which) && (event.which == 1)) || -((event.button) && (event.button == 1))); -}, -pointerX: function(event) { -return event.pageX || (event.clientX + -(document.documentElement.scrollLeft || document.body.scrollLeft)); -}, -pointerY: function(event) { -return event.pageY || (event.clientY + -(document.documentElement.scrollTop || document.body.scrollTop)); -}, -stop: function(event) { -if (event.preventDefault) { -event.preventDefault(); -event.stopPropagation(); -} else { -event.returnValue = false; -event.cancelBubble = true; -} -}, -findElement: function(event, tagName) { -var element = Event.element(event); -while (element.parentNode && (!element.tagName || -(element.tagName.toUpperCase() != tagName.toUpperCase()))) -element = element.parentNode; -return element; -}, -observers: false, -_observeAndCache: function(element, name, observer, useCapture) { -if (!this.observers) this.observers = []; -if (element.addEventListener) { -this.observers.push([element, name, observer, useCapture]); -element.addEventListener(name, observer, useCapture); -} else if (element.attachEvent) { -this.observers.push([element, name, observer, useCapture]); -element.attachEvent('on' + name, observer); -} -}, -unloadCache: function() { -if (!Event.observers) return; -for (var i = 0; i < Event.observers.length; i++) { -Event.stopObserving.apply(this, Event.observers[i]); -Event.observers[i][0] = null; -} -Event.observers = false; -}, -observe: function(element, name, observer, useCapture) { -var element = $(element); -useCapture = useCapture || false; -if (name == 'keypress' && -(navigator.appVersion.match(/Konqueror|Safari|KHTML/) -|| element.attachEvent)) -name = 'keydown'; -this._observeAndCache(element, name, observer, useCapture); -}, -stopObserving: function(element, name, observer, useCapture) { -var element = $(element); -useCapture = useCapture || false; -if (name == 'keypress' && -(navigator.appVersion.match(/Konqueror|Safari|KHTML/) -|| element.detachEvent)) -name = 'keydown'; -if (element.removeEventListener) { -element.removeEventListener(name, observer, useCapture); -} else if (element.detachEvent) { -element.detachEvent('on' + name, observer); -} -} -}); -Event.observe(window, 'unload', Event.unloadCache, false); -var Position = { -includeScrollOffsets: false, -prepare: function() { -this.deltaX = window.pageXOffset -|| document.documentElement.scrollLeft -|| document.body.scrollLeft -|| 0; -this.deltaY = window.pageYOffset -|| document.documentElement.scrollTop -|| document.body.scrollTop -|| 0; -}, -realOffset: function(element) { -var valueT = 0, valueL = 0; -do { -valueT += element.scrollTop || 0; -valueL += element.scrollLeft || 0; -element = element.parentNode; -} while (element); -return [valueL, valueT]; -}, -cumulativeOffset: function(element) { -var valueT = 0, valueL = 0; -do { -valueT += element.offsetTop || 0; -valueL += element.offsetLeft || 0; -element = element.offsetParent; -} while (element); -return [valueL, valueT]; -}, -positionedOffset: function(element) { -var valueT = 0, valueL = 0; -do { -valueT += element.offsetTop || 0; -valueL += element.offsetLeft || 0; -element = element.offsetParent; -if (element) { -p = Element.getStyle(element, 'position'); -if (p == 'relative' || p == 'absolute') break; -} -} while (element); -return [valueL, valueT]; -}, -offsetParent: function(element) { -if (element.offsetParent) return element.offsetParent; -if (element == document.body) return element; -while ((element = element.parentNode) && element != document.body) -if (Element.getStyle(element, 'position') != 'static') -return element; -return document.body; -}, -within: function(element, x, y) { -if (this.includeScrollOffsets) -return this.withinIncludingScrolloffsets(element, x, y); -this.xcomp = x; -this.ycomp = y; -this.offset = this.cumulativeOffset(element); -return (y >= this.offset[1] && -y < this.offset[1] + element.offsetHeight && -x >= this.offset[0] && -x < this.offset[0] + element.offsetWidth); -}, -withinIncludingScrolloffsets: function(element, x, y) { -var offsetcache = this.realOffset(element); -this.xcomp = x + offsetcache[0] - this.deltaX; -this.ycomp = y + offsetcache[1] - this.deltaY; -this.offset = this.cumulativeOffset(element); -return (this.ycomp >= this.offset[1] && -this.ycomp < this.offset[1] + element.offsetHeight && -this.xcomp >= this.offset[0] && -this.xcomp < this.offset[0] + element.offsetWidth); -}, -overlap: function(mode, element) { -if (!mode) return 0; -if (mode == 'vertical') -return ((this.offset[1] + element.offsetHeight) - this.ycomp) / -element.offsetHeight; -if (mode == 'horizontal') -return ((this.offset[0] + element.offsetWidth) - this.xcomp) / -element.offsetWidth; -}, -clone: function(source, target) { -source = $(source); -target = $(target); -target.style.position = 'absolute'; -var offsets = this.cumulativeOffset(source); -target.style.top = offsets[1] + 'px'; -target.style.left = offsets[0] + 'px'; -target.style.width = source.offsetWidth + 'px'; -target.style.height = source.offsetHeight + 'px'; -}, -page: function(forElement) { -var valueT = 0, valueL = 0; -var element = forElement; -do { -valueT += element.offsetTop || 0; -valueL += element.offsetLeft || 0; -if (element.offsetParent==document.body) -if (Element.getStyle(element,'position')=='absolute') break; -} while (element = element.offsetParent); -element = forElement; -do { -valueT -= element.scrollTop || 0; -valueL -= element.scrollLeft || 0; -} while (element = element.parentNode); -return [valueL, valueT]; -}, -clone: function(source, target) { -var options = Object.extend({ -setLeft: true, -setTop: true, -setWidth: true, -setHeight: true, -offsetTop: 0, -offsetLeft: 0 -}, arguments[2] || {}) -source = $(source); -var p = Position.page(source); -target = $(target); -var delta = [0, 0]; -var parent = null; -if (Element.getStyle(target,'position') == 'absolute') { -parent = Position.offsetParent(target); -delta = Position.page(parent); -} -if (parent == document.body) { -delta[0] -= document.body.offsetLeft; -delta[1] -= document.body.offsetTop; -} -if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; -if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; -if(options.setWidth) target.style.width = source.offsetWidth + 'px'; -if(options.setHeight) target.style.height = source.offsetHeight + 'px'; -}, -absolutize: function(element) { -element = $(element); -if (element.style.position == 'absolute') return; -Position.prepare(); -var offsets = Position.positionedOffset(element); -var top = offsets[1]; -var left = offsets[0]; -var width = element.clientWidth; -var height = element.clientHeight; -element._originalLeft = left - parseFloat(element.style.left || 0); -element._originalTop = top - parseFloat(element.style.top || 0); -element._originalWidth = element.style.width; -element._originalHeight = element.style.height; -element.style.position = 'absolute'; -element.style.top = top + 'px';; -element.style.left = left + 'px';; -element.style.width = width + 'px';; -element.style.height = height + 'px';; -}, -relativize: function(element) { -element = $(element); -if (element.style.position == 'relative') return; -Position.prepare(); -element.style.position = 'relative'; -var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); -var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); -element.style.top = top + 'px'; -element.style.left = left + 'px'; -element.style.height = element._originalHeight; -element.style.width = element._originalWidth; -} -} -if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { -Position.cumulativeOffset = function(element) { -var valueT = 0, valueL = 0; -do { -valueT += element.offsetTop || 0; -valueL += element.offsetLeft || 0; -if (element.offsetParent == document.body) -if (Element.getStyle(element, 'position') == 'absolute') break; -element = element.offsetParent; -} while (element); -return [valueL, valueT]; -} -} diff --git a/test/expected_dir/js1.js/javascript/comment b/test/expected_dir/js1.js/javascript/comment deleted file mode 100644 index 71f7f83..0000000 --- a/test/expected_dir/js1.js/javascript/comment +++ /dev/null @@ -1,46 +0,0 @@ -/* Prototype JavaScript framework, version 1.4.0 -* (c) 2005 Sam Stephenson -* -* Prototype is freely distributable under the terms of an MIT-style license. -* For details, see the Prototype web site: http://prototype.conio.net/ -* -/*--------------------------------------------------------------------------*/ -/*--------------------------------------------------------------------------*/ -/*--------------------------------------------------------------------------*/ -/* Force "Connection: close" for Mozilla browsers to work around -* a bug where XMLHttpReqeuest sends an incorrect Content-length -* header. See Mozilla Bugzilla #246651. -*/ -/* Avoid memory leak in MSIE: clean up the oncomplete event handler */ -/*--------------------------------------------------------------------------*/ -// removes whitespace-only text node children -// All *Width and *Height properties give 0 on elements with display none, -// so enable the element temporarily -// Opera returns the offset relative to the positioning context, when an -// element is position relative but top and left have not been defined -/*--------------------------------------------------------------------------*/ -/*--------------------------------------------------------------------------*/ -/*--------------------------------------------------------------------------*/ -/*--------------------------------------------------------------------------*/ -/*--------------------------------------------------------------------------*/ -/*--------------------------------------------------------------------------*/ -// find the first node with the given tagName, starting from the -// node the event was triggered on; traverses the DOM upwards -/* prevent memory leaks in IE */ -// set to true if needed, warning: firefox performance problems -// NOT neeeded for page scrolling, only if draggable contained in -// scrollable elements -// must be called before calling withinIncludingScrolloffset, every time the -// page is scrolled -// caches x/y coordinate pair to use with overlap -// within must be called directly before -// Safari fix -// find page position of source -// find coordinate system to use -// delta [0,0] will do fine with position: fixed elements, -// position:absolute needs offsetParent deltas -// correct by body offsets (fixes Safari) -// set position -// Safari returns margins on body which is incorrect if the child is absolutely -// positioned. For performance reasons, redefine Position.cumulativeOffset for -// KHTML/WebKit only. diff --git a/test/expected_dir/js2.js b/test/expected_dir/js2.js new file mode 100644 index 0000000..48019a4 --- /dev/null +++ b/test/expected_dir/js2.js @@ -0,0 +1,13 @@ +javascript code diff --git a/test/expected_dir/js2.js/javascript/code b/test/expected_dir/js2.js/javascript/code deleted file mode 100644 index 2b8e7c5..0000000 --- a/test/expected_dir/js2.js/javascript/code +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/test/expected_dir/js2.js/javascript/comment b/test/expected_dir/js2.js/javascript/comment deleted file mode 100644 index 636c0ba..0000000 --- a/test/expected_dir/js2.js/javascript/comment +++ /dev/null @@ -1,7 +0,0 @@ -/* -Random Comments -Foo Foo Foo -*/ -// comment -// another comment -//Set delay before submenu disappears after mouse moves out of it (in milliseconds) diff --git a/test/expected_dir/js3.js b/test/expected_dir/js3.js new file mode 100644 index 0000000..ed52700 --- /dev/null +++ b/test/expected_dir/js3.js @@ -0,0 +1,2 @@ +javascript code return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'"; +javascript comment // comment diff --git a/test/expected_dir/jsp1.jsp b/test/expected_dir/jsp1.jsp new file mode 100644 index 0000000..6ba6c49 --- /dev/null +++ b/test/expected_dir/jsp1.jsp @@ -0,0 +1,14 @@ +html code +html code +html code JSP page +html code +html code +java code <%@ page language="java" %> +java code <% out.println("Hello World"); %> +java comment <% // comment +java comment /* +java comment * more comment +java comment */ +html code %> +html code +html code diff --git a/test/expected_dir/jsp1.jsp/html/code b/test/expected_dir/jsp1.jsp/html/code deleted file mode 100644 index c34bf15..0000000 --- a/test/expected_dir/jsp1.jsp/html/code +++ /dev/null @@ -1,8 +0,0 @@ - - -JSP page - - -%> - - diff --git a/test/expected_dir/jsp1.jsp/java/blanks b/test/expected_dir/jsp1.jsp/java/blanks deleted file mode 100644 index c227083..0000000 --- a/test/expected_dir/jsp1.jsp/java/blanks +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/test/expected_dir/jsp1.jsp/java/code b/test/expected_dir/jsp1.jsp/java/code deleted file mode 100644 index e139ba9..0000000 --- a/test/expected_dir/jsp1.jsp/java/code +++ /dev/null @@ -1,2 +0,0 @@ -<%@ page language="java" %> -<% out.println("Hello World"); %> diff --git a/test/expected_dir/jsp1.jsp/java/comment b/test/expected_dir/jsp1.jsp/java/comment deleted file mode 100644 index 49d6ff4..0000000 --- a/test/expected_dir/jsp1.jsp/java/comment +++ /dev/null @@ -1,4 +0,0 @@ -<% // comment -/* -* more comment -*/ diff --git a/test/expected_dir/lsp1.lsp b/test/expected_dir/lsp1.lsp new file mode 100644 index 0000000..7bfd739 --- /dev/null +++ b/test/expected_dir/lsp1.lsp @@ -0,0 +1,135 @@ +lisp comment ;;; CrapsSim.lsp +lisp blank +lisp comment """ +lisp comment The main purpose of this program was to implement a Craps game, using a language that we have just +lisp comment learned. Also, it was written in a functional style with almost no reliance on the assignment +lisp comment operation. Only one local variable called THROW was used. +lisp comment """ +lisp blank +lisp blank +lisp comment ;;; ====================================================================================================== ;;; +lisp comment ;;; ======================================= CRAPS SIMULATION ============================================= ;;; +lisp comment ;;; ====================================================================================================== ;;; +lisp blank +lisp blank +lisp comment ;;; ** This function takes no parameters as input and returns a random number between 1 and 6. ** +lisp blank +lisp code (DEFUN THROW-DIE () +lisp code (+ (RANDOM 6) 1) ;;; get a random number between 0 and 5 and then add 1 +lisp code ) +lisp blank +lisp comment ;;; ====================================================================================================== ;;; +lisp blank +lisp comment ;;; ** This function takes no parameters as input and returns a LIST with two numbers between 1 and 6. ** +lisp blank +lisp blank +lisp code (DEFUN THROW-DICE () +lisp blank +lisp code (LIST (THROW-DIE) (THROW-DIE)) ;;; create a list with two random numbers +lisp blank +lisp code ) +lisp blank +lisp comment ;;; ====================================================================================================== ;;; +lisp blank +lisp comment ;;; ** This function takes two numbers as parameters for input and returns T or Nil. T is returned if both +lisp comment ;;; numbers are equal to 6. Nil is returned otherwise. ** +lisp blank +lisp code (DEFUN BOXCARS-P (A B) +lisp code (AND (EQUAL '6 A) +lisp code (EQUAL '6 B) +lisp code ) +lisp blank +lisp code ) +lisp blank +lisp comment ;;; ====================================================================================================== ;;; +lisp blank +lisp comment ;;; ** This function takes two numbers as parameters for input and returns T or Nil. T is returned if both +lisp comment ;;; numbers are equal to 1. Nil is returned otherwise. ** +lisp blank +lisp code (DEFUN SNAKE-EYES-P (A B) +lisp code (AND (EQUAL '1 A) +lisp code (EQUAL '1 B) +lisp code ) +lisp blank +lisp code ) +lisp blank +lisp comment ;;; ====================================================================================================== ;;; +lisp blank +lisp comment ;;; ** This function takes two numbers as parameters for input and returns T or Nil. T is returned if the +lisp comment ;;; sum of both numbers is equal to a 7 or 11. Nil is returned otherwise. ** +lisp blank +lisp code (DEFUN INSTANT-WIN-P (A B) +lisp code (OR (EQUAL '7 (+ A B)) +lisp code (EQUAL '11 (+ A B)) +lisp code ) +lisp blank +lisp code ) +lisp blank +lisp comment ;;; ====================================================================================================== ;;; +lisp blank +lisp comment ;;; ** This function takes two numbers as parameters for input and returns T or Nil. T is returned if the +lisp comment ;;; sum of both numbers is equal to a 2, 3 or 12. Nil is returned otherwise. ** +lisp blank +lisp code (DEFUN INSTANT-LOSS-P (A B) +lisp code (OR (EQUAL '2 (+ A B)) +lisp code (EQUAL '3 (+ A B)) +lisp code (EQUAL '12 (+ A B)) +lisp code ) +lisp blank +lisp code ) +lisp blank +lisp comment ;;; ====================================================================================================== ;;; +lisp blank +lisp comment ;;; ** This function takes two numbers as parameters for input and returns a string. If function BOXCARS_P +lisp comment ;;; returns T, then the returned string equals BOXCARS. If function SNAKE_EYES_P returns T, then the +lisp comment ;;; returned string equals SNAKE_EYES. The string contains Nil otherwise. ** +lisp blank +lisp code (DEFUN SAY-THROW (A B) +lisp code (COND ((BOXCARS-P A B) 'BOXCARS) ;;; make use of function BOXCARS_P +lisp code ((SNAKE-EYES-P A B) 'SNAKE-EYES) ;;; make use of function SNAKE_EYES_P +lisp blank +lisp code ) +lisp code ) +lisp blank +lisp comment ;;; ====================================================================================================== ;;; +lisp blank +lisp comment ;;; ** This is the main function used to simulate the game of craps. Variable THROW contains a LIST of two +lisp comment ;;; numbers between 1 and 6. The numbers located in THROW, are used as parameters for the other functions. +lisp comment ;;; The several pieces used for output are listed together and then the LIST is returned from this +lisp comment ;;; function. +lisp blank +lisp blank +lisp code (DEFUN CRAPS () +lisp code (LET THROW (THROW-DICE)) ;;; get initial roll of the dice +lisp blank +lisp comment ;;; if roll is a win, then LIST the appropriate output +lisp blank +lisp code (COND ((INSTANT-WIN-P (FIRST THROW) (SECOND THROW)) +lisp code (LIST 'THROW (FIRST THROW) 'AND (SECOND THROW) '-- (+ (FIRST THROW) (SECOND THROW)) '-- 'YOU 'WIN)) +lisp blank +lisp comment ;;; if roll is a loss, then check for BOXCARS or SNAKE-EYES +lisp blank +lisp code ((INSTANT-LOSS-P (FIRST THROW) (SECOND THROW)) +lisp blank +lisp code (IF (EQUAL 'NIL (SAY-THROW (FIRST THROW) (SECOND THROW))) ;;; if Nil then LIST appropriate output +lisp blank +lisp code (LIST 'THROW (FIRST THROW) 'AND (SECOND THROW) '-- (+ (FIRST THROW) (SECOND THROW)) '-- 'YOU 'LOSE) +lisp blank +lisp comment ;;; else include the BOXCARS or SNAKE-EYES string in the output +lisp blank +lisp code (LIST 'THROW (FIRST THROW) 'AND (SECOND THROW) '-- (SAY-THROW (FIRST THROW) (SECOND THROW)) +lisp code '-- 'YOU 'LOSE))) +lisp blank +lisp comment ;;; if roll is not instant win or loss then output sum of dice +lisp blank +lisp code (T (LIST 'THROW (FIRST THROW) 'AND (SECOND THROW) '-- 'YOUR 'POINT 'IS (+ (FIRST THROW) +lisp code (SECOND THROW)))) +lisp code ) ;;; end COND +lisp blank +lisp code ) ;;; end LET +lisp blank +lisp blank +lisp code ) +lisp blank +lisp blank +lisp comment ;;; ======================================== END OF PROGRAM CRAPS ======================================== ;;; diff --git a/test/expected_dir/lsp1.lsp/lisp/blanks b/test/expected_dir/lsp1.lsp/lisp/blanks deleted file mode 100644 index 7003e7f..0000000 --- a/test/expected_dir/lsp1.lsp/lisp/blanks +++ /dev/null @@ -1 +0,0 @@ -51 \ No newline at end of file diff --git a/test/expected_dir/lsp1.lsp/lisp/code b/test/expected_dir/lsp1.lsp/lisp/code deleted file mode 100644 index b79eef4..0000000 --- a/test/expected_dir/lsp1.lsp/lisp/code +++ /dev/null @@ -1,46 +0,0 @@ -(DEFUN THROW-DIE () -(+ (RANDOM 6) 1) ;;; get a random number between 0 and 5 and then add 1 -) -(DEFUN THROW-DICE () -(LIST (THROW-DIE) (THROW-DIE)) ;;; create a list with two random numbers -) -(DEFUN BOXCARS-P (A B) -(AND (EQUAL '6 A) -(EQUAL '6 B) -) -) -(DEFUN SNAKE-EYES-P (A B) -(AND (EQUAL '1 A) -(EQUAL '1 B) -) -) -(DEFUN INSTANT-WIN-P (A B) -(OR (EQUAL '7 (+ A B)) -(EQUAL '11 (+ A B)) -) -) -(DEFUN INSTANT-LOSS-P (A B) -(OR (EQUAL '2 (+ A B)) -(EQUAL '3 (+ A B)) -(EQUAL '12 (+ A B)) -) -) -(DEFUN SAY-THROW (A B) -(COND ((BOXCARS-P A B) 'BOXCARS) ;;; make use of function BOXCARS_P -((SNAKE-EYES-P A B) 'SNAKE-EYES) ;;; make use of function SNAKE_EYES_P -) -) -(DEFUN CRAPS () -(LET THROW (THROW-DICE)) ;;; get initial roll of the dice -(COND ((INSTANT-WIN-P (FIRST THROW) (SECOND THROW)) -(LIST 'THROW (FIRST THROW) 'AND (SECOND THROW) '-- (+ (FIRST THROW) (SECOND THROW)) '-- 'YOU 'WIN)) -((INSTANT-LOSS-P (FIRST THROW) (SECOND THROW)) -(IF (EQUAL 'NIL (SAY-THROW (FIRST THROW) (SECOND THROW))) ;;; if Nil then LIST appropriate output -(LIST 'THROW (FIRST THROW) 'AND (SECOND THROW) '-- (+ (FIRST THROW) (SECOND THROW)) '-- 'YOU 'LOSE) -(LIST 'THROW (FIRST THROW) 'AND (SECOND THROW) '-- (SAY-THROW (FIRST THROW) (SECOND THROW)) -'-- 'YOU 'LOSE))) -(T (LIST 'THROW (FIRST THROW) 'AND (SECOND THROW) '-- 'YOUR 'POINT 'IS (+ (FIRST THROW) -(SECOND THROW)))) -) ;;; end COND -) ;;; end LET -) diff --git a/test/expected_dir/lsp1.lsp/lisp/comment b/test/expected_dir/lsp1.lsp/lisp/comment deleted file mode 100644 index 4e7403d..0000000 --- a/test/expected_dir/lsp1.lsp/lisp/comment +++ /dev/null @@ -1,38 +0,0 @@ -;;; CrapsSim.lsp -""" -The main purpose of this program was to implement a Craps game, using a language that we have just -learned. Also, it was written in a functional style with almost no reliance on the assignment -operation. Only one local variable called THROW was used. -""" -;;; ====================================================================================================== ;;; -;;; ======================================= CRAPS SIMULATION ============================================= ;;; -;;; ====================================================================================================== ;;; -;;; ** This function takes no parameters as input and returns a random number between 1 and 6. ** -;;; ====================================================================================================== ;;; -;;; ** This function takes no parameters as input and returns a LIST with two numbers between 1 and 6. ** -;;; ====================================================================================================== ;;; -;;; ** This function takes two numbers as parameters for input and returns T or Nil. T is returned if both -;;; numbers are equal to 6. Nil is returned otherwise. ** -;;; ====================================================================================================== ;;; -;;; ** This function takes two numbers as parameters for input and returns T or Nil. T is returned if both -;;; numbers are equal to 1. Nil is returned otherwise. ** -;;; ====================================================================================================== ;;; -;;; ** This function takes two numbers as parameters for input and returns T or Nil. T is returned if the -;;; sum of both numbers is equal to a 7 or 11. Nil is returned otherwise. ** -;;; ====================================================================================================== ;;; -;;; ** This function takes two numbers as parameters for input and returns T or Nil. T is returned if the -;;; sum of both numbers is equal to a 2, 3 or 12. Nil is returned otherwise. ** -;;; ====================================================================================================== ;;; -;;; ** This function takes two numbers as parameters for input and returns a string. If function BOXCARS_P -;;; returns T, then the returned string equals BOXCARS. If function SNAKE_EYES_P returns T, then the -;;; returned string equals SNAKE_EYES. The string contains Nil otherwise. ** -;;; ====================================================================================================== ;;; -;;; ** This is the main function used to simulate the game of craps. Variable THROW contains a LIST of two -;;; numbers between 1 and 6. The numbers located in THROW, are used as parameters for the other functions. -;;; The several pieces used for output are listed together and then the LIST is returned from this -;;; function. -;;; if roll is a win, then LIST the appropriate output -;;; if roll is a loss, then check for BOXCARS or SNAKE-EYES -;;; else include the BOXCARS or SNAKE-EYES string in the output -;;; if roll is not instant win or loss then output sum of dice -;;; ======================================== END OF PROGRAM CRAPS ======================================== ;;; diff --git a/test/expected_dir/lua1.lua b/test/expected_dir/lua1.lua new file mode 100644 index 0000000..92ba5d7 --- /dev/null +++ b/test/expected_dir/lua1.lua @@ -0,0 +1,121 @@ +lua comment -- random code from http://lua-users.org/wiki/TextJustification +lua comment -- easy queue implementation ------------------------------------------ +lua blank +lua code function q_create() +lua code local q = {} +lua code q.first = 0 +lua code q.last = 0 +lua code return q +lua code end +lua blank +lua code function q_insert(q, s) +lua code q[q.last] = s +lua code q.last = q.last + 1 +lua code end +lua blank +lua code function q_empty(q) +lua code return q.first >= q.last +lua code end +lua blank +lua code function q_remove(q) +lua code if q_empty(q) then +lua code return nil +lua code end +lua code local s = q[q.first] +lua code q[q.first] = nil +lua code q.first = q.first+1 +lua code return s +lua code end +lua blank +lua code function q_card(q) +lua code return q.last - q.first +lua code end +lua blank +lua code function q_length(q, f) +lua code local l, i = 0, q.first +lua code while i < q.last do +lua code l = l + strlen(q[i]) +lua code i = i + 1 +lua code end +lua code return l +lua code end +lua blank +lua comment -- line creation routines ------------------------------------------ +lua blank +lua comment -- justifies one line to fit into MAX columns +lua code function justify(q) +lua code local blanks = MAX - q_length(q) +lua code local skips = q_card(q) - 1 +lua code local line = q_remove(q) +lua code local quotient = floor(blanks/skips) +lua code local reminder = blanks/skips - quotient +lua code local error = 0 +lua code while skips > 0 do +lua code error = error + reminder +lua code if error >= 0.5 then +lua code error = error - 1 +lua code line = line .. strrep(" ", quotient+1) +lua code else +lua code line = line .. strrep(" ", quotient) +lua code end +lua code line = line .. q_remove(q) +lua code skips = skips - 1 +lua code end +lua code return line or "" +lua code end +lua blank +lua comment -- join all words with one space between them +lua code function catenate(q) +lua code local line = q_remove(q) +lua code while not q_empty(q) do +lua code line = line .. " " .. q_remove(q) +lua code end +lua code return line or "" +lua code end +lua blank +lua comment -- main program ----------------------------------------------------- +lua code DEFMAX = 72 +lua comment -- tries to get MAX from command-line +lua code if not arg or getn(arg) < 1 then +lua code MAX = DEFMAX +lua code else +lua code MAX = tonumber(arg[1]) +lua code if not MAX or MAX < 0 then +lua code MAX = DEFMAX +lua code end +lua code end +lua blank +lua comment -- collects all text from stdin +lua code text = q_create() +lua code line = read() +lua code while line do +lua code _, n = gsub(line, "(%S+)", function (s) q_insert(%text, s) end) +lua code if n == 0 then +lua code q_insert(text, "\n") +lua code end +lua code line = read() +lua code end +lua blank +lua comment -- justify paragraphs +lua code line = q_create() +lua code word = q_remove(text) +lua code size = 0 +lua code while word do +lua code if word == "\n" then +lua code if not q_empty(line) then +lua code write(catenate(line), "\n\n") +lua code else +lua code write("\n") +lua code end +lua code size = 0 +lua code elseif size + strlen(word) > MAX then +lua code write(justify(line), "\n") +lua code size = 0 +lua code end +lua code if word ~= "\n" then +lua code q_insert(line, word) +lua code size = size + strlen(word) + 1 +lua code end +lua code word = q_remove(text) +lua code end +lua code write(catenate(line), "\n") diff --git a/test/expected_dir/lua1.lua/lua/blanks b/test/expected_dir/lua1.lua/lua/blanks deleted file mode 100644 index 3cacc0b..0000000 --- a/test/expected_dir/lua1.lua/lua/blanks +++ /dev/null @@ -1 +0,0 @@ -12 \ No newline at end of file diff --git a/test/expected_dir/lua1.lua/lua/code b/test/expected_dir/lua1.lua/lua/code deleted file mode 100644 index 32b5ead..0000000 --- a/test/expected_dir/lua1.lua/lua/code +++ /dev/null @@ -1,100 +0,0 @@ -function q_create() -local q = {} -q.first = 0 -q.last = 0 -return q -end -function q_insert(q, s) -q[q.last] = s -q.last = q.last + 1 -end -function q_empty(q) -return q.first >= q.last -end -function q_remove(q) -if q_empty(q) then -return nil -end -local s = q[q.first] -q[q.first] = nil -q.first = q.first+1 -return s -end -function q_card(q) -return q.last - q.first -end -function q_length(q, f) -local l, i = 0, q.first -while i < q.last do -l = l + strlen(q[i]) -i = i + 1 -end -return l -end -function justify(q) -local blanks = MAX - q_length(q) -local skips = q_card(q) - 1 -local line = q_remove(q) -local quotient = floor(blanks/skips) -local reminder = blanks/skips - quotient -local error = 0 -while skips > 0 do -error = error + reminder -if error >= 0.5 then -error = error - 1 -line = line .. strrep(" ", quotient+1) -else -line = line .. strrep(" ", quotient) -end -line = line .. q_remove(q) -skips = skips - 1 -end -return line or "" -end -function catenate(q) -local line = q_remove(q) -while not q_empty(q) do -line = line .. " " .. q_remove(q) -end -return line or "" -end -DEFMAX = 72 -if not arg or getn(arg) < 1 then -MAX = DEFMAX -else -MAX = tonumber(arg[1]) -if not MAX or MAX < 0 then -MAX = DEFMAX -end -end -text = q_create() -line = read() -while line do -_, n = gsub(line, "(%S+)", function (s) q_insert(%text, s) end) -if n == 0 then -q_insert(text, "\n") -end -line = read() -end -line = q_create() -word = q_remove(text) -size = 0 -while word do -if word == "\n" then -if not q_empty(line) then -write(catenate(line), "\n\n") -else -write("\n") -end -size = 0 -elseif size + strlen(word) > MAX then -write(justify(line), "\n") -size = 0 -end -if word ~= "\n" then -q_insert(line, word) -size = size + strlen(word) + 1 -end -word = q_remove(text) -end -write(catenate(line), "\n") diff --git a/test/expected_dir/lua1.lua/lua/comment b/test/expected_dir/lua1.lua/lua/comment deleted file mode 100644 index 7f5dbe6..0000000 --- a/test/expected_dir/lua1.lua/lua/comment +++ /dev/null @@ -1,9 +0,0 @@ --- random code from http://lua-users.org/wiki/TextJustification --- easy queue implementation ------------------------------------------ --- line creation routines ------------------------------------------ --- justifies one line to fit into MAX columns --- join all words with one space between them --- main program ----------------------------------------------------- --- tries to get MAX from command-line --- collects all text from stdin --- justify paragraphs diff --git a/test/expected_dir/matlab1.m b/test/expected_dir/matlab1.m new file mode 100644 index 0000000..6499b80 --- /dev/null +++ b/test/expected_dir/matlab1.m @@ -0,0 +1,54 @@ +matlab comment % PROGRAM theta_logistic.m +matlab comment % Calculates by simulation the probability that a population +matlab comment % following the theta logistic model and starting at Nc will fall +matlab comment % below the quasi-extinction threshold Nx at or before time tmax +matlab blank +matlab comment % SIMULATION PARAMETERS +matlab comment % for butterflies (Euphydryas editha bayensis) at Jasper Ridge (population C) +matlab blank +matlab code r=0.3458; % intrinsic rate of increase--Butterflies at Jasper Ridge +matlab code K=846.017; % carrying capacity +matlab code theta=1; % nonlinearity in density dependence +matlab code sigma2=1.1151; % environmental variance +matlab code Nc=94; % starting population size +matlab code Nx=20; % quasi-extinction threshold +matlab code tmax=20; % time horizon +matlab code NumReps=50000; % number of replicate population trajectories +matlab blank +matlab comment % SIMULATION CODE +matlab blank +matlab code sigma=sqrt(sigma2); +matlab code randn('state',sum(100*clock)); % seed the random number generator +matlab blank +matlab code N=Nc*ones(1,NumReps); % all NumRep populations start at Nc +matlab code NumExtant=NumReps; % all populations are initially extant +matlab code Extant=[NumExtant]; % vector for number of extant pops. vs. time +matlab blank +matlab code for t=1:tmax, % For each future time, +matlab code N=N.*exp( r*( 1-(N/K).^theta )... % the theta logistic model +matlab code + sigma*randn(1,NumExtant) ); % with random environmental effects. +matlab code for i=NumExtant:-1:1, % Then, looping over all extant populations, +matlab code if N(i)<=Nx, % if at or below quasi-extinction threshold, +matlab code N(i)=[]; % delete the population. +matlab code end; +matlab code end; +matlab code NumExtant=length(N); % Count remaining extant populations +matlab code Extant=[Extant NumExtant]; % and store the result. +matlab code end; +matlab blank +matlab comment % OUTPUT CODE +matlab comment % ComputeS quasi-extinction probability as the fraction of replicate +matlab comment % populations that have hit the threshold by each future time, +matlab comment % and plotS quasi-extinction probability vs. time +matlab blank +matlab code ProbExtinct=(NumReps-Extant)/NumReps; +matlab code plot([0:tmax],ProbExtinct) +matlab code xlabel('Years into the future'); +matlab code ylabel('Cumulative probability of quasi-extinction'); +matlab code axis([0 tmax 0 1]); +matlab blank +matlab comment % Integrate solution exactly % +matlab comment % Options=[]; +matlab comment % [T,true] = ode45(@logistic,[0,20],Nc,Options,r,K,theta); +matlab comment % subplot(1,2,2) +matlab comment % plot([1:tmax],P,'r.-',T,true,'g.-') diff --git a/test/expected_dir/matlab1.m/matlab/blanks b/test/expected_dir/matlab1.m/matlab/blanks deleted file mode 100644 index f11c82a..0000000 --- a/test/expected_dir/matlab1.m/matlab/blanks +++ /dev/null @@ -1 +0,0 @@ -9 \ No newline at end of file diff --git a/test/expected_dir/matlab1.m/matlab/code b/test/expected_dir/matlab1.m/matlab/code deleted file mode 100644 index 0c0b7d9..0000000 --- a/test/expected_dir/matlab1.m/matlab/code +++ /dev/null @@ -1,29 +0,0 @@ -r=0.3458; % intrinsic rate of increase--Butterflies at Jasper Ridge -K=846.017; % carrying capacity -theta=1; % nonlinearity in density dependence -sigma2=1.1151; % environmental variance -Nc=94; % starting population size -Nx=20; % quasi-extinction threshold -tmax=20; % time horizon -NumReps=50000; % number of replicate population trajectories -sigma=sqrt(sigma2); -randn('state',sum(100*clock)); % seed the random number generator -N=Nc*ones(1,NumReps); % all NumRep populations start at Nc -NumExtant=NumReps; % all populations are initially extant -Extant=[NumExtant]; % vector for number of extant pops. vs. time -for t=1:tmax, % For each future time, -N=N.*exp( r*( 1-(N/K).^theta )... % the theta logistic model -+ sigma*randn(1,NumExtant) ); % with random environmental effects. -for i=NumExtant:-1:1, % Then, looping over all extant populations, -if N(i)<=Nx, % if at or below quasi-extinction threshold, -N(i)=[]; % delete the population. -end; -end; -NumExtant=length(N); % Count remaining extant populations -Extant=[Extant NumExtant]; % and store the result. -end; -ProbExtinct=(NumReps-Extant)/NumReps; -plot([0:tmax],ProbExtinct) -xlabel('Years into the future'); -ylabel('Cumulative probability of quasi-extinction'); -axis([0 tmax 0 1]); diff --git a/test/expected_dir/matlab1.m/matlab/comment b/test/expected_dir/matlab1.m/matlab/comment deleted file mode 100644 index e9dae13..0000000 --- a/test/expected_dir/matlab1.m/matlab/comment +++ /dev/null @@ -1,16 +0,0 @@ -% PROGRAM theta_logistic.m -% Calculates by simulation the probability that a population -% following the theta logistic model and starting at Nc will fall -% below the quasi-extinction threshold Nx at or before time tmax -% SIMULATION PARAMETERS -% for butterflies (Euphydryas editha bayensis) at Jasper Ridge (population C) -% SIMULATION CODE -% OUTPUT CODE -% ComputeS quasi-extinction probability as the fraction of replicate -% populations that have hit the threshold by each future time, -% and plotS quasi-extinction probability vs. time -% Integrate solution exactly % -% Options=[]; -% [T,true] = ode45(@logistic,[0,20],Nc,Options,r,K,theta); -% subplot(1,2,2) -% plot([1:tmax],P,'r.-',T,true,'g.-') diff --git a/test/expected_dir/metafont.mf b/test/expected_dir/metafont.mf new file mode 100644 index 0000000..a367226 --- /dev/null +++ b/test/expected_dir/metafont.mf @@ -0,0 +1,22 @@ +metafont comment % The (not really) first 20 or so lines from the plain METAFONT base +metafont blank +metafont comment % Unlimited copying and redistribution of this file are permitted as long +metafont comment % as this file is not modified. Modifications are permitted, but only if +metafont comment % the resulting file is not named plain.mf. +metafont blank +metafont code string base_name, base_version; base_name="plain"; base_version="2.71"; +metafont blank +metafont code message "Preloading the plain base, version "&base_version&": preliminaries,"; +metafont blank +metafont code delimiters (); % this makes parentheses behave like parentheses +metafont code def upto = step 1 until enddef; % syntactic sugar +metafont code def downto = step -1 until enddef; +metafont code def exitunless expr c = exitif not c enddef; +metafont code let relax = \; % ignore the word `relax', as in TeX +metafont code let \\ = \; % double relaxation is like single +metafont code def ]] = ] ] enddef; % right brackets should be loners +metafont code def -- = {curl 1}..{curl 1} enddef; +metafont code def --- = .. tension infinity .. enddef; +metafont code def ... = .. tension atleast 1 .. enddef; +metafont blank +metafont code def gobble primary g = enddef; def killtext text t = enddef; diff --git a/test/expected_dir/metafont.mf/metafont/blanks b/test/expected_dir/metafont.mf/metafont/blanks deleted file mode 100644 index 7813681..0000000 --- a/test/expected_dir/metafont.mf/metafont/blanks +++ /dev/null @@ -1 +0,0 @@ -5 \ No newline at end of file diff --git a/test/expected_dir/metafont.mf/metafont/code b/test/expected_dir/metafont.mf/metafont/code deleted file mode 100644 index f3f95b0..0000000 --- a/test/expected_dir/metafont.mf/metafont/code +++ /dev/null @@ -1,13 +0,0 @@ -string base_name, base_version; base_name="plain"; base_version="2.71"; -message "Preloading the plain base, version "&base_version&": preliminaries,"; -delimiters (); % this makes parentheses behave like parentheses -def upto = step 1 until enddef; % syntactic sugar -def downto = step -1 until enddef; -def exitunless expr c = exitif not c enddef; -let relax = \; % ignore the word `relax', as in TeX -let \\ = \; % double relaxation is like single -def ]] = ] ] enddef; % right brackets should be loners -def -- = {curl 1}..{curl 1} enddef; -def --- = .. tension infinity .. enddef; -def ... = .. tension atleast 1 .. enddef; -def gobble primary g = enddef; def killtext text t = enddef; diff --git a/test/expected_dir/metafont.mf/metafont/comment b/test/expected_dir/metafont.mf/metafont/comment deleted file mode 100644 index 06714e9..0000000 --- a/test/expected_dir/metafont.mf/metafont/comment +++ /dev/null @@ -1,4 +0,0 @@ -% The (not really) first 20 or so lines from the plain METAFONT base -% Unlimited copying and redistribution of this file are permitted as long -% as this file is not modified. Modifications are permitted, but only if -% the resulting file is not named plain.mf. diff --git a/test/expected_dir/metapost.mp b/test/expected_dir/metapost.mp new file mode 100644 index 0000000..0698dfb --- /dev/null +++ b/test/expected_dir/metapost.mp @@ -0,0 +1,62 @@ +metapost comment % Sample MetaPost with embedded LaTeX, used as unit test for ohcount +metapost comment % +metapost comment % The MetaPost code is taken of LaTeXLabels.mp from +metapost comment % the excellent MetaPost tutorial by Urs Oswald +metapost comment % http://www.ursoswald.ch/metapost/tutorial.html +metapost comment % +metapost code verbatimtex +tex comment %&latex +tex code \documentclass{article} +tex code \newcommand{\uB}{\upshape{B\'ezier}} % up: upright +tex code \newcommand{\iB}{\itshape{B\'ezier}} % it: italic +tex code \newcommand{\lB}{\slshape{B\'ezier}} % sl: slanted +tex code \newcommand{\cB}{\scshape{B\'ezier}} % sc: small caps +tex code \newfont{\cyr}{wncyr10} +tex code \begin{document} +metapost code etex +metapost blank +metapost code u:=25; % 25 = 25bp = 25 PostScript points = 30/72 in +metapost code wi:=10; % width in units u +metapost code he:=7; % height in units u +metapost code hoehe:=he*u; % height +metapost code breite:=wi*u; % width +metapost code picture lab; +metapost blank +metapost code beginfig(1) +metapost comment % --- Grid --- +metapost code for i=0 upto he: +metapost code draw (0, i*u)--(breite, i*u) withcolor .7white; +metapost code endfor +metapost code for j=0 upto wi: +metapost code draw (j*u, 0)--(j*u, hoehe) withcolor .7white; +metapost code endfor +metapost comment % --- End Grid --- +metapost blank +metapost code draw (0, 0)--(breite, 0)--(breite, hoehe)--(0, hoehe)--cycle; +metapost blank +metapost code for i=0 upto 5: +metapost code draw .5(u, u){dir 20i}..{dir 20i}(9.5u, 4u); +metapost code endfor +metapost blank +metapost code lab:=\thelabel( +metapost code btex +tex code \begin{tabular}{|r|l|l|l|l|} +tex code \hline +tex code \textbf{md} & upright & italic & slanted & smallcaps \\ +tex code \hline +tex code rm & \textrm{\uB} & \textrm{\iB} & \textrm{\lB} &\textrm{\cB} \\ +tex code sf & \textsf{\uB} & \textsf{\iB} &\textsf{\lB} &\textsf{\cB} \\ +tex code tt & \texttt{\uB} & \texttt{\iB} &\texttt{\lB} &\texttt{\cB} \\ +tex code \hline +tex code \end{tabular} +metapost code etex, +metapost code (.5breite, hoehe-1.5u) +metapost code ); +metapost blank +metapost code unfill bbox lab; +metapost code draw lab; +metapost blank +metapost code label.ulft(btex \cyr C\char24 rih, 08.09.2002 etex, (breite, 0)); +metapost code endfig; +metapost blank +metapost code end diff --git a/test/expected_dir/metapost.mp/metapost/blanks b/test/expected_dir/metapost.mp/metapost/blanks deleted file mode 100644 index 301160a..0000000 --- a/test/expected_dir/metapost.mp/metapost/blanks +++ /dev/null @@ -1 +0,0 @@ -8 \ No newline at end of file diff --git a/test/expected_dir/metapost.mp/metapost/code b/test/expected_dir/metapost.mp/metapost/code deleted file mode 100644 index 68ca6e4..0000000 --- a/test/expected_dir/metapost.mp/metapost/code +++ /dev/null @@ -1,29 +0,0 @@ -verbatimtex -etex -u:=25; % 25 = 25bp = 25 PostScript points = 30/72 in -wi:=10; % width in units u -he:=7; % height in units u -hoehe:=he*u; % height -breite:=wi*u; % width -picture lab; -beginfig(1) -for i=0 upto he: -draw (0, i*u)--(breite, i*u) withcolor .7white; -endfor -for j=0 upto wi: -draw (j*u, 0)--(j*u, hoehe) withcolor .7white; -endfor -draw (0, 0)--(breite, 0)--(breite, hoehe)--(0, hoehe)--cycle; -for i=0 upto 5: -draw .5(u, u){dir 20i}..{dir 20i}(9.5u, 4u); -endfor -lab:=\thelabel( -btex -etex, -(.5breite, hoehe-1.5u) -); -unfill bbox lab; -draw lab; -label.ulft(btex \cyr C\char24 rih, 08.09.2002 etex, (breite, 0)); -endfig; -end diff --git a/test/expected_dir/metapost.mp/metapost/comment b/test/expected_dir/metapost.mp/metapost/comment deleted file mode 100644 index 34d49cf..0000000 --- a/test/expected_dir/metapost.mp/metapost/comment +++ /dev/null @@ -1,8 +0,0 @@ -% Sample MetaPost with embedded LaTeX, used as unit test for ohcount -% -% The MetaPost code is taken of LaTeXLabels.mp from -% the excellent MetaPost tutorial by Urs Oswald -% http://www.ursoswald.ch/metapost/tutorial.html -% -% --- Grid --- -% --- End Grid --- diff --git a/test/expected_dir/metapost.mp/tex/blanks b/test/expected_dir/metapost.mp/tex/blanks deleted file mode 100644 index c227083..0000000 --- a/test/expected_dir/metapost.mp/tex/blanks +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/test/expected_dir/metapost.mp/tex/code b/test/expected_dir/metapost.mp/tex/code deleted file mode 100644 index 334d27a..0000000 --- a/test/expected_dir/metapost.mp/tex/code +++ /dev/null @@ -1,16 +0,0 @@ -\documentclass{article} -\newcommand{\uB}{\upshape{B\'ezier}} % up: upright -\newcommand{\iB}{\itshape{B\'ezier}} % it: italic -\newcommand{\lB}{\slshape{B\'ezier}} % sl: slanted -\newcommand{\cB}{\scshape{B\'ezier}} % sc: small caps -\newfont{\cyr}{wncyr10} -\begin{document} -\begin{tabular}{|r|l|l|l|l|} -\hline -\textbf{md} & upright & italic & slanted & smallcaps \\ -\hline -rm & \textrm{\uB} & \textrm{\iB} & \textrm{\lB} &\textrm{\cB} \\ -sf & \textsf{\uB} & \textsf{\iB} &\textsf{\lB} &\textsf{\cB} \\ -tt & \texttt{\uB} & \texttt{\iB} &\texttt{\lB} &\texttt{\cB} \\ -\hline -\end{tabular} diff --git a/test/expected_dir/metapost.mp/tex/comment b/test/expected_dir/metapost.mp/tex/comment deleted file mode 100644 index 68d8154..0000000 --- a/test/expected_dir/metapost.mp/tex/comment +++ /dev/null @@ -1 +0,0 @@ -%&latex diff --git a/test/expected_dir/mxml1.mxml b/test/expected_dir/mxml1.mxml new file mode 100644 index 0000000..3ef2c18 --- /dev/null +++ b/test/expected_dir/mxml1.mxml @@ -0,0 +1,26 @@ +mxml code +mxml blank +mxml code +mxml blank +mxml code +css blank +css code TextArea { +css code backgroundColor: #EEF5EE; +css code } +css blank +mxml code +mxml blank +mxml code +actionscript blank +actionscript code function copy() { +actionscript code destination.text=source.text +actionscript code } +actionscript blank +mxml code +mxml blank +mxml blank +mxml code +mxml code +mxml code +mxml blank +mxml code diff --git a/test/expected_dir/mxml1.mxml/actionscript/code b/test/expected_dir/mxml1.mxml/actionscript/code deleted file mode 100644 index d44d7a2..0000000 --- a/test/expected_dir/mxml1.mxml/actionscript/code +++ /dev/null @@ -1,3 +0,0 @@ -function copy() { -destination.text=source.text -} diff --git a/test/expected_dir/mxml1.mxml/css/code b/test/expected_dir/mxml1.mxml/css/code deleted file mode 100644 index cc0a23d..0000000 --- a/test/expected_dir/mxml1.mxml/css/code +++ /dev/null @@ -1,3 +0,0 @@ -TextArea { -backgroundColor: #EEF5EE; -} diff --git a/test/expected_dir/mxml1.mxml/mxml/code b/test/expected_dir/mxml1.mxml/mxml/code deleted file mode 100644 index 2664220..0000000 --- a/test/expected_dir/mxml1.mxml/mxml/code +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/test/expected_dir/ocaml.ml b/test/expected_dir/ocaml.ml new file mode 100644 index 0000000..1171914 --- /dev/null +++ b/test/expected_dir/ocaml.ml @@ -0,0 +1,10 @@ +ocaml comment (** documentation *) +ocaml code print_string "Hello world!\n";; +ocaml comment (**/**) +ocaml comment (* extra comment *) +ocaml blank +ocaml comment (* multiline +ocaml comment comment*) +ocaml blank +ocaml comment (* recursion in (* a +ocaml comment comment *) to complicate things *) diff --git a/test/expected_dir/ocaml.ml/ocaml/blanks b/test/expected_dir/ocaml.ml/ocaml/blanks deleted file mode 100644 index d8263ee..0000000 --- a/test/expected_dir/ocaml.ml/ocaml/blanks +++ /dev/null @@ -1 +0,0 @@ -2 \ No newline at end of file diff --git a/test/expected_dir/ocaml.ml/ocaml/code b/test/expected_dir/ocaml.ml/ocaml/code deleted file mode 100644 index bb7a2d2..0000000 --- a/test/expected_dir/ocaml.ml/ocaml/code +++ /dev/null @@ -1 +0,0 @@ -print_string "Hello world!\n";; diff --git a/test/expected_dir/ocaml.ml/ocaml/comment b/test/expected_dir/ocaml.ml/ocaml/comment deleted file mode 100644 index 8b700eb..0000000 --- a/test/expected_dir/ocaml.ml/ocaml/comment +++ /dev/null @@ -1,7 +0,0 @@ -(** documentation *) -(**/**) -(* extra comment *) -(* multiline -comment*) -(* recursion in (* a -comment *) to complicate things *) diff --git a/test/expected_dir/pascal1.pas b/test/expected_dir/pascal1.pas new file mode 100644 index 0000000..1ca997c --- /dev/null +++ b/test/expected_dir/pascal1.pas @@ -0,0 +1,112 @@ +pascal comment {*************************************************************** +pascal comment * +pascal comment * Unit Name: pndefs +pascal comment * Purpose : Various Definitions and functions... +pascal comment * Author : Simon Steele +pascal comment * Copyright: This Source Code is Copyright © 1998-2000 Echo +pascal comment * Software and Simon Steele. Please read the license +pascal comment * agreement at www.pnotepad.org/press/psidx.html. +pascal comment **************************************************************} +pascal code unit pndefs; +pascal blank +pascal code interface +pascal blank +pascal code uses SysUtils; +pascal blank +pascal code function CreatePNFile(filename : string; Text : pChar) : Boolean; +pascal code function StripNewLines(aString: string): string; +pascal code procedure ConvertTypes(filename : string); +pascal blank +pascal code const strFileTypes : PChar = ('.txt'); +pascal code strOpenTypes : PChar = ('%2|Text files (*.txt)|*.txt|0|0|0|LOG files (*.log)|*.log|0|0|0|Executable Files (*.exe, *.com, *.dll)|*.exe;*.com;*.dll|0|0|0'); +pascal code sepChar = '|'; +pascal code verChar = '%'; +pascal code CurrFileVer = '2'; +pascal blank +pascal code implementation +pascal blank +pascal code function CreatePNFile(filename : string; Text : pChar) : Boolean; +pascal code var F : TextFile; +pascal code begin +pascal comment {$I-} +pascal code AssignFile(F, filename); +pascal code Rewrite(F); +pascal code Write(F, Text); +pascal code CloseFile(F); +pascal code If IOResult <> 0 Then Result := False +pascal code Else Result := True; +pascal comment {$I+} +pascal code end; +pascal blank +pascal code function StripNewLines(aString: string): string; +pascal code var i : longint; +pascal code begin +pascal code result := ''; +pascal code i := 1; +pascal code while i <= length(aString) do +pascal code begin +pascal code if aString[i] = #13 then result := result + ' ' else +pascal code if aString[i] <> #10 then result := result + aString[i]; +pascal code inc(i); +pascal code end; +pascal code end; +pascal blank +pascal code procedure ConvertTypes(filename : string); +pascal code var t : TextFile; +pascal code s : string; +pascal code ps : string; {part of string} +pascal code Part : integer; +pascal code ipos : integer; +pascal code OutStr : string; +pascal code const Desc = 1; +pascal code Files = 2; +pascal code Parser = 3; +pascal code Unix = 4; +pascal code begin +pascal comment // This assumes that it is being passed one of the old style type definition +pascal comment // files. We'll set the status on the main form to indicate this as well... +pascal code OutStr := VerChar + CurrFileVer; +pascal code if not fileexists(filename) then +pascal code begin +pascal code CreatePNFile(filename, strOpenTypes); +pascal code exit; +pascal code end; +pascal code Assignfile(t, FileName); +pascal code Reset(t); +pascal code repeat +pascal code Readln(t, s) +pascal code until (Length(s) > 0) or EOF(t); +pascal code CloseFile(t); +pascal code if s = '' then Exit; +pascal code part := Desc; +pascal code repeat +pascal code iPos := Pos(SepChar, s); +pascal code if (iPos = 0) and (Length(s) > 0) then +pascal code begin +pascal code ps := s; +pascal code s := ''; +pascal code end else +pascal code ps := Copy(s, 1, ipos - 1); +pascal code s := Copy(S, ipos + 1, Length(s)); +pascal code case part of +pascal code Desc : begin +pascal code OutStr := OutStr + SepChar + ps; +pascal code part := Files; +pascal code end; +pascal code Files : begin +pascal code OutStr := OutStr + SepChar + ps; +pascal code part := Parser; +pascal code end; +pascal code Parser : begin +pascal code OutStr := OutStr + SepChar + ps + SepChar + '0' + SepChar + '0'; +pascal code part := Desc; +pascal code end; +pascal code end; +pascal code until Length(s) < 1; +pascal code Assignfile(t, filename); +pascal code Rewrite(t); +pascal code Write(t, OutStr); +pascal code CloseFile(t); +pascal code end; +pascal blank +pascal code end. diff --git a/test/expected_dir/pascal1.pas/pascal/blanks b/test/expected_dir/pascal1.pas/pascal/blanks deleted file mode 100644 index f11c82a..0000000 --- a/test/expected_dir/pascal1.pas/pascal/blanks +++ /dev/null @@ -1 +0,0 @@ -9 \ No newline at end of file diff --git a/test/expected_dir/pascal1.pas/pascal/code b/test/expected_dir/pascal1.pas/pascal/code deleted file mode 100644 index 263e32f..0000000 --- a/test/expected_dir/pascal1.pas/pascal/code +++ /dev/null @@ -1,90 +0,0 @@ -unit pndefs; -interface -uses SysUtils; -function CreatePNFile(filename : string; Text : pChar) : Boolean; -function StripNewLines(aString: string): string; -procedure ConvertTypes(filename : string); -const strFileTypes : PChar = ('.txt'); -strOpenTypes : PChar = ('%2|Text files (*.txt)|*.txt|0|0|0|LOG files (*.log)|*.log|0|0|0|Executable Files (*.exe, *.com, *.dll)|*.exe;*.com;*.dll|0|0|0'); -sepChar = '|'; -verChar = '%'; -CurrFileVer = '2'; -implementation -function CreatePNFile(filename : string; Text : pChar) : Boolean; -var F : TextFile; -begin -AssignFile(F, filename); -Rewrite(F); -Write(F, Text); -CloseFile(F); -If IOResult <> 0 Then Result := False -Else Result := True; -end; -function StripNewLines(aString: string): string; -var i : longint; -begin -result := ''; -i := 1; -while i <= length(aString) do -begin -if aString[i] = #13 then result := result + ' ' else -if aString[i] <> #10 then result := result + aString[i]; -inc(i); -end; -end; -procedure ConvertTypes(filename : string); -var t : TextFile; -s : string; -ps : string; {part of string} -Part : integer; -ipos : integer; -OutStr : string; -const Desc = 1; -Files = 2; -Parser = 3; -Unix = 4; -begin -OutStr := VerChar + CurrFileVer; -if not fileexists(filename) then -begin -CreatePNFile(filename, strOpenTypes); -exit; -end; -Assignfile(t, FileName); -Reset(t); -repeat -Readln(t, s) -until (Length(s) > 0) or EOF(t); -CloseFile(t); -if s = '' then Exit; -part := Desc; -repeat -iPos := Pos(SepChar, s); -if (iPos = 0) and (Length(s) > 0) then -begin -ps := s; -s := ''; -end else -ps := Copy(s, 1, ipos - 1); -s := Copy(S, ipos + 1, Length(s)); -case part of -Desc : begin -OutStr := OutStr + SepChar + ps; -part := Files; -end; -Files : begin -OutStr := OutStr + SepChar + ps; -part := Parser; -end; -Parser : begin -OutStr := OutStr + SepChar + ps + SepChar + '0' + SepChar + '0'; -part := Desc; -end; -end; -until Length(s) < 1; -Assignfile(t, filename); -Rewrite(t); -Write(t, OutStr); -CloseFile(t); -end; -end. diff --git a/test/expected_dir/pascal1.pas/pascal/comment b/test/expected_dir/pascal1.pas/pascal/comment deleted file mode 100644 index de8ff05..0000000 --- a/test/expected_dir/pascal1.pas/pascal/comment +++ /dev/null @@ -1,13 +0,0 @@ -{*************************************************************** -* -* Unit Name: pndefs -* Purpose : Various Definitions and functions... -* Author : Simon Steele -* Copyright: This Source Code is Copyright © 1998-2000 Echo -* Software and Simon Steele. Please read the license -* agreement at www.pnotepad.org/press/psidx.html. -**************************************************************} -{$I-} -{$I+} -// This assumes that it is being passed one of the old style type definition -// files. We'll set the status on the main form to indicate this as well... diff --git a/test/expected_dir/pascal2.pp b/test/expected_dir/pascal2.pp new file mode 100644 index 0000000..1ca997c --- /dev/null +++ b/test/expected_dir/pascal2.pp @@ -0,0 +1,112 @@ +pascal comment {*************************************************************** +pascal comment * +pascal comment * Unit Name: pndefs +pascal comment * Purpose : Various Definitions and functions... +pascal comment * Author : Simon Steele +pascal comment * Copyright: This Source Code is Copyright © 1998-2000 Echo +pascal comment * Software and Simon Steele. Please read the license +pascal comment * agreement at www.pnotepad.org/press/psidx.html. +pascal comment **************************************************************} +pascal code unit pndefs; +pascal blank +pascal code interface +pascal blank +pascal code uses SysUtils; +pascal blank +pascal code function CreatePNFile(filename : string; Text : pChar) : Boolean; +pascal code function StripNewLines(aString: string): string; +pascal code procedure ConvertTypes(filename : string); +pascal blank +pascal code const strFileTypes : PChar = ('.txt'); +pascal code strOpenTypes : PChar = ('%2|Text files (*.txt)|*.txt|0|0|0|LOG files (*.log)|*.log|0|0|0|Executable Files (*.exe, *.com, *.dll)|*.exe;*.com;*.dll|0|0|0'); +pascal code sepChar = '|'; +pascal code verChar = '%'; +pascal code CurrFileVer = '2'; +pascal blank +pascal code implementation +pascal blank +pascal code function CreatePNFile(filename : string; Text : pChar) : Boolean; +pascal code var F : TextFile; +pascal code begin +pascal comment {$I-} +pascal code AssignFile(F, filename); +pascal code Rewrite(F); +pascal code Write(F, Text); +pascal code CloseFile(F); +pascal code If IOResult <> 0 Then Result := False +pascal code Else Result := True; +pascal comment {$I+} +pascal code end; +pascal blank +pascal code function StripNewLines(aString: string): string; +pascal code var i : longint; +pascal code begin +pascal code result := ''; +pascal code i := 1; +pascal code while i <= length(aString) do +pascal code begin +pascal code if aString[i] = #13 then result := result + ' ' else +pascal code if aString[i] <> #10 then result := result + aString[i]; +pascal code inc(i); +pascal code end; +pascal code end; +pascal blank +pascal code procedure ConvertTypes(filename : string); +pascal code var t : TextFile; +pascal code s : string; +pascal code ps : string; {part of string} +pascal code Part : integer; +pascal code ipos : integer; +pascal code OutStr : string; +pascal code const Desc = 1; +pascal code Files = 2; +pascal code Parser = 3; +pascal code Unix = 4; +pascal code begin +pascal comment // This assumes that it is being passed one of the old style type definition +pascal comment // files. We'll set the status on the main form to indicate this as well... +pascal code OutStr := VerChar + CurrFileVer; +pascal code if not fileexists(filename) then +pascal code begin +pascal code CreatePNFile(filename, strOpenTypes); +pascal code exit; +pascal code end; +pascal code Assignfile(t, FileName); +pascal code Reset(t); +pascal code repeat +pascal code Readln(t, s) +pascal code until (Length(s) > 0) or EOF(t); +pascal code CloseFile(t); +pascal code if s = '' then Exit; +pascal code part := Desc; +pascal code repeat +pascal code iPos := Pos(SepChar, s); +pascal code if (iPos = 0) and (Length(s) > 0) then +pascal code begin +pascal code ps := s; +pascal code s := ''; +pascal code end else +pascal code ps := Copy(s, 1, ipos - 1); +pascal code s := Copy(S, ipos + 1, Length(s)); +pascal code case part of +pascal code Desc : begin +pascal code OutStr := OutStr + SepChar + ps; +pascal code part := Files; +pascal code end; +pascal code Files : begin +pascal code OutStr := OutStr + SepChar + ps; +pascal code part := Parser; +pascal code end; +pascal code Parser : begin +pascal code OutStr := OutStr + SepChar + ps + SepChar + '0' + SepChar + '0'; +pascal code part := Desc; +pascal code end; +pascal code end; +pascal code until Length(s) < 1; +pascal code Assignfile(t, filename); +pascal code Rewrite(t); +pascal code Write(t, OutStr); +pascal code CloseFile(t); +pascal code end; +pascal blank +pascal code end. diff --git a/test/expected_dir/pascal2.pp/pascal/blanks b/test/expected_dir/pascal2.pp/pascal/blanks deleted file mode 100644 index f11c82a..0000000 --- a/test/expected_dir/pascal2.pp/pascal/blanks +++ /dev/null @@ -1 +0,0 @@ -9 \ No newline at end of file diff --git a/test/expected_dir/pascal2.pp/pascal/code b/test/expected_dir/pascal2.pp/pascal/code deleted file mode 100644 index 263e32f..0000000 --- a/test/expected_dir/pascal2.pp/pascal/code +++ /dev/null @@ -1,90 +0,0 @@ -unit pndefs; -interface -uses SysUtils; -function CreatePNFile(filename : string; Text : pChar) : Boolean; -function StripNewLines(aString: string): string; -procedure ConvertTypes(filename : string); -const strFileTypes : PChar = ('.txt'); -strOpenTypes : PChar = ('%2|Text files (*.txt)|*.txt|0|0|0|LOG files (*.log)|*.log|0|0|0|Executable Files (*.exe, *.com, *.dll)|*.exe;*.com;*.dll|0|0|0'); -sepChar = '|'; -verChar = '%'; -CurrFileVer = '2'; -implementation -function CreatePNFile(filename : string; Text : pChar) : Boolean; -var F : TextFile; -begin -AssignFile(F, filename); -Rewrite(F); -Write(F, Text); -CloseFile(F); -If IOResult <> 0 Then Result := False -Else Result := True; -end; -function StripNewLines(aString: string): string; -var i : longint; -begin -result := ''; -i := 1; -while i <= length(aString) do -begin -if aString[i] = #13 then result := result + ' ' else -if aString[i] <> #10 then result := result + aString[i]; -inc(i); -end; -end; -procedure ConvertTypes(filename : string); -var t : TextFile; -s : string; -ps : string; {part of string} -Part : integer; -ipos : integer; -OutStr : string; -const Desc = 1; -Files = 2; -Parser = 3; -Unix = 4; -begin -OutStr := VerChar + CurrFileVer; -if not fileexists(filename) then -begin -CreatePNFile(filename, strOpenTypes); -exit; -end; -Assignfile(t, FileName); -Reset(t); -repeat -Readln(t, s) -until (Length(s) > 0) or EOF(t); -CloseFile(t); -if s = '' then Exit; -part := Desc; -repeat -iPos := Pos(SepChar, s); -if (iPos = 0) and (Length(s) > 0) then -begin -ps := s; -s := ''; -end else -ps := Copy(s, 1, ipos - 1); -s := Copy(S, ipos + 1, Length(s)); -case part of -Desc : begin -OutStr := OutStr + SepChar + ps; -part := Files; -end; -Files : begin -OutStr := OutStr + SepChar + ps; -part := Parser; -end; -Parser : begin -OutStr := OutStr + SepChar + ps + SepChar + '0' + SepChar + '0'; -part := Desc; -end; -end; -until Length(s) < 1; -Assignfile(t, filename); -Rewrite(t); -Write(t, OutStr); -CloseFile(t); -end; -end. diff --git a/test/expected_dir/pascal2.pp/pascal/comment b/test/expected_dir/pascal2.pp/pascal/comment deleted file mode 100644 index de8ff05..0000000 --- a/test/expected_dir/pascal2.pp/pascal/comment +++ /dev/null @@ -1,13 +0,0 @@ -{*************************************************************** -* -* Unit Name: pndefs -* Purpose : Various Definitions and functions... -* Author : Simon Steele -* Copyright: This Source Code is Copyright © 1998-2000 Echo -* Software and Simon Steele. Please read the license -* agreement at www.pnotepad.org/press/psidx.html. -**************************************************************} -{$I-} -{$I+} -// This assumes that it is being passed one of the old style type definition -// files. We'll set the status on the main form to indicate this as well... diff --git a/test/expected_dir/perl.cgi b/test/expected_dir/perl.cgi new file mode 100644 index 0000000..c5f2bf9 --- /dev/null +++ b/test/expected_dir/perl.cgi @@ -0,0 +1,66 @@ +perl comment #!/usr/bin/perl -w +perl blank +perl comment # ajaxCheckbox.pl - a script to test Ajax functionality +perl blank +perl code use strict; +perl code use CGI qw/:standard/; +perl code use CGI::Ajax; +perl code use DBI; +perl blank +perl comment # --- database authenication +perl code my $dbh = do 'db.inc'; +perl blank +perl code my $query = q{ SELECT project.project_id, project.name, project.phase, prio.prio, +perl code HEX((255 - prio.prio)) AS hex, begun, tags +perl code FROM project JOIN prio +perl code ON (project.project_id = prio.project_id) +perl code WHERE completed < 1 +perl code ORDER BY prio.prio DESC LIMIT 3}; +perl blank +perl code my $sth = $dbh->prepare($query); +perl code $sth->execute(); +perl code my $result = $dbh->selectall_arrayref($sth); +perl blank +perl code my $cgi = new CGI; +perl code my $pjx = new CGI::Ajax( 'toStruck' => \&perl_func ); +perl code print $pjx->build_html( $cgi, \&Show_HTML); +perl blank +perl code sub Show_HTML { +perl blank +perl code use CGI qw/:standard/; +perl blank +perl code my $html = < +perl code +perl code +perl code This is the lastest source version +perl code +perl code +perl code +perl code

Carrot Queue

Priority List  |   +perl code Add a listing  |  

Project listing

+perl code HEAD +perl blank +perl code foreach my $row (@$result) { +perl code $html .= ""; +perl code $html .= "
" . @$row[1] . "

"; +perl code } +perl blank +perl comment # you can append stuff to the HTML this way +perl code $html .= ""; +perl blank +perl code return $html; +perl code } +perl blank +perl code sub perl_func { +perl code my $input=shift; +perl blank +perl comment # if onClick the change the style +perl code if ($input eq "ON") { +perl code $input=""; +perl code } else { +perl code $input =""; +perl code } +perl code } diff --git a/test/expected_dir/perl.cgi/perl/blanks b/test/expected_dir/perl.cgi/perl/blanks deleted file mode 100644 index da2d398..0000000 --- a/test/expected_dir/perl.cgi/perl/blanks +++ /dev/null @@ -1 +0,0 @@ -14 \ No newline at end of file diff --git a/test/expected_dir/perl.cgi/perl/code b/test/expected_dir/perl.cgi/perl/code deleted file mode 100644 index 4957a35..0000000 --- a/test/expected_dir/perl.cgi/perl/code +++ /dev/null @@ -1,47 +0,0 @@ -use strict; -use CGI qw/:standard/; -use CGI::Ajax; -use DBI; -my $dbh = do 'db.inc'; -my $query = q{ SELECT project.project_id, project.name, project.phase, prio.prio, -HEX((255 - prio.prio)) AS hex, begun, tags -FROM project JOIN prio -ON (project.project_id = prio.project_id) -WHERE completed < 1 -ORDER BY prio.prio DESC LIMIT 3}; -my $sth = $dbh->prepare($query); -$sth->execute(); -my $result = $dbh->selectall_arrayref($sth); -my $cgi = new CGI; -my $pjx = new CGI::Ajax( 'toStruck' => \&perl_func ); -print $pjx->build_html( $cgi, \&Show_HTML); -sub Show_HTML { -use CGI qw/:standard/; -my $html = < - - -This is the lastest source version - - - -

Carrot Queue

Priority List  |   -Add a listing  |  

Project listing

-HEAD -foreach my $row (@$result) { -$html .= ""; -$html .= "
" . @$row[1] . "

"; -} -$html .= ""; -return $html; -} -sub perl_func { -my $input=shift; -if ($input eq "ON") { -$input=""; -} else { -$input =""; -} -} diff --git a/test/expected_dir/perl.cgi/perl/comment b/test/expected_dir/perl.cgi/perl/comment deleted file mode 100644 index 8844721..0000000 --- a/test/expected_dir/perl.cgi/perl/comment +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/perl -w -# ajaxCheckbox.pl - a script to test Ajax functionality -# --- database authenication -# you can append stuff to the HTML this way -# if onClick the change the style diff --git a/test/expected_dir/perl1.pl b/test/expected_dir/perl1.pl new file mode 100644 index 0000000..60744e5 --- /dev/null +++ b/test/expected_dir/perl1.pl @@ -0,0 +1,72 @@ +perl comment #!/usr/bin/perl +perl comment # Conserve bandwidth - put a copy of Dilbert on your intranet. +perl comment # Run every morning with cron - after about 7am Eastern +perl comment ######################################################## +perl code use Time::ParseDate; +perl code use Time::CTime; +perl code use LWP::Simple; +perl blank +perl comment # Where do you want the image put? +perl code $dir="/usr/local/etc/httpd/htdocs/Dilbert"; +perl comment # $dir = "c:/httpd/htdocs/Dilbert"; +perl code $location ="$dir/dilbert.gif"; +perl blank +perl code $_ = get("http://www.unitedmedia.com/comics/dilbert/index.html"); +perl blank +perl comment # These next 4 lines will change every time they change the +perl comment # page layout on the Dilbert site. Check back on my web site +perl comment # if things suddenly stop working +perl code s/^.*strip_left\.gif//s; +perl code s/^.*?HREF=\"//s; +perl code s/\">.*$//s; +perl code $line = "http://www.unitedmedia.com" . $_; +perl blank +perl comment # Back up yesterday's image: +perl comment # get the number +perl code open (ID,"$dir/id"); +perl code $id=; +perl code close ID; +perl blank +perl code $id++; +perl code $id=~s/\n$//; +perl code `mv $location $dir/dilbert.$id.gif`; +perl comment # If you're using this on NT, you may want to replace 'mv' +perl comment # with 'move'. +perl blank +perl code open (ID,">$dir/id"); +perl code print ID "$id"; +perl code close ID; +perl blank +perl comment # Now get the actual image +perl code $_ = get($line); +perl blank +perl code open (FILE, ">$location"); +perl code binmode FILE; # Important for NT +perl code print FILE; +perl code close FILE; +perl blank +perl comment # Now I want to update the index.html file +perl code open (FILE, "$dir/index.html"); +perl code @index=; +perl code close FILE; +perl blank +perl code $yesterday = parsedate('yesterday'); +perl code $printdate = strftime('%a, %b %d', localtime($yesterday)); +perl blank +perl code open (FILE, ">$dir/index.html"); +perl code for (@index) { +perl code if (/INSERT HERE/) { +perl code print FILE "$_"; +perl code print FILE "$printdate\n"; +perl code if (($id % 5) == 0) {print FILE "\n"} +perl code } +perl code else {print FILE "$_"}; +perl code } # End for +perl code close FILE; +perl blank +perl comment # Start with an index.html file containing ... +perl comment # +perl comment # +perl comment #
+perl comment # ... +perl comment # And whatever else you want on the page. diff --git a/test/expected_dir/perl1.pl/perl/blanks b/test/expected_dir/perl1.pl/perl/blanks deleted file mode 100644 index 3cacc0b..0000000 --- a/test/expected_dir/perl1.pl/perl/blanks +++ /dev/null @@ -1 +0,0 @@ -12 \ No newline at end of file diff --git a/test/expected_dir/perl1.pl/perl/code b/test/expected_dir/perl1.pl/perl/code deleted file mode 100644 index 768585f..0000000 --- a/test/expected_dir/perl1.pl/perl/code +++ /dev/null @@ -1,45 +0,0 @@ -use Time::ParseDate; -use Time::CTime; -use LWP::Simple; -$dir="/usr/local/etc/httpd/htdocs/Dilbert"; -$location ="$dir/dilbert.gif"; -$_ = get("http://www.unitedmedia.com/comics/dilbert/index.html"); -s/^.*strip_left\.gif//s; -s/^.*?HREF=\"//s; -s/\">.*$//s; -$line = "http://www.unitedmedia.com" . $_; -# Back up yesterday's image: -# get the number -open (ID,"$dir/id"); -$id=; -close ID; -$id++; -$id=~s/\n$//; -`mv $location $dir/dilbert.$id.gif`; -# If you're using this on NT, you may want to replace 'mv' -# with 'move'. -open (ID,">$dir/id"); -print ID "$id"; -close ID; -# Now get the actual image -$_ = get($line); -open (FILE, ">$location"); -binmode FILE; # Important for NT -print FILE; -close FILE; -# Now I want to update the index.html file -open (FILE, "$dir/index.html"); -@index=; -close FILE; -$yesterday = parsedate('yesterday'); -$printdate = strftime('%a, %b %d', localtime($yesterday)); -open (FILE, ">$dir/index.html"); -for (@index) { -if (/INSERT HERE/) { -print FILE "$_"; -print FILE "$printdate\n"; -if (($id % 5) == 0) {print FILE "\n"} -} -else {print FILE "$_"}; -} # End for -close FILE; diff --git a/test/expected_dir/perl1.pl/perl/comment b/test/expected_dir/perl1.pl/perl/comment deleted file mode 100644 index d9fab5e..0000000 --- a/test/expected_dir/perl1.pl/perl/comment +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/perl -# Conserve bandwidth - put a copy of Dilbert on your intranet. -# Run every morning with cron - after about 7am Eastern -######################################################## -# Where do you want the image put? -# $dir = "c:/httpd/htdocs/Dilbert"; -# These next 4 lines will change every time they change the -# page layout on the Dilbert site. Check back on my web site -# if things suddenly stop working -# Start with an index.html file containing ... -# -# -#
-# ... -# And whatever else you want on the page. diff --git a/test/expected_dir/perl_module.pm b/test/expected_dir/perl_module.pm new file mode 100644 index 0000000..f62cbe3 --- /dev/null +++ b/test/expected_dir/perl_module.pm @@ -0,0 +1,1191 @@ +perl code package PAR::Dist; +perl code require Exporter; +perl code use vars qw/$VERSION @ISA @EXPORT @EXPORT_OK/; +perl blank +perl code $VERSION = '0.29'; +perl code @ISA = 'Exporter'; +perl code @EXPORT = qw/ +perl code blib_to_par +perl code install_par +perl code uninstall_par +perl code sign_par +perl code verify_par +perl code merge_par +perl code remove_man +perl code get_meta +perl code generate_blib_stub +perl code /; +perl blank +perl code @EXPORT_OK = qw/ +perl code parse_dist_name +perl code contains_binaries +perl code /; +perl blank +perl code use strict; +perl code use Carp qw/carp croak/; +perl code use File::Spec; +perl blank +perl comment =head1 NAME +perl blank +perl comment PAR::Dist - Create and manipulate PAR distributions +perl blank +perl comment =head1 VERSION +perl blank +perl comment This document describes version 0.29 of PAR::Dist, released Feb 6, 2008. +perl blank +perl comment =head1 SYNOPSIS +perl blank +perl comment As a shell command: +perl blank +perl comment % perl -MPAR::Dist -eblib_to_par +perl blank +perl comment In programs: +perl blank +perl comment use PAR::Dist; +perl blank +perl comment my $dist = blib_to_par(); # make a PAR file using ./blib/ +perl comment install_par($dist); # install it into the system +perl comment uninstall_par($dist); # uninstall it from the system +perl comment sign_par($dist); # sign it using Module::Signature +perl comment verify_par($dist); # verify it using Module::Signature +perl blank +perl comment install_par("http://foo.com/DBI-1.37-MSWin32-5.8.0.par"); # works too +perl comment install_par("http://foo.com/DBI-1.37"); # auto-appends archname + perlver +perl comment install_par("cpan://SMUELLER/PAR-Packer-0.975"); # uses CPAN author directory +perl blank +perl comment =head1 DESCRIPTION +perl blank +perl comment This module creates and manipulates I. They are +perl comment architecture-specific B files, containing everything under F +perl comment of CPAN distributions after their C or C stage, a +perl comment F describing metadata of the original CPAN distribution, +perl comment and a F detailing all files within it. Digitally signed PAR +perl comment distributions will also contain a F file. +perl blank +perl comment The naming convention for such distributions is: +perl blank +perl comment $NAME-$VERSION-$ARCH-$PERL_VERSION.par +perl blank +perl comment For example, C corresponds to the +perl comment 0.01 release of C on CPAN, built for perl 5.8.0 running on +perl comment C. +perl blank +perl comment =head1 FUNCTIONS +perl blank +perl comment Several functions are exported by default. Unless otherwise noted, +perl comment they can take either a hash of +perl comment named arguments, a single argument (taken as C<$path> by C +perl comment and C<$dist> by other functions), or no arguments (in which case +perl comment the first PAR file in the current directory is used). +perl blank +perl comment Therefore, under a directory containing only a single F, all +perl comment invocations below are equivalent: +perl blank +perl comment % perl -MPAR::Dist -e"install_par( dist => 'test.par' )" +perl comment % perl -MPAR::Dist -e"install_par( 'test.par' )" +perl comment % perl -MPAR::Dist -einstall_par; +perl blank +perl comment If C<$dist> resembles a URL, C is called to mirror it +perl comment locally under C<$ENV{PAR_TEMP}> (or C<$TEMP/par/> if unspecified), and the +perl comment function will act on the fetched local file instead. If the URL begins +perl comment with C, it will be expanded automatically to the author's CPAN +perl comment directory (e.g. C). +perl blank +perl comment If C<$dist> does not have a file extension beginning with a letter or +perl comment underscore, a dash and C<$suffix> ($ARCH-$PERL_VERSION.par by default) +perl comment will be appended to it. +perl blank +perl comment =head2 blib_to_par +perl blank +perl comment Takes key/value pairs as parameters or a single parameter indicating the +perl comment path that contains the F subdirectory. +perl blank +perl comment Builds a PAR distribution from the F subdirectory under C, or +perl comment under the current directory if unspecified. If F does not exist, +perl comment it automatically runs F, F, F or F to +perl comment create it. +perl blank +perl comment Returns the filename or the generated PAR distribution. +perl blank +perl comment Valid parameters are: +perl blank +perl comment =over 2 +perl blank +perl comment =item path +perl blank +perl comment Sets the path which contains the F subdirectory from which the PAR +perl comment distribution will be generated. +perl blank +perl comment =item name, version, suffix +perl blank +perl comment These attributes set the name, version and platform specific suffix +perl comment of the distribution. Name and version can be automatically +perl comment determined from the distributions F or F files. +perl blank +perl comment The suffix is generated from your architecture name and your version of +perl comment perl by default. +perl blank +perl comment =item dist +perl blank +perl comment The output filename for the PAR distribution. +perl blank +perl comment =back +perl blank +perl comment =cut +perl blank +perl code sub blib_to_par { +perl code @_ = (path => @_) if @_ == 1; +perl blank +perl code my %args = @_; +perl code require Config; +perl blank +perl blank +perl comment # don't use 'my $foo ... if ...' it creates a static variable! +perl code my $dist; +perl code my $path = $args{path}; +perl code $dist = File::Spec->rel2abs($args{dist}) if $args{dist}; +perl code my $name = $args{name}; +perl code my $version = $args{version}; +perl code my $suffix = $args{suffix} || "$Config::Config{archname}-$Config::Config{version}.par"; +perl code my $cwd; +perl blank +perl code if (defined $path) { +perl code require Cwd; +perl code $cwd = Cwd::cwd(); +perl code chdir $path; +perl code } +perl blank +perl code _build_blib() unless -d "blib"; +perl blank +perl code my @files; +perl code open MANIFEST, ">", File::Spec->catfile("blib", "MANIFEST") or die $!; +perl code open META, ">", File::Spec->catfile("blib", "META.yml") or die $!; +perl blank +perl code require File::Find; +perl code File::Find::find( sub { +perl code next unless $File::Find::name; +perl code (-r && !-d) and push ( @files, substr($File::Find::name, 5) ); +perl code } , 'blib' ); +perl blank +perl code print MANIFEST join( +perl code "\n", +perl code ' ', +perl code (sort @files), +perl code q( # ) +perl code ); +perl code close MANIFEST; +perl blank +perl code if (open(OLD_META, "META.yml")) { +perl code while () { +perl code if (/^distribution_type:/) { +perl code print META "distribution_type: par\n"; +perl code } +perl code else { +perl code print META $_; +perl code } +perl blank +perl code if (/^name:\s+(.*)/) { +perl code $name ||= $1; +perl code $name =~ s/::/-/g; +perl code } +perl code elsif (/^version:\s+.*Module::Build::Version/) { +perl code while () { +perl code /^\s+original:\s+(.*)/ or next; +perl code $version ||= $1; +perl code last; +perl code } +perl code } +perl code elsif (/^version:\s+(.*)/) { +perl code $version ||= $1; +perl code } +perl code } +perl code close OLD_META; +perl code close META; +perl code } +perl blank +perl code if ((!$name or !$version) and open(MAKEFILE, "Makefile")) { +perl code while () { +perl code if (/^DISTNAME\s+=\s+(.*)$/) { +perl code $name ||= $1; +perl code } +perl code elsif (/^VERSION\s+=\s+(.*)$/) { +perl code $version ||= $1; +perl code } +perl code } +perl code } +perl blank +perl code if (not defined($name) or not defined($version)) { +perl comment # could not determine name or version. Error. +perl code my $what; +perl code if (not defined $name) { +perl code $what = 'name'; +perl code $what .= ' and version' if not defined $version; +perl code } +perl code elsif (not defined $version) { +perl code $what = 'version'; +perl code } +perl blank +perl code carp("I was unable to determine the $what of the PAR distribution. Please create a Makefile or META.yml file from which we can infer the information or just specify the missing information as an option to blib_to_par."); +perl code return(); +perl code } +perl blank +perl code $name =~ s/\s+$//; +perl code $version =~ s/\s+$//; +perl blank +perl code my $file = "$name-$version-$suffix"; +perl code unlink $file if -f $file; +perl blank +perl code print META << "YAML" if fileno(META); +perl code name: $name +perl code version: $version +perl code build_requires: {} +perl code conflicts: {} +perl code dist_name: $file +perl code distribution_type: par +perl code dynamic_config: 0 +perl code generated_by: 'PAR::Dist version $PAR::Dist::VERSION' +perl code license: unknown +perl code YAML +perl code close META; +perl blank +perl code mkdir('blib', 0777); +perl code chdir('blib'); +perl code _zip(dist => File::Spec->catfile(File::Spec->updir, $file)) or die $!; +perl code chdir(File::Spec->updir); +perl blank +perl code unlink File::Spec->catfile("blib", "MANIFEST"); +perl code unlink File::Spec->catfile("blib", "META.yml"); +perl blank +perl code $dist ||= File::Spec->catfile($cwd, $file) if $cwd; +perl blank +perl code if ($dist and $file ne $dist) { +perl code rename( $file => $dist ); +perl code $file = $dist; +perl code } +perl blank +perl code my $pathname = File::Spec->rel2abs($file); +perl code if ($^O eq 'MSWin32') { +perl code $pathname =~ s!\\!/!g; +perl code $pathname =~ s!:!|!g; +perl code }; +perl code print << "."; +perl code Successfully created binary distribution '$file'. +perl code Its contents are accessible in compliant browsers as: +perl code jar:file://$pathname!/MANIFEST +perl code . +perl blank +perl code chdir $cwd if $cwd; +perl code return $file; +perl code } +perl blank +perl code sub _build_blib { +perl code if (-e 'Build') { +perl code system($^X, "Build"); +perl code } +perl code elsif (-e 'Makefile') { +perl code system($Config::Config{make}); +perl code } +perl code elsif (-e 'Build.PL') { +perl code system($^X, "Build.PL"); +perl code system($^X, "Build"); +perl code } +perl code elsif (-e 'Makefile.PL') { +perl code system($^X, "Makefile.PL"); +perl code system($Config::Config{make}); +perl code } +perl code } +perl blank +perl comment =head2 install_par +perl blank +perl comment Installs a PAR distribution into the system, using +perl comment C. +perl blank +perl comment Valid parameters are: +perl blank +perl comment =over 2 +perl blank +perl comment =item dist +perl blank +perl comment The .par file to install. The heuristics outlined in the B +perl comment section above apply. +perl blank +perl comment =item prefix +perl blank +perl comment This string will be prepended to all installation paths. +perl comment If it isn't specified, the environment variable +perl comment C is used as a prefix. +perl blank +perl comment =back +perl blank +perl comment Additionally, you can use several parameters to change the default +perl comment installation destinations. You don't usually have to worry about this +perl comment unless you are installing into a user-local directory. +perl comment The following section outlines the parameter names and default settings: +perl blank +perl comment Parameter From To +perl comment inst_lib blib/lib $Config{installsitelib} (*) +perl comment inst_archlib blib/arch $Config{installsitearch} +perl comment inst_script blib/script $Config{installscript} +perl comment inst_bin blib/bin $Config{installbin} +perl comment inst_man1dir blib/man1 $Config{installman1dir} +perl comment inst_man3dir blib/man3 $Config{installman3dir} +perl comment packlist_read $Config{sitearchexp}/auto/$name/.packlist +perl comment packlist_write $Config{installsitearch}/auto/$name/.packlist +perl blank +perl comment The C parameter is used to control where the F<.packlist> +perl comment file is written to. (Necessary for uninstallation.) +perl comment The C parameter specifies a .packlist file to merge in if +perl comment it exists. By setting any of the above installation targets to C, +perl comment you can remove that target altogether. For example, passing +perl comment C undef, inst_man3dir => undef> means that the contained +perl comment manual pages won't be installed. This is not available for the packlists. +perl blank +perl comment Finally, you may specify a C parameter. Its value should be +perl comment a reference to a hash of custom installation targets such as +perl blank +perl comment custom_targets => { 'blib/my_data' => '/some/path/my_data' } +perl blank +perl comment You can use this to install the F<.par> archives contents to arbitrary +perl comment locations. +perl blank +perl comment If only a single parameter is given, it is treated as the C +perl comment parameter. +perl blank +perl comment =cut +perl blank +perl code sub install_par { +perl code my %args = &_args; +perl code _install_or_uninstall(%args, action => 'install'); +perl code } +perl blank +perl comment =head2 uninstall_par +perl blank +perl comment Uninstalls all previously installed contents of a PAR distribution, +perl comment using C. +perl blank +perl comment Takes almost the same parameters as C, but naturally, +perl comment the installation target parameters do not apply. The only exception +perl comment to this is the C parameter which specifies the +perl comment F<.packlist> file to read the list of installed files from. +perl comment It defaults to C<$Config::Config{installsitearch}/auto/$name/.packlist>. +perl blank +perl comment =cut +perl blank +perl code sub uninstall_par { +perl code my %args = &_args; +perl code _install_or_uninstall(%args, action => 'uninstall'); +perl code } +perl blank +perl code sub _install_or_uninstall { +perl code my %args = &_args; +perl code my $name = $args{name}; +perl code my $action = $args{action}; +perl blank +perl code my %ENV_copy = %ENV; +perl code $ENV{PERL_INSTALL_ROOT} = $args{prefix} if defined $args{prefix}; +perl blank +perl code require Cwd; +perl code my $old_dir = Cwd::cwd(); +perl blank +perl code my ($dist, $tmpdir) = _unzip_to_tmpdir( dist => $args{dist}, subdir => 'blib' ); +perl blank +perl code if ( open (META, File::Spec->catfile('blib', 'META.yml')) ) { +perl code while () { +perl code next unless /^name:\s+(.*)/; +perl code $name = $1; +perl code $name =~ s/\s+$//; +perl code last; +perl code } +perl code close META; +perl code } +perl code return if not defined $name or $name eq ''; +perl blank +perl code if (-d 'script') { +perl code require ExtUtils::MY; +perl code foreach my $file (glob("script/*")) { +perl code next unless -T $file; +perl code ExtUtils::MY->fixin($file); +perl code chmod(0555, $file); +perl code } +perl code } +perl blank +perl code $name =~ s{::|-}{/}g; +perl code require ExtUtils::Install; +perl blank +perl code my $rv; +perl code if ($action eq 'install') { +perl code my $target = _installation_target( File::Spec->curdir, $name, \%args ); +perl code my $custom_targets = $args{custom_targets} || {}; +perl code $target->{$_} = $custom_targets->{$_} foreach keys %{$custom_targets}; +perl blank +perl code $rv = ExtUtils::Install::install($target, 1, 0, 0); +perl code } +perl code elsif ($action eq 'uninstall') { +perl code require Config; +perl code $rv = ExtUtils::Install::uninstall( +perl code $args{packlist_read}||"$Config::Config{installsitearch}/auto/$name/.packlist" +perl code ); +perl code } +perl blank +perl code %ENV = %ENV_copy; +perl blank +perl code chdir($old_dir); +perl code File::Path::rmtree([$tmpdir]); +perl code return $rv; +perl code } +perl blank +perl comment # Returns the default installation target as used by +perl comment # ExtUtils::Install::install(). First parameter should be the base +perl comment # directory containing the blib/ we're installing from. +perl comment # Second parameter should be the name of the distribution for the packlist +perl comment # paths. Third parameter may be a hash reference with user defined keys for +perl comment # the target hash. In fact, any contents that do not start with 'inst_' are +perl comment # skipped. +perl code sub _installation_target { +perl code require Config; +perl code my $dir = shift; +perl code my $name = shift; +perl code my $user = shift || {}; +perl blank +perl comment # accepted sources (and user overrides) +perl code my %sources = ( +perl code inst_lib => File::Spec->catdir($dir,"blib","lib"), +perl code inst_archlib => File::Spec->catdir($dir,"blib","arch"), +perl code inst_bin => File::Spec->catdir($dir,'blib','bin'), +perl code inst_script => File::Spec->catdir($dir,'blib','script'), +perl code inst_man1dir => File::Spec->catdir($dir,'blib','man1'), +perl code inst_man3dir => File::Spec->catdir($dir,'blib','man3'), +perl code packlist_read => 'read', +perl code packlist_write => 'write', +perl code ); +perl blank +perl blank +perl comment # default targets +perl code my $target = { +perl code read => $Config::Config{sitearchexp}."/auto/$name/.packlist", +perl code write => $Config::Config{installsitearch}."/auto/$name/.packlist", +perl code $sources{inst_lib} +perl code => (_directory_not_empty($sources{inst_archlib})) +perl code ? $Config::Config{installsitearch} +perl code : $Config::Config{installsitelib}, +perl code $sources{inst_archlib} => $Config::Config{installsitearch}, +perl code $sources{inst_bin} => $Config::Config{installbin} , +perl code $sources{inst_script} => $Config::Config{installscript}, +perl code $sources{inst_man1dir} => $Config::Config{installman1dir}, +perl code $sources{inst_man3dir} => $Config::Config{installman3dir}, +perl code }; +perl blank +perl comment # Included for future support for ${flavour}perl external lib installation +perl comment # if ($Config::Config{flavour_perl}) { +perl comment # my $ext = File::Spec->catdir($dir, 'blib', 'ext'); +perl comment # # from => to +perl comment # $sources{inst_external_lib} = File::Spec->catdir($ext, 'lib'); +perl comment # $sources{inst_external_bin} = File::Spec->catdir($ext, 'bin'); +perl comment # $sources{inst_external_include} = File::Spec->catdir($ext, 'include'); +perl comment # $sources{inst_external_src} = File::Spec->catdir($ext, 'src'); +perl comment # $target->{ $sources{inst_external_lib} } = $Config::Config{flavour_install_lib}; +perl comment # $target->{ $sources{inst_external_bin} } = $Config::Config{flavour_install_bin}; +perl comment # $target->{ $sources{inst_external_include} } = $Config::Config{flavour_install_include}; +perl comment # $target->{ $sources{inst_external_src} } = $Config::Config{flavour_install_src}; +perl comment # } +perl blank +perl comment # insert user overrides +perl code foreach my $key (keys %$user) { +perl code my $value = $user->{$key}; +perl code if (not defined $value and $key ne 'packlist_read' and $key ne 'packlist_write') { +perl comment # undef means "remove" +perl code delete $target->{ $sources{$key} }; +perl code } +perl code elsif (exists $sources{$key}) { +perl comment # overwrite stuff, don't let the user create new entries +perl code $target->{ $sources{$key} } = $value; +perl code } +perl code } +perl blank +perl code return $target; +perl code } +perl blank +perl code sub _directory_not_empty { +perl code require File::Find; +perl code my($dir) = @_; +perl code my $files = 0; +perl code File::Find::find(sub { +perl code return if $_ eq ".exists"; +perl code if (-f) { +perl code $File::Find::prune++; +perl code $files = 1; +perl code } +perl code }, $dir); +perl code return $files; +perl code } +perl blank +perl comment =head2 sign_par +perl blank +perl comment Digitally sign a PAR distribution using C or B, +perl comment via B. +perl blank +perl comment =cut +perl blank +perl code sub sign_par { +perl code my %args = &_args; +perl code _verify_or_sign(%args, action => 'sign'); +perl code } +perl blank +perl comment =head2 verify_par +perl blank +perl comment Verify the digital signature of a PAR distribution using C or +perl comment B, via B. +perl blank +perl comment Returns a boolean value indicating whether verification passed; C<$!> +perl comment is set to the return code of C. +perl blank +perl comment =cut +perl blank +perl code sub verify_par { +perl code my %args = &_args; +perl code $! = _verify_or_sign(%args, action => 'verify'); +perl code return ( $! == Module::Signature::SIGNATURE_OK() ); +perl code } +perl blank +perl comment =head2 merge_par +perl blank +perl comment Merge two or more PAR distributions into one. First argument must +perl comment be the name of the distribution you want to merge all others into. +perl comment Any following arguments will be interpreted as the file names of +perl comment further PAR distributions to merge into the first one. +perl blank +perl comment merge_par('foo.par', 'bar.par', 'baz.par') +perl blank +perl comment This will merge the distributions C, C and C +perl comment into the distribution C. C will be overwritten! +perl comment The original META.yml of C is retained. +perl blank +perl comment =cut +perl blank +perl code sub merge_par { +perl code my $base_par = shift; +perl code my @additional_pars = @_; +perl code require Cwd; +perl code require File::Copy; +perl code require File::Path; +perl code require File::Find; +perl blank +perl comment # parameter checking +perl code if (not defined $base_par) { +perl code croak "First argument to merge_par() must be the .par archive to modify."; +perl code } +perl blank +perl code if (not -f $base_par or not -r _ or not -w _) { +perl code croak "'$base_par' is not a file or you do not have enough permissions to read and modify it."; +perl code } +perl blank +perl code foreach (@additional_pars) { +perl code if (not -f $_ or not -r _) { +perl code croak "'$_' is not a file or you do not have enough permissions to read it."; +perl code } +perl code } +perl blank +perl comment # The unzipping will change directories. Remember old dir. +perl code my $old_cwd = Cwd::cwd(); +perl blank +perl comment # Unzip the base par to a temp. dir. +perl code (undef, my $base_dir) = _unzip_to_tmpdir( +perl code dist => $base_par, subdir => 'blib' +perl code ); +perl code my $blibdir = File::Spec->catdir($base_dir, 'blib'); +perl blank +perl comment # move the META.yml to the (main) temp. dir. +perl code File::Copy::move( +perl code File::Spec->catfile($blibdir, 'META.yml'), +perl code File::Spec->catfile($base_dir, 'META.yml') +perl code ); +perl comment # delete (incorrect) MANIFEST +perl code unlink File::Spec->catfile($blibdir, 'MANIFEST'); +perl blank +perl comment # extract additional pars and merge +perl code foreach my $par (@additional_pars) { +perl comment # restore original directory because the par path +perl comment # might have been relative! +perl code chdir($old_cwd); +perl code (undef, my $add_dir) = _unzip_to_tmpdir( +perl code dist => $par +perl code ); +perl code my @files; +perl code my @dirs; +perl comment # I hate File::Find +perl comment # And I hate writing portable code, too. +perl code File::Find::find( +perl code {wanted =>sub { +perl code my $file = $File::Find::name; +perl code push @files, $file if -f $file; +perl code push @dirs, $file if -d _; +perl code }}, +perl code $add_dir +perl code ); +perl code my ($vol, $subdir, undef) = File::Spec->splitpath( $add_dir, 1); +perl code my @dir = File::Spec->splitdir( $subdir ); +perl blank +perl comment # merge directory structure +perl code foreach my $dir (@dirs) { +perl code my ($v, $d, undef) = File::Spec->splitpath( $dir, 1 ); +perl code my @d = File::Spec->splitdir( $d ); +perl code shift @d foreach @dir; # remove tmp dir from path +perl code my $target = File::Spec->catdir( $blibdir, @d ); +perl code mkdir($target); +perl code } +perl blank +perl comment # merge files +perl code foreach my $file (@files) { +perl code my ($v, $d, $f) = File::Spec->splitpath( $file ); +perl code my @d = File::Spec->splitdir( $d ); +perl code shift @d foreach @dir; # remove tmp dir from path +perl code my $target = File::Spec->catfile( +perl code File::Spec->catdir( $blibdir, @d ), +perl code $f +perl code ); +perl code File::Copy::copy($file, $target) +perl code or die "Could not copy '$file' to '$target': $!"; +perl blank +perl code } +perl code chdir($old_cwd); +perl code File::Path::rmtree([$add_dir]); +perl code } +perl blank +perl comment # delete (copied) MANIFEST and META.yml +perl code unlink File::Spec->catfile($blibdir, 'MANIFEST'); +perl code unlink File::Spec->catfile($blibdir, 'META.yml'); +perl blank +perl code chdir($base_dir); +perl code my $resulting_par_file = Cwd::abs_path(blib_to_par()); +perl code chdir($old_cwd); +perl code File::Copy::move($resulting_par_file, $base_par); +perl blank +perl code File::Path::rmtree([$base_dir]); +perl code } +perl blank +perl blank +perl comment =head2 remove_man +perl blank +perl comment Remove the man pages from a PAR distribution. Takes one named +perl comment parameter: I which should be the name (and path) of the +perl comment PAR distribution file. The calling conventions outlined in +perl comment the C section above apply. +perl blank +perl comment The PAR archive will be +perl comment extracted, stripped of all C and C subdirectories +perl comment and then repackaged into the original file. +perl blank +perl comment =cut +perl blank +perl code sub remove_man { +perl code my %args = &_args; +perl code my $par = $args{dist}; +perl code require Cwd; +perl code require File::Copy; +perl code require File::Path; +perl code require File::Find; +perl blank +perl comment # parameter checking +perl code if (not defined $par) { +perl code croak "First argument to remove_man() must be the .par archive to modify."; +perl code } +perl blank +perl code if (not -f $par or not -r _ or not -w _) { +perl code croak "'$par' is not a file or you do not have enough permissions to read and modify it."; +perl code } +perl blank +perl comment # The unzipping will change directories. Remember old dir. +perl code my $old_cwd = Cwd::cwd(); +perl blank +perl comment # Unzip the base par to a temp. dir. +perl code (undef, my $base_dir) = _unzip_to_tmpdir( +perl code dist => $par, subdir => 'blib' +perl code ); +perl code my $blibdir = File::Spec->catdir($base_dir, 'blib'); +perl blank +perl comment # move the META.yml to the (main) temp. dir. +perl code File::Copy::move( +perl code File::Spec->catfile($blibdir, 'META.yml'), +perl code File::Spec->catfile($base_dir, 'META.yml') +perl code ); +perl comment # delete (incorrect) MANIFEST +perl code unlink File::Spec->catfile($blibdir, 'MANIFEST'); +perl blank +perl code opendir DIRECTORY, 'blib' or die $!; +perl code my @dirs = grep { /^blib\/(?:man\d*|html)$/ } +perl code grep { -d $_ } +perl code map { File::Spec->catfile('blib', $_) } +perl code readdir DIRECTORY; +perl code close DIRECTORY; +perl blank +perl code File::Path::rmtree(\@dirs); +perl blank +perl code chdir($base_dir); +perl code my $resulting_par_file = Cwd::abs_path(blib_to_par()); +perl code chdir($old_cwd); +perl code File::Copy::move($resulting_par_file, $par); +perl blank +perl code File::Path::rmtree([$base_dir]); +perl code } +perl blank +perl blank +perl comment =head2 get_meta +perl blank +perl comment Opens a PAR archive and extracts the contained META.yml file. +perl comment Returns the META.yml file as a string. +perl blank +perl comment Takes one named parameter: I. If only one parameter is +perl comment passed, it is treated as the I parameter. (Have a look +perl comment at the description in the C section above.) +perl blank +perl comment Returns undef if no PAR archive or no META.yml within the +perl comment archive were found. +perl blank +perl comment =cut +perl blank +perl code sub get_meta { +perl code my %args = &_args; +perl code my $dist = $args{dist}; +perl code return undef if not defined $dist or not -r $dist; +perl code require Cwd; +perl code require File::Path; +perl blank +perl comment # The unzipping will change directories. Remember old dir. +perl code my $old_cwd = Cwd::cwd(); +perl blank +perl comment # Unzip the base par to a temp. dir. +perl code (undef, my $base_dir) = _unzip_to_tmpdir( +perl code dist => $dist, subdir => 'blib' +perl code ); +perl code my $blibdir = File::Spec->catdir($base_dir, 'blib'); +perl blank +perl code my $meta = File::Spec->catfile($blibdir, 'META.yml'); +perl blank +perl code if (not -r $meta) { +perl code return undef; +perl code } +perl blank +perl code open FH, '<', $meta +perl code or die "Could not open file '$meta' for reading: $!"; +perl blank +perl code local $/ = undef; +perl code my $meta_text = ; +perl code close FH; +perl blank +perl code chdir($old_cwd); +perl blank +perl code File::Path::rmtree([$base_dir]); +perl blank +perl code return $meta_text; +perl code } +perl blank +perl blank +perl blank +perl code sub _unzip { +perl code my %args = &_args; +perl code my $dist = $args{dist}; +perl code my $path = $args{path} || File::Spec->curdir; +perl code return unless -f $dist; +perl blank +perl comment # Try fast unzipping first +perl code if (eval { require Archive::Unzip::Burst; 1 }) { +perl code my $return = Archive::Unzip::Burst::unzip($dist, $path); +perl code return if $return; # true return value == error (a la system call) +perl code } +perl comment # Then slow unzipping +perl code if (eval { require Archive::Zip; 1 }) { +perl code my $zip = Archive::Zip->new; +perl code local %SIG; +perl code $SIG{__WARN__} = sub { print STDERR $_[0] unless $_[0] =~ /\bstat\b/ }; +perl code return unless $zip->read($dist) == Archive::Zip::AZ_OK() +perl code and $zip->extractTree('', "$path/") == Archive::Zip::AZ_OK(); +perl code } +perl comment # Then fall back to the system +perl code else { +perl code return if system(unzip => $dist, '-d', $path); +perl code } +perl blank +perl code return 1; +perl code } +perl blank +perl code sub _zip { +perl code my %args = &_args; +perl code my $dist = $args{dist}; +perl blank +perl code if (eval { require Archive::Zip; 1 }) { +perl code my $zip = Archive::Zip->new; +perl code $zip->addTree( File::Spec->curdir, '' ); +perl code $zip->writeToFileNamed( $dist ) == Archive::Zip::AZ_OK() or die $!; +perl code } +perl code else { +perl code system(qw(zip -r), $dist, File::Spec->curdir) and die $!; +perl code } +perl code } +perl blank +perl blank +perl comment # This sub munges the arguments to most of the PAR::Dist functions +perl comment # into a hash. On the way, it downloads PAR archives as necessary, etc. +perl code sub _args { +perl comment # default to the first .par in the CWD +perl code if (not @_) { +perl code @_ = (glob('*.par'))[0]; +perl code } +perl blank +perl comment # single argument => it's a distribution file name or URL +perl code @_ = (dist => @_) if @_ == 1; +perl blank +perl code my %args = @_; +perl code $args{name} ||= $args{dist}; +perl blank +perl comment # If we are installing from an URL, we want to munge the +perl comment # distribution name so that it is in form "Module-Name" +perl code if (defined $args{name}) { +perl code $args{name} =~ s/^\w+:\/\///; +perl code my @elems = parse_dist_name($args{name}); +perl comment # @elems is name, version, arch, perlversion +perl code if (defined $elems[0]) { +perl code $args{name} = $elems[0]; +perl code } +perl code else { +perl code $args{name} =~ s/^.*\/([^\/]+)$/$1/; +perl code $args{name} =~ s/^([0-9A-Za-z_-]+)-\d+\..+$/$1/; +perl code } +perl code } +perl blank +perl comment # append suffix if there is none +perl code if ($args{dist} and not $args{dist} =~ /\.[a-zA-Z_][^.]*$/) { +perl code require Config; +perl code my $suffix = $args{suffix}; +perl code $suffix ||= "$Config::Config{archname}-$Config::Config{version}.par"; +perl code $args{dist} .= "-$suffix"; +perl code } +perl blank +perl comment # download if it's an URL +perl code if ($args{dist} and $args{dist} =~ m!^\w+://!) { +perl code $args{dist} = _fetch(dist => $args{dist}) +perl code } +perl blank +perl code return %args; +perl code } +perl blank +perl blank +perl comment # Download PAR archive, but only if necessary (mirror!) +perl code my %escapes; +perl code sub _fetch { +perl code my %args = @_; +perl blank +perl code if ($args{dist} =~ s/^file:\/\///) { +perl code return $args{dist} if -e $args{dist}; +perl code return; +perl code } +perl code require LWP::Simple; +perl blank +perl code $ENV{PAR_TEMP} ||= File::Spec->catdir(File::Spec->tmpdir, 'par'); +perl code mkdir $ENV{PAR_TEMP}, 0777; +perl code %escapes = map { chr($_) => sprintf("%%%02X", $_) } 0..255 unless %escapes; +perl blank +perl code $args{dist} =~ s{^cpan://((([a-zA-Z])[a-zA-Z])[-_a-zA-Z]+)/} +perl code {http://www.cpan.org/modules/by-authors/id/\U$3/$2/$1\E/}; +perl blank +perl code my $file = $args{dist}; +perl code $file =~ s/([^\w\.])/$escapes{$1}/g; +perl code $file = File::Spec->catfile( $ENV{PAR_TEMP}, $file); +perl code my $rc = LWP::Simple::mirror( $args{dist}, $file ); +perl blank +perl code if (!LWP::Simple::is_success($rc) and $rc != 304) { +perl code die "Error $rc: ", LWP::Simple::status_message($rc), " ($args{dist})\n"; +perl code } +perl blank +perl code return $file if -e $file; +perl code return; +perl code } +perl blank +perl code sub _verify_or_sign { +perl code my %args = &_args; +perl blank +perl code require File::Path; +perl code require Module::Signature; +perl code die "Module::Signature version 0.25 required" +perl code unless Module::Signature->VERSION >= 0.25; +perl blank +perl code require Cwd; +perl code my $cwd = Cwd::cwd(); +perl code my $action = $args{action}; +perl code my ($dist, $tmpdir) = _unzip_to_tmpdir($args{dist}); +perl code $action ||= (-e 'SIGNATURE' ? 'verify' : 'sign'); +perl blank +perl code if ($action eq 'sign') { +perl code open FH, '>SIGNATURE' unless -e 'SIGNATURE'; +perl code open FH, 'MANIFEST' or die $!; +perl blank +perl code local $/; +perl code my $out = ; +perl code if ($out !~ /^SIGNATURE(?:\s|$)/m) { +perl code $out =~ s/^(?!\s)/SIGNATURE\n/m; +perl code open FH, '>MANIFEST' or die $!; +perl code print FH $out; +perl code } +perl code close FH; +perl blank +perl code $args{overwrite} = 1 unless exists $args{overwrite}; +perl code $args{skip} = 0 unless exists $args{skip}; +perl code } +perl blank +perl code my $rv = Module::Signature->can($action)->(%args); +perl code _zip(dist => $dist) if $action eq 'sign'; +perl code File::Path::rmtree([$tmpdir]); +perl blank +perl code chdir($cwd); +perl code return $rv; +perl code } +perl blank +perl code sub _unzip_to_tmpdir { +perl code my %args = &_args; +perl blank +perl code require File::Temp; +perl blank +perl code my $dist = File::Spec->rel2abs($args{dist}); +perl code my $tmpdirname = File::Spec->catdir(File::Spec->tmpdir, "parXXXXX"); +perl code my $tmpdir = File::Temp::mkdtemp($tmpdirname) +perl code or die "Could not create temporary directory from template '$tmpdirname': $!"; +perl code my $path = $tmpdir; +perl code $path = File::Spec->catdir($tmpdir, $args{subdir}) if defined $args{subdir}; +perl code _unzip(dist => $dist, path => $path); +perl blank +perl code chdir $tmpdir; +perl code return ($dist, $tmpdir); +perl code } +perl blank +perl blank +perl blank +perl comment =head2 parse_dist_name +perl blank +perl comment First argument must be a distribution file name. The file name +perl comment is parsed into I, I, +perl comment I, and I. +perl blank +perl comment Returns the results as a list in the above order. +perl comment If any or all of the above cannot be determined, returns undef instead +perl comment of the undetermined elements. +perl blank +perl comment Supported formats are: +perl blank +perl comment Math-Symbolic-0.502-x86_64-linux-gnu-thread-multi-5.8.7 +perl blank +perl comment Math-Symbolic-0.502 +perl blank +perl comment The ".tar.gz" or ".par" extensions as well as any +perl comment preceding paths are stripped before parsing. Starting with C +perl comment 0.22, versions containing a preceding C are parsed correctly. +perl blank +perl comment This function is not exported by default. +perl blank +perl comment =cut +perl blank +perl code sub parse_dist_name { +perl code my $file = shift; +perl code return(undef, undef, undef, undef) if not defined $file; +perl blank +perl code (undef, undef, $file) = File::Spec->splitpath($file); +perl blank +perl code my $version = qr/v?(?:\d+(?:_\d+)?|\d*(?:\.\d+(?:_\d+)?)+)/; +perl code $file =~ s/\.(?:par|tar\.gz|tar)$//i; +perl code my @elem = split /-/, $file; +perl code my (@dn, $dv, @arch, $pv); +perl code while (@elem) { +perl code my $e = shift @elem; +perl code if ( +perl code $e =~ /^$version$/o +perl code and not(# if not next token also a version +perl comment # (assumes an arch string doesnt start with a version...) +perl code @elem and $elem[0] =~ /^$version$/o +perl code ) +perl code ) { +perl blank +perl code $dv = $e; +perl code last; +perl code } +perl code push @dn, $e; +perl code } +perl blank +perl code my $dn; +perl code $dn = join('-', @dn) if @dn; +perl blank +perl code if (not @elem) { +perl code return( $dn, $dv, undef, undef); +perl code } +perl blank +perl code while (@elem) { +perl code my $e = shift @elem; +perl code if ($e =~ /^$version|any_version$/) { +perl code $pv = $e; +perl code last; +perl code } +perl code push @arch, $e; +perl code } +perl blank +perl code my $arch; +perl code $arch = join('-', @arch) if @arch; +perl blank +perl code return($dn, $dv, $arch, $pv); +perl code } +perl blank +perl comment =head2 generate_blib_stub +perl blank +perl comment Creates a F subdirectory in the current directory +perl comment and prepares a F with meta information for a +perl comment new PAR distribution. First argument should be the name of the +perl comment PAR distribution in a format understood by C. +perl comment Alternatively, named arguments resembling those of +perl comment C are accepted. +perl blank +perl comment After running C and injecting files into +perl comment the F directory, you can create a PAR distribution +perl comment using C. +perl comment This function is useful for creating custom PAR distributions +perl comment from scratch. (I.e. not from an unpacked CPAN distribution) +perl comment Example: +perl blank +perl comment use PAR::Dist; +perl comment use File::Copy 'copy'; +perl blank +perl comment generate_blib_stub( +perl comment name => 'MyApp', version => '1.00' +perl comment ); +perl comment copy('MyApp.pm', 'blib/lib/MyApp.pm'); +perl comment blib_to_par(); # generates the .par file! +perl blank +perl comment C will not overwrite existing files. +perl blank +perl comment =cut +perl blank +perl code sub generate_blib_stub { +perl code my %args = &_args; +perl code my $dist = $args{dist}; +perl code require Config; +perl blank +perl code my $name = $args{name}; +perl code my $version = $args{version}; +perl code my $suffix = $args{suffix}; +perl blank +perl code my ($parse_name, $parse_version, $archname, $perlversion) +perl code = parse_dist_name($dist); +perl blank +perl code $name ||= $parse_name; +perl code $version ||= $parse_version; +perl code $suffix = "$archname-$perlversion" +perl code if (not defined $suffix or $suffix eq '') +perl code and $archname and $perlversion; +perl blank +perl code $suffix ||= "$Config::Config{archname}-$Config::Config{version}"; +perl code if ( grep { not defined $_ } ($name, $version, $suffix) ) { +perl code warn "Could not determine distribution meta information from distribution name '$dist'"; +perl code return(); +perl code } +perl code $suffix =~ s/\.par$//; +perl blank +perl code if (not -f 'META.yml') { +perl code open META, '>', 'META.yml' +perl code or die "Could not open META.yml file for writing: $!"; +perl code print META << "YAML" if fileno(META); +perl code name: $name +perl code version: $version +perl code build_requires: {} +perl code conflicts: {} +perl code dist_name: $name-$version-$suffix.par +perl code distribution_type: par +perl code dynamic_config: 0 +perl code generated_by: 'PAR::Dist version $PAR::Dist::VERSION' +perl code license: unknown +perl code YAML +perl code close META; +perl code } +perl blank +perl code mkdir('blib'); +perl code mkdir(File::Spec->catdir('blib', 'lib')); +perl code mkdir(File::Spec->catdir('blib', 'script')); +perl blank +perl code return 1; +perl code } +perl blank +perl blank +perl comment =head2 contains_binaries +perl blank +perl comment This function is not exported by default. +perl blank +perl comment Opens a PAR archive tries to determine whether that archive +perl comment contains platform-specific binary code. +perl blank +perl comment Takes one named parameter: I. If only one parameter is +perl comment passed, it is treated as the I parameter. (Have a look +perl comment at the description in the C section above.) +perl blank +perl comment Throws a fatal error if the PAR archive could not be found. +perl blank +perl comment Returns one if the PAR was found to contain binary code +perl comment and zero otherwise. +perl blank +perl comment =cut +perl blank +perl code sub contains_binaries { +perl code require File::Find; +perl code my %args = &_args; +perl code my $dist = $args{dist}; +perl code return undef if not defined $dist or not -r $dist; +perl code require Cwd; +perl code require File::Path; +perl blank +perl comment # The unzipping will change directories. Remember old dir. +perl code my $old_cwd = Cwd::cwd(); +perl blank +perl comment # Unzip the base par to a temp. dir. +perl code (undef, my $base_dir) = _unzip_to_tmpdir( +perl code dist => $dist, subdir => 'blib' +perl code ); +perl code my $blibdir = File::Spec->catdir($base_dir, 'blib'); +perl code my $archdir = File::Spec->catdir($blibdir, 'arch'); +perl blank +perl code my $found = 0; +perl blank +perl code File::Find::find( +perl code sub { +perl code $found++ if -f $_ and not /^\.exists$/; +perl code }, +perl code $archdir +perl code ); +perl blank +perl code chdir($old_cwd); +perl blank +perl code File::Path::rmtree([$base_dir]); +perl blank +perl code return $found ? 1 : 0; +perl code } +perl blank +perl code 1; +perl blank +perl comment =head1 SEE ALSO +perl blank +perl comment L, L, L, L +perl blank +perl comment =head1 AUTHORS +perl blank +perl comment Audrey Tang Ecpan@audreyt.orgE 2003-2007 +perl blank +perl comment Steffen Mueller Esmueller@cpan.orgE 2005-2007 +perl blank +perl comment PAR has a mailing list, Epar@perl.orgE, that you can write to; +perl comment send an empty mail to Epar-subscribe@perl.orgE to join the list +perl comment and participate in the discussion. +perl blank +perl comment Please send bug reports to Ebug-par@rt.cpan.orgE. +perl blank +perl comment =head1 COPYRIGHT +perl blank +perl comment Copyright 2003-2007 by Audrey Tang Eautrijus@autrijus.orgE. +perl blank +perl comment This program is free software; you can redistribute it and/or modify it +perl comment under the same terms as Perl itself. +perl blank +perl comment See L +perl blank +perl comment =cut diff --git a/test/expected_dir/perl_module.pm/perl/blanks b/test/expected_dir/perl_module.pm/perl/blanks deleted file mode 100644 index 44dfb1d..0000000 --- a/test/expected_dir/perl_module.pm/perl/blanks +++ /dev/null @@ -1 +0,0 @@ -264 \ No newline at end of file diff --git a/test/expected_dir/perl_module.pm/perl/code b/test/expected_dir/perl_module.pm/perl/code deleted file mode 100644 index 48eac67..0000000 --- a/test/expected_dir/perl_module.pm/perl/code +++ /dev/null @@ -1,642 +0,0 @@ -package PAR::Dist; -require Exporter; -use vars qw/$VERSION @ISA @EXPORT @EXPORT_OK/; -$VERSION = '0.29'; -@ISA = 'Exporter'; -@EXPORT = qw/ -blib_to_par -install_par -uninstall_par -sign_par -verify_par -merge_par -remove_man -get_meta -generate_blib_stub -/; -@EXPORT_OK = qw/ -parse_dist_name -contains_binaries -/; -use strict; -use Carp qw/carp croak/; -use File::Spec; -sub blib_to_par { -@_ = (path => @_) if @_ == 1; -my %args = @_; -require Config; -my $dist; -my $path = $args{path}; -$dist = File::Spec->rel2abs($args{dist}) if $args{dist}; -my $name = $args{name}; -my $version = $args{version}; -my $suffix = $args{suffix} || "$Config::Config{archname}-$Config::Config{version}.par"; -my $cwd; -if (defined $path) { -require Cwd; -$cwd = Cwd::cwd(); -chdir $path; -} -_build_blib() unless -d "blib"; -my @files; -open MANIFEST, ">", File::Spec->catfile("blib", "MANIFEST") or die $!; -open META, ">", File::Spec->catfile("blib", "META.yml") or die $!; -require File::Find; -File::Find::find( sub { -next unless $File::Find::name; -(-r && !-d) and push ( @files, substr($File::Find::name, 5) ); -} , 'blib' ); -print MANIFEST join( -"\n", -' ', -(sort @files), -q( # ) -); -close MANIFEST; -if (open(OLD_META, "META.yml")) { -while () { -if (/^distribution_type:/) { -print META "distribution_type: par\n"; -} -else { -print META $_; -} -if (/^name:\s+(.*)/) { -$name ||= $1; -$name =~ s/::/-/g; -} -elsif (/^version:\s+.*Module::Build::Version/) { -while () { -/^\s+original:\s+(.*)/ or next; -$version ||= $1; -last; -} -} -elsif (/^version:\s+(.*)/) { -$version ||= $1; -} -} -close OLD_META; -close META; -} -if ((!$name or !$version) and open(MAKEFILE, "Makefile")) { -while () { -if (/^DISTNAME\s+=\s+(.*)$/) { -$name ||= $1; -} -elsif (/^VERSION\s+=\s+(.*)$/) { -$version ||= $1; -} -} -} -if (not defined($name) or not defined($version)) { -my $what; -if (not defined $name) { -$what = 'name'; -$what .= ' and version' if not defined $version; -} -elsif (not defined $version) { -$what = 'version'; -} -carp("I was unable to determine the $what of the PAR distribution. Please create a Makefile or META.yml file from which we can infer the information or just specify the missing information as an option to blib_to_par."); -return(); -} -$name =~ s/\s+$//; -$version =~ s/\s+$//; -my $file = "$name-$version-$suffix"; -unlink $file if -f $file; -print META << "YAML" if fileno(META); -name: $name -version: $version -build_requires: {} -conflicts: {} -dist_name: $file -distribution_type: par -dynamic_config: 0 -generated_by: 'PAR::Dist version $PAR::Dist::VERSION' -license: unknown -YAML -close META; -mkdir('blib', 0777); -chdir('blib'); -_zip(dist => File::Spec->catfile(File::Spec->updir, $file)) or die $!; -chdir(File::Spec->updir); -unlink File::Spec->catfile("blib", "MANIFEST"); -unlink File::Spec->catfile("blib", "META.yml"); -$dist ||= File::Spec->catfile($cwd, $file) if $cwd; -if ($dist and $file ne $dist) { -rename( $file => $dist ); -$file = $dist; -} -my $pathname = File::Spec->rel2abs($file); -if ($^O eq 'MSWin32') { -$pathname =~ s!\\!/!g; -$pathname =~ s!:!|!g; -}; -print << "."; -Successfully created binary distribution '$file'. -Its contents are accessible in compliant browsers as: -jar:file://$pathname!/MANIFEST -. -chdir $cwd if $cwd; -return $file; -} -sub _build_blib { -if (-e 'Build') { -system($^X, "Build"); -} -elsif (-e 'Makefile') { -system($Config::Config{make}); -} -elsif (-e 'Build.PL') { -system($^X, "Build.PL"); -system($^X, "Build"); -} -elsif (-e 'Makefile.PL') { -system($^X, "Makefile.PL"); -system($Config::Config{make}); -} -} -sub install_par { -my %args = &_args; -_install_or_uninstall(%args, action => 'install'); -} -sub uninstall_par { -my %args = &_args; -_install_or_uninstall(%args, action => 'uninstall'); -} -sub _install_or_uninstall { -my %args = &_args; -my $name = $args{name}; -my $action = $args{action}; -my %ENV_copy = %ENV; -$ENV{PERL_INSTALL_ROOT} = $args{prefix} if defined $args{prefix}; -require Cwd; -my $old_dir = Cwd::cwd(); -my ($dist, $tmpdir) = _unzip_to_tmpdir( dist => $args{dist}, subdir => 'blib' ); -if ( open (META, File::Spec->catfile('blib', 'META.yml')) ) { -while () { -next unless /^name:\s+(.*)/; -$name = $1; -$name =~ s/\s+$//; -last; -} -close META; -} -return if not defined $name or $name eq ''; -if (-d 'script') { -require ExtUtils::MY; -foreach my $file (glob("script/*")) { -next unless -T $file; -ExtUtils::MY->fixin($file); -chmod(0555, $file); -} -} -$name =~ s{::|-}{/}g; -require ExtUtils::Install; -my $rv; -if ($action eq 'install') { -my $target = _installation_target( File::Spec->curdir, $name, \%args ); -my $custom_targets = $args{custom_targets} || {}; -$target->{$_} = $custom_targets->{$_} foreach keys %{$custom_targets}; -$rv = ExtUtils::Install::install($target, 1, 0, 0); -} -elsif ($action eq 'uninstall') { -require Config; -$rv = ExtUtils::Install::uninstall( -$args{packlist_read}||"$Config::Config{installsitearch}/auto/$name/.packlist" -); -} -%ENV = %ENV_copy; -chdir($old_dir); -File::Path::rmtree([$tmpdir]); -return $rv; -} -sub _installation_target { -require Config; -my $dir = shift; -my $name = shift; -my $user = shift || {}; -my %sources = ( -inst_lib => File::Spec->catdir($dir,"blib","lib"), -inst_archlib => File::Spec->catdir($dir,"blib","arch"), -inst_bin => File::Spec->catdir($dir,'blib','bin'), -inst_script => File::Spec->catdir($dir,'blib','script'), -inst_man1dir => File::Spec->catdir($dir,'blib','man1'), -inst_man3dir => File::Spec->catdir($dir,'blib','man3'), -packlist_read => 'read', -packlist_write => 'write', -); -my $target = { -read => $Config::Config{sitearchexp}."/auto/$name/.packlist", -write => $Config::Config{installsitearch}."/auto/$name/.packlist", -$sources{inst_lib} -=> (_directory_not_empty($sources{inst_archlib})) -? $Config::Config{installsitearch} -: $Config::Config{installsitelib}, -$sources{inst_archlib} => $Config::Config{installsitearch}, -$sources{inst_bin} => $Config::Config{installbin} , -$sources{inst_script} => $Config::Config{installscript}, -$sources{inst_man1dir} => $Config::Config{installman1dir}, -$sources{inst_man3dir} => $Config::Config{installman3dir}, -}; -foreach my $key (keys %$user) { -my $value = $user->{$key}; -if (not defined $value and $key ne 'packlist_read' and $key ne 'packlist_write') { -delete $target->{ $sources{$key} }; -} -elsif (exists $sources{$key}) { -$target->{ $sources{$key} } = $value; -} -} -return $target; -} -sub _directory_not_empty { -require File::Find; -my($dir) = @_; -my $files = 0; -File::Find::find(sub { -return if $_ eq ".exists"; -if (-f) { -$File::Find::prune++; -$files = 1; -} -}, $dir); -return $files; -} -sub sign_par { -my %args = &_args; -_verify_or_sign(%args, action => 'sign'); -} -sub verify_par { -my %args = &_args; -$! = _verify_or_sign(%args, action => 'verify'); -return ( $! == Module::Signature::SIGNATURE_OK() ); -} -sub merge_par { -my $base_par = shift; -my @additional_pars = @_; -require Cwd; -require File::Copy; -require File::Path; -require File::Find; -if (not defined $base_par) { -croak "First argument to merge_par() must be the .par archive to modify."; -} -if (not -f $base_par or not -r _ or not -w _) { -croak "'$base_par' is not a file or you do not have enough permissions to read and modify it."; -} -foreach (@additional_pars) { -if (not -f $_ or not -r _) { -croak "'$_' is not a file or you do not have enough permissions to read it."; -} -} -my $old_cwd = Cwd::cwd(); -(undef, my $base_dir) = _unzip_to_tmpdir( -dist => $base_par, subdir => 'blib' -); -my $blibdir = File::Spec->catdir($base_dir, 'blib'); -File::Copy::move( -File::Spec->catfile($blibdir, 'META.yml'), -File::Spec->catfile($base_dir, 'META.yml') -); -unlink File::Spec->catfile($blibdir, 'MANIFEST'); -foreach my $par (@additional_pars) { -chdir($old_cwd); -(undef, my $add_dir) = _unzip_to_tmpdir( -dist => $par -); -my @files; -my @dirs; -File::Find::find( -{wanted =>sub { -my $file = $File::Find::name; -push @files, $file if -f $file; -push @dirs, $file if -d _; -}}, -$add_dir -); -my ($vol, $subdir, undef) = File::Spec->splitpath( $add_dir, 1); -my @dir = File::Spec->splitdir( $subdir ); -foreach my $dir (@dirs) { -my ($v, $d, undef) = File::Spec->splitpath( $dir, 1 ); -my @d = File::Spec->splitdir( $d ); -shift @d foreach @dir; # remove tmp dir from path -my $target = File::Spec->catdir( $blibdir, @d ); -mkdir($target); -} -foreach my $file (@files) { -my ($v, $d, $f) = File::Spec->splitpath( $file ); -my @d = File::Spec->splitdir( $d ); -shift @d foreach @dir; # remove tmp dir from path -my $target = File::Spec->catfile( -File::Spec->catdir( $blibdir, @d ), -$f -); -File::Copy::copy($file, $target) -or die "Could not copy '$file' to '$target': $!"; -} -chdir($old_cwd); -File::Path::rmtree([$add_dir]); -} -unlink File::Spec->catfile($blibdir, 'MANIFEST'); -unlink File::Spec->catfile($blibdir, 'META.yml'); -chdir($base_dir); -my $resulting_par_file = Cwd::abs_path(blib_to_par()); -chdir($old_cwd); -File::Copy::move($resulting_par_file, $base_par); -File::Path::rmtree([$base_dir]); -} -sub remove_man { -my %args = &_args; -my $par = $args{dist}; -require Cwd; -require File::Copy; -require File::Path; -require File::Find; -if (not defined $par) { -croak "First argument to remove_man() must be the .par archive to modify."; -} -if (not -f $par or not -r _ or not -w _) { -croak "'$par' is not a file or you do not have enough permissions to read and modify it."; -} -my $old_cwd = Cwd::cwd(); -(undef, my $base_dir) = _unzip_to_tmpdir( -dist => $par, subdir => 'blib' -); -my $blibdir = File::Spec->catdir($base_dir, 'blib'); -File::Copy::move( -File::Spec->catfile($blibdir, 'META.yml'), -File::Spec->catfile($base_dir, 'META.yml') -); -unlink File::Spec->catfile($blibdir, 'MANIFEST'); -opendir DIRECTORY, 'blib' or die $!; -my @dirs = grep { /^blib\/(?:man\d*|html)$/ } -grep { -d $_ } -map { File::Spec->catfile('blib', $_) } -readdir DIRECTORY; -close DIRECTORY; -File::Path::rmtree(\@dirs); -chdir($base_dir); -my $resulting_par_file = Cwd::abs_path(blib_to_par()); -chdir($old_cwd); -File::Copy::move($resulting_par_file, $par); -File::Path::rmtree([$base_dir]); -} -sub get_meta { -my %args = &_args; -my $dist = $args{dist}; -return undef if not defined $dist or not -r $dist; -require Cwd; -require File::Path; -my $old_cwd = Cwd::cwd(); -(undef, my $base_dir) = _unzip_to_tmpdir( -dist => $dist, subdir => 'blib' -); -my $blibdir = File::Spec->catdir($base_dir, 'blib'); -my $meta = File::Spec->catfile($blibdir, 'META.yml'); -if (not -r $meta) { -return undef; -} -open FH, '<', $meta -or die "Could not open file '$meta' for reading: $!"; -local $/ = undef; -my $meta_text = ; -close FH; -chdir($old_cwd); -File::Path::rmtree([$base_dir]); -return $meta_text; -} -sub _unzip { -my %args = &_args; -my $dist = $args{dist}; -my $path = $args{path} || File::Spec->curdir; -return unless -f $dist; -if (eval { require Archive::Unzip::Burst; 1 }) { -my $return = Archive::Unzip::Burst::unzip($dist, $path); -return if $return; # true return value == error (a la system call) -} -if (eval { require Archive::Zip; 1 }) { -my $zip = Archive::Zip->new; -local %SIG; -$SIG{__WARN__} = sub { print STDERR $_[0] unless $_[0] =~ /\bstat\b/ }; -return unless $zip->read($dist) == Archive::Zip::AZ_OK() -and $zip->extractTree('', "$path/") == Archive::Zip::AZ_OK(); -} -else { -return if system(unzip => $dist, '-d', $path); -} -return 1; -} -sub _zip { -my %args = &_args; -my $dist = $args{dist}; -if (eval { require Archive::Zip; 1 }) { -my $zip = Archive::Zip->new; -$zip->addTree( File::Spec->curdir, '' ); -$zip->writeToFileNamed( $dist ) == Archive::Zip::AZ_OK() or die $!; -} -else { -system(qw(zip -r), $dist, File::Spec->curdir) and die $!; -} -} -sub _args { -if (not @_) { -@_ = (glob('*.par'))[0]; -} -@_ = (dist => @_) if @_ == 1; -my %args = @_; -$args{name} ||= $args{dist}; -if (defined $args{name}) { -$args{name} =~ s/^\w+:\/\///; -my @elems = parse_dist_name($args{name}); -if (defined $elems[0]) { -$args{name} = $elems[0]; -} -else { -$args{name} =~ s/^.*\/([^\/]+)$/$1/; -$args{name} =~ s/^([0-9A-Za-z_-]+)-\d+\..+$/$1/; -} -} -if ($args{dist} and not $args{dist} =~ /\.[a-zA-Z_][^.]*$/) { -require Config; -my $suffix = $args{suffix}; -$suffix ||= "$Config::Config{archname}-$Config::Config{version}.par"; -$args{dist} .= "-$suffix"; -} -if ($args{dist} and $args{dist} =~ m!^\w+://!) { -$args{dist} = _fetch(dist => $args{dist}) -} -return %args; -} -my %escapes; -sub _fetch { -my %args = @_; -if ($args{dist} =~ s/^file:\/\///) { -return $args{dist} if -e $args{dist}; -return; -} -require LWP::Simple; -$ENV{PAR_TEMP} ||= File::Spec->catdir(File::Spec->tmpdir, 'par'); -mkdir $ENV{PAR_TEMP}, 0777; -%escapes = map { chr($_) => sprintf("%%%02X", $_) } 0..255 unless %escapes; -$args{dist} =~ s{^cpan://((([a-zA-Z])[a-zA-Z])[-_a-zA-Z]+)/} -{http://www.cpan.org/modules/by-authors/id/\U$3/$2/$1\E/}; -my $file = $args{dist}; -$file =~ s/([^\w\.])/$escapes{$1}/g; -$file = File::Spec->catfile( $ENV{PAR_TEMP}, $file); -my $rc = LWP::Simple::mirror( $args{dist}, $file ); -if (!LWP::Simple::is_success($rc) and $rc != 304) { -die "Error $rc: ", LWP::Simple::status_message($rc), " ($args{dist})\n"; -} -return $file if -e $file; -return; -} -sub _verify_or_sign { -my %args = &_args; -require File::Path; -require Module::Signature; -die "Module::Signature version 0.25 required" -unless Module::Signature->VERSION >= 0.25; -require Cwd; -my $cwd = Cwd::cwd(); -my $action = $args{action}; -my ($dist, $tmpdir) = _unzip_to_tmpdir($args{dist}); -$action ||= (-e 'SIGNATURE' ? 'verify' : 'sign'); -if ($action eq 'sign') { -open FH, '>SIGNATURE' unless -e 'SIGNATURE'; -open FH, 'MANIFEST' or die $!; -local $/; -my $out = ; -if ($out !~ /^SIGNATURE(?:\s|$)/m) { -$out =~ s/^(?!\s)/SIGNATURE\n/m; -open FH, '>MANIFEST' or die $!; -print FH $out; -} -close FH; -$args{overwrite} = 1 unless exists $args{overwrite}; -$args{skip} = 0 unless exists $args{skip}; -} -my $rv = Module::Signature->can($action)->(%args); -_zip(dist => $dist) if $action eq 'sign'; -File::Path::rmtree([$tmpdir]); -chdir($cwd); -return $rv; -} -sub _unzip_to_tmpdir { -my %args = &_args; -require File::Temp; -my $dist = File::Spec->rel2abs($args{dist}); -my $tmpdirname = File::Spec->catdir(File::Spec->tmpdir, "parXXXXX"); -my $tmpdir = File::Temp::mkdtemp($tmpdirname) -or die "Could not create temporary directory from template '$tmpdirname': $!"; -my $path = $tmpdir; -$path = File::Spec->catdir($tmpdir, $args{subdir}) if defined $args{subdir}; -_unzip(dist => $dist, path => $path); -chdir $tmpdir; -return ($dist, $tmpdir); -} -sub parse_dist_name { -my $file = shift; -return(undef, undef, undef, undef) if not defined $file; -(undef, undef, $file) = File::Spec->splitpath($file); -my $version = qr/v?(?:\d+(?:_\d+)?|\d*(?:\.\d+(?:_\d+)?)+)/; -$file =~ s/\.(?:par|tar\.gz|tar)$//i; -my @elem = split /-/, $file; -my (@dn, $dv, @arch, $pv); -while (@elem) { -my $e = shift @elem; -if ( -$e =~ /^$version$/o -and not(# if not next token also a version -@elem and $elem[0] =~ /^$version$/o -) -) { -$dv = $e; -last; -} -push @dn, $e; -} -my $dn; -$dn = join('-', @dn) if @dn; -if (not @elem) { -return( $dn, $dv, undef, undef); -} -while (@elem) { -my $e = shift @elem; -if ($e =~ /^$version|any_version$/) { -$pv = $e; -last; -} -push @arch, $e; -} -my $arch; -$arch = join('-', @arch) if @arch; -return($dn, $dv, $arch, $pv); -} -sub generate_blib_stub { -my %args = &_args; -my $dist = $args{dist}; -require Config; -my $name = $args{name}; -my $version = $args{version}; -my $suffix = $args{suffix}; -my ($parse_name, $parse_version, $archname, $perlversion) -= parse_dist_name($dist); -$name ||= $parse_name; -$version ||= $parse_version; -$suffix = "$archname-$perlversion" -if (not defined $suffix or $suffix eq '') -and $archname and $perlversion; -$suffix ||= "$Config::Config{archname}-$Config::Config{version}"; -if ( grep { not defined $_ } ($name, $version, $suffix) ) { -warn "Could not determine distribution meta information from distribution name '$dist'"; -return(); -} -$suffix =~ s/\.par$//; -if (not -f 'META.yml') { -open META, '>', 'META.yml' -or die "Could not open META.yml file for writing: $!"; -print META << "YAML" if fileno(META); -name: $name -version: $version -build_requires: {} -conflicts: {} -dist_name: $name-$version-$suffix.par -distribution_type: par -dynamic_config: 0 -generated_by: 'PAR::Dist version $PAR::Dist::VERSION' -license: unknown -YAML -close META; -} -mkdir('blib'); -mkdir(File::Spec->catdir('blib', 'lib')); -mkdir(File::Spec->catdir('blib', 'script')); -return 1; -} -sub contains_binaries { -require File::Find; -my %args = &_args; -my $dist = $args{dist}; -return undef if not defined $dist or not -r $dist; -require Cwd; -require File::Path; -my $old_cwd = Cwd::cwd(); -(undef, my $base_dir) = _unzip_to_tmpdir( -dist => $dist, subdir => 'blib' -); -my $blibdir = File::Spec->catdir($base_dir, 'blib'); -my $archdir = File::Spec->catdir($blibdir, 'arch'); -my $found = 0; -File::Find::find( -sub { -$found++ if -f $_ and not /^\.exists$/; -}, -$archdir -); -chdir($old_cwd); -File::Path::rmtree([$base_dir]); -return $found ? 1 : 0; -} -1; diff --git a/test/expected_dir/perl_module.pm/perl/comment b/test/expected_dir/perl_module.pm/perl/comment deleted file mode 100644 index ee6abe8..0000000 --- a/test/expected_dir/perl_module.pm/perl/comment +++ /dev/null @@ -1,285 +0,0 @@ -=head1 NAME -PAR::Dist - Create and manipulate PAR distributions -=head1 VERSION -This document describes version 0.29 of PAR::Dist, released Feb 6, 2008. -=head1 SYNOPSIS -As a shell command: -% perl -MPAR::Dist -eblib_to_par -In programs: -use PAR::Dist; -my $dist = blib_to_par(); # make a PAR file using ./blib/ -install_par($dist); # install it into the system -uninstall_par($dist); # uninstall it from the system -sign_par($dist); # sign it using Module::Signature -verify_par($dist); # verify it using Module::Signature -install_par("http://foo.com/DBI-1.37-MSWin32-5.8.0.par"); # works too -install_par("http://foo.com/DBI-1.37"); # auto-appends archname + perlver -install_par("cpan://SMUELLER/PAR-Packer-0.975"); # uses CPAN author directory -=head1 DESCRIPTION -This module creates and manipulates I. They are -architecture-specific B files, containing everything under F -of CPAN distributions after their C or C stage, a -F describing metadata of the original CPAN distribution, -and a F detailing all files within it. Digitally signed PAR -distributions will also contain a F file. -The naming convention for such distributions is: -$NAME-$VERSION-$ARCH-$PERL_VERSION.par -For example, C corresponds to the -0.01 release of C on CPAN, built for perl 5.8.0 running on -C. -=head1 FUNCTIONS -Several functions are exported by default. Unless otherwise noted, -they can take either a hash of -named arguments, a single argument (taken as C<$path> by C -and C<$dist> by other functions), or no arguments (in which case -the first PAR file in the current directory is used). -Therefore, under a directory containing only a single F, all -invocations below are equivalent: -% perl -MPAR::Dist -e"install_par( dist => 'test.par' )" -% perl -MPAR::Dist -e"install_par( 'test.par' )" -% perl -MPAR::Dist -einstall_par; -If C<$dist> resembles a URL, C is called to mirror it -locally under C<$ENV{PAR_TEMP}> (or C<$TEMP/par/> if unspecified), and the -function will act on the fetched local file instead. If the URL begins -with C, it will be expanded automatically to the author's CPAN -directory (e.g. C). -If C<$dist> does not have a file extension beginning with a letter or -underscore, a dash and C<$suffix> ($ARCH-$PERL_VERSION.par by default) -will be appended to it. -=head2 blib_to_par -Takes key/value pairs as parameters or a single parameter indicating the -path that contains the F subdirectory. -Builds a PAR distribution from the F subdirectory under C, or -under the current directory if unspecified. If F does not exist, -it automatically runs F, F, F or F to -create it. -Returns the filename or the generated PAR distribution. -Valid parameters are: -=over 2 -=item path -Sets the path which contains the F subdirectory from which the PAR -distribution will be generated. -=item name, version, suffix -These attributes set the name, version and platform specific suffix -of the distribution. Name and version can be automatically -determined from the distributions F or F files. -The suffix is generated from your architecture name and your version of -perl by default. -=item dist -The output filename for the PAR distribution. -=back -=cut -# don't use 'my $foo ... if ...' it creates a static variable! -# could not determine name or version. Error. -=head2 install_par -Installs a PAR distribution into the system, using -C. -Valid parameters are: -=over 2 -=item dist -The .par file to install. The heuristics outlined in the B -section above apply. -=item prefix -This string will be prepended to all installation paths. -If it isn't specified, the environment variable -C is used as a prefix. -=back -Additionally, you can use several parameters to change the default -installation destinations. You don't usually have to worry about this -unless you are installing into a user-local directory. -The following section outlines the parameter names and default settings: -Parameter From To -inst_lib blib/lib $Config{installsitelib} (*) -inst_archlib blib/arch $Config{installsitearch} -inst_script blib/script $Config{installscript} -inst_bin blib/bin $Config{installbin} -inst_man1dir blib/man1 $Config{installman1dir} -inst_man3dir blib/man3 $Config{installman3dir} -packlist_read $Config{sitearchexp}/auto/$name/.packlist -packlist_write $Config{installsitearch}/auto/$name/.packlist -The C parameter is used to control where the F<.packlist> -file is written to. (Necessary for uninstallation.) -The C parameter specifies a .packlist file to merge in if -it exists. By setting any of the above installation targets to C, -you can remove that target altogether. For example, passing -C undef, inst_man3dir => undef> means that the contained -manual pages won't be installed. This is not available for the packlists. -Finally, you may specify a C parameter. Its value should be -a reference to a hash of custom installation targets such as -custom_targets => { 'blib/my_data' => '/some/path/my_data' } -You can use this to install the F<.par> archives contents to arbitrary -locations. -If only a single parameter is given, it is treated as the C -parameter. -=cut -=head2 uninstall_par -Uninstalls all previously installed contents of a PAR distribution, -using C. -Takes almost the same parameters as C, but naturally, -the installation target parameters do not apply. The only exception -to this is the C parameter which specifies the -F<.packlist> file to read the list of installed files from. -It defaults to C<$Config::Config{installsitearch}/auto/$name/.packlist>. -=cut -# Returns the default installation target as used by -# ExtUtils::Install::install(). First parameter should be the base -# directory containing the blib/ we're installing from. -# Second parameter should be the name of the distribution for the packlist -# paths. Third parameter may be a hash reference with user defined keys for -# the target hash. In fact, any contents that do not start with 'inst_' are -# skipped. -# accepted sources (and user overrides) -# default targets -# Included for future support for ${flavour}perl external lib installation -# if ($Config::Config{flavour_perl}) { -# my $ext = File::Spec->catdir($dir, 'blib', 'ext'); -# # from => to -# $sources{inst_external_lib} = File::Spec->catdir($ext, 'lib'); -# $sources{inst_external_bin} = File::Spec->catdir($ext, 'bin'); -# $sources{inst_external_include} = File::Spec->catdir($ext, 'include'); -# $sources{inst_external_src} = File::Spec->catdir($ext, 'src'); -# $target->{ $sources{inst_external_lib} } = $Config::Config{flavour_install_lib}; -# $target->{ $sources{inst_external_bin} } = $Config::Config{flavour_install_bin}; -# $target->{ $sources{inst_external_include} } = $Config::Config{flavour_install_include}; -# $target->{ $sources{inst_external_src} } = $Config::Config{flavour_install_src}; -# } -# insert user overrides -# undef means "remove" -# overwrite stuff, don't let the user create new entries -=head2 sign_par -Digitally sign a PAR distribution using C or B, -via B. -=cut -=head2 verify_par -Verify the digital signature of a PAR distribution using C or -B, via B. -Returns a boolean value indicating whether verification passed; C<$!> -is set to the return code of C. -=cut -=head2 merge_par -Merge two or more PAR distributions into one. First argument must -be the name of the distribution you want to merge all others into. -Any following arguments will be interpreted as the file names of -further PAR distributions to merge into the first one. -merge_par('foo.par', 'bar.par', 'baz.par') -This will merge the distributions C, C and C -into the distribution C. C will be overwritten! -The original META.yml of C is retained. -=cut -# parameter checking -# The unzipping will change directories. Remember old dir. -# Unzip the base par to a temp. dir. -# move the META.yml to the (main) temp. dir. -# delete (incorrect) MANIFEST -# extract additional pars and merge -# restore original directory because the par path -# might have been relative! -# I hate File::Find -# And I hate writing portable code, too. -# merge directory structure -# merge files -# delete (copied) MANIFEST and META.yml -=head2 remove_man -Remove the man pages from a PAR distribution. Takes one named -parameter: I which should be the name (and path) of the -PAR distribution file. The calling conventions outlined in -the C section above apply. -The PAR archive will be -extracted, stripped of all C and C subdirectories -and then repackaged into the original file. -=cut -# parameter checking -# The unzipping will change directories. Remember old dir. -# Unzip the base par to a temp. dir. -# move the META.yml to the (main) temp. dir. -# delete (incorrect) MANIFEST -=head2 get_meta -Opens a PAR archive and extracts the contained META.yml file. -Returns the META.yml file as a string. -Takes one named parameter: I. If only one parameter is -passed, it is treated as the I parameter. (Have a look -at the description in the C section above.) -Returns undef if no PAR archive or no META.yml within the -archive were found. -=cut -# The unzipping will change directories. Remember old dir. -# Unzip the base par to a temp. dir. -# Try fast unzipping first -# Then slow unzipping -# Then fall back to the system -# This sub munges the arguments to most of the PAR::Dist functions -# into a hash. On the way, it downloads PAR archives as necessary, etc. -# default to the first .par in the CWD -# single argument => it's a distribution file name or URL -# If we are installing from an URL, we want to munge the -# distribution name so that it is in form "Module-Name" -# @elems is name, version, arch, perlversion -# append suffix if there is none -# download if it's an URL -# Download PAR archive, but only if necessary (mirror!) -=head2 parse_dist_name -First argument must be a distribution file name. The file name -is parsed into I, I, -I, and I. -Returns the results as a list in the above order. -If any or all of the above cannot be determined, returns undef instead -of the undetermined elements. -Supported formats are: -Math-Symbolic-0.502-x86_64-linux-gnu-thread-multi-5.8.7 -Math-Symbolic-0.502 -The ".tar.gz" or ".par" extensions as well as any -preceding paths are stripped before parsing. Starting with C -0.22, versions containing a preceding C are parsed correctly. -This function is not exported by default. -=cut -# (assumes an arch string doesnt start with a version...) -=head2 generate_blib_stub -Creates a F subdirectory in the current directory -and prepares a F with meta information for a -new PAR distribution. First argument should be the name of the -PAR distribution in a format understood by C. -Alternatively, named arguments resembling those of -C are accepted. -After running C and injecting files into -the F directory, you can create a PAR distribution -using C. -This function is useful for creating custom PAR distributions -from scratch. (I.e. not from an unpacked CPAN distribution) -Example: -use PAR::Dist; -use File::Copy 'copy'; -generate_blib_stub( -name => 'MyApp', version => '1.00' -); -copy('MyApp.pm', 'blib/lib/MyApp.pm'); -blib_to_par(); # generates the .par file! -C will not overwrite existing files. -=cut -=head2 contains_binaries -This function is not exported by default. -Opens a PAR archive tries to determine whether that archive -contains platform-specific binary code. -Takes one named parameter: I. If only one parameter is -passed, it is treated as the I parameter. (Have a look -at the description in the C section above.) -Throws a fatal error if the PAR archive could not be found. -Returns one if the PAR was found to contain binary code -and zero otherwise. -=cut -# The unzipping will change directories. Remember old dir. -# Unzip the base par to a temp. dir. -=head1 SEE ALSO -L, L, L, L -=head1 AUTHORS -Audrey Tang Ecpan@audreyt.orgE 2003-2007 -Steffen Mueller Esmueller@cpan.orgE 2005-2007 -PAR has a mailing list, Epar@perl.orgE, that you can write to; -send an empty mail to Epar-subscribe@perl.orgE to join the list -and participate in the discussion. -Please send bug reports to Ebug-par@rt.cpan.orgE. -=head1 COPYRIGHT -Copyright 2003-2007 by Audrey Tang Eautrijus@autrijus.orgE. -This program is free software; you can redistribute it and/or modify it -under the same terms as Perl itself. -See L -=cut diff --git a/test/expected_dir/php1.php b/test/expected_dir/php1.php new file mode 100644 index 0000000..a9d85ec --- /dev/null +++ b/test/expected_dir/php1.php @@ -0,0 +1,59 @@ +html code +html code +html code +html code +html code +html code +html code +html code +html code +html code +html code +html code +html code
FirstLastEmail +html code
+html blank +html code +html blank +html code +php code +php code +php code +html code +html code +html blank +html code +html blank +html code diff --git a/test/expected_dir/php1.php/css/code b/test/expected_dir/php1.php/css/code deleted file mode 100644 index b42db9a..0000000 --- a/test/expected_dir/php1.php/css/code +++ /dev/null @@ -1,3 +0,0 @@ -h1 { -color: black; -} diff --git a/test/expected_dir/php1.php/css/comment b/test/expected_dir/php1.php/css/comment deleted file mode 100644 index 5912a96..0000000 --- a/test/expected_dir/php1.php/css/comment +++ /dev/null @@ -1 +0,0 @@ -/* css comment */ diff --git a/test/expected_dir/php1.php/html/blanks b/test/expected_dir/php1.php/html/blanks deleted file mode 100644 index bf0d87a..0000000 --- a/test/expected_dir/php1.php/html/blanks +++ /dev/null @@ -1 +0,0 @@ -4 \ No newline at end of file diff --git a/test/expected_dir/php1.php/html/code b/test/expected_dir/php1.php/html/code deleted file mode 100644 index a7114ab..0000000 --- a/test/expected_dir/php1.php/html/code +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - -
FirstLastEmail -
- - - - - - diff --git a/test/expected_dir/php1.php/javascript/code b/test/expected_dir/php1.php/javascript/code deleted file mode 100644 index b14f5c0..0000000 --- a/test/expected_dir/php1.php/javascript/code +++ /dev/null @@ -1 +0,0 @@ -document.write("Hello World!") diff --git a/test/expected_dir/php1.php/javascript/comment b/test/expected_dir/php1.php/javascript/comment deleted file mode 100644 index ecd132d..0000000 --- a/test/expected_dir/php1.php/javascript/comment +++ /dev/null @@ -1 +0,0 @@ -// javascript comment diff --git a/test/expected_dir/php1.php/php/code b/test/expected_dir/php1.php/php/code deleted file mode 100644 index f967d78..0000000 --- a/test/expected_dir/php1.php/php/code +++ /dev/null @@ -1,16 +0,0 @@ -mysql_connect("localhost", "db user", "db pass") -or die("DB CONNECT ERROR: " . mysql_error()); -mysql_select_db("db name") -or die("DB SELECT ERROR: " . mysql_error()); -$query = "SELECT fname, lname, email FROM table ORDER BY lname"; -$result = mysql_query($query) -or die("DB SELECT ERROR: " . mysql_error()); -while($row = mysql_fetch_array($result)) -{ -$lname = $row['lname']; -$fname = $row['fname']; -$email = $row['email']; - - - -} // end while diff --git a/test/expected_dir/php1.php/php/comment b/test/expected_dir/php1.php/php/comment deleted file mode 100644 index 3a86eb9..0000000 --- a/test/expected_dir/php1.php/php/comment +++ /dev/null @@ -1,3 +0,0 @@ -## Comment with a hash symbol ## -// Spaghetti code starts....(slopping html code in) -// Spaghetti code is both a source of praise and complaints diff --git a/test/expected_dir/pike1.pike b/test/expected_dir/pike1.pike new file mode 100644 index 0000000..73b3cf7 --- /dev/null +++ b/test/expected_dir/pike1.pike @@ -0,0 +1,6 @@ +pike code #!/bin/env pike +pike comment /* Say hello. */ +pike code int main(int argc, array(string) argv) +pike code { +pike code Stdio.stdout.write("Hello, world.\n"); +pike code } diff --git a/test/expected_dir/pike1.pike/pike/blanks b/test/expected_dir/pike1.pike/pike/blanks deleted file mode 100644 index c227083..0000000 --- a/test/expected_dir/pike1.pike/pike/blanks +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/test/expected_dir/pike1.pike/pike/code b/test/expected_dir/pike1.pike/pike/code deleted file mode 100644 index 6f52ddd..0000000 --- a/test/expected_dir/pike1.pike/pike/code +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/env pike -int main(int argc, array(string) argv) -{ -Stdio.stdout.write("Hello, world.\n"); -} diff --git a/test/expected_dir/pike1.pike/pike/comment b/test/expected_dir/pike1.pike/pike/comment deleted file mode 100644 index 8fda75e..0000000 --- a/test/expected_dir/pike1.pike/pike/comment +++ /dev/null @@ -1 +0,0 @@ -/* Say hello. */ diff --git a/test/expected_dir/pike2.pmod b/test/expected_dir/pike2.pmod new file mode 100644 index 0000000..2305875 --- /dev/null +++ b/test/expected_dir/pike2.pmod @@ -0,0 +1,241 @@ +pike comment // +pike comment // LPD.pmod: an implementation of the BSD lpd protocol (RFC 1179). +pike comment // This is a module for pike. +pike comment // 3 July 1998 Bill Welliver +pike comment // +pike comment // $Id: LPD.pmod,v 1.10 2008/01/13 17:02:43 nilsson Exp $ +pike comment // +pike blank +pike code #pike __REAL_VERSION__ +pike blank +pike comment //! A client for communicating with printers and print spoolers that +pike comment //! support the BSD lpd protocol (RFC 1179). +pike code class client { +pike code string host; +pike code int port; +pike code private object conn; +pike code int jobnum; +pike code string jobtype; +pike code string jobname; +pike blank +pike code private int connect(string host, int port) +pike code { +pike code int a=random(10); +pike comment // try to open one of the "official" local socket ports. +pike comment // not having one doesn't seem to be a problem with most LPD +pike comment // servers, but we should at least try. will probably fail +pike comment // if two try to open the same local port at once. ymmv. +pike code int res=conn->open_socket(721 + a); +pike blank +pike code return conn->connect(host, port); +pike code } +pike blank +pike comment //! @decl int set_job_type(string type) +pike comment //! Set the type of job to be sent to the printer to @i{type@}. +pike comment //! Valid types are: text, postscript and raw. +pike code int set_job_type(string type) +pike code { +pike code type=lower_case(type); +pike blank +pike code switch (type) { +pike code case "f": +pike code case "text": +pike code jobtype="f"; +pike code break; +pike blank +pike code case "o": +pike code case "postscript": +pike code case "ps": +pike code jobtype="o"; +pike code break; +pike blank +pike code default: +pike code case "l": +pike code case "raw": +pike code jobtype="l"; +pike code break; +pike code } +pike code return 1; +pike code } +pike blank +pike comment //! @decl int set_job_name(string name) +pike comment //! Sets the name of the print job to @i{name@}. +pike code int set_job_name(string name) +pike code { +pike code jobname=name; +pike code return 1; +pike code } +pike blank +pike comment //! @decl int start_queue(string queue) +pike comment //! Start the queue @i{queue@} if not already printing. +pike comment //! @returns +pike comment //! Returns 0 if unable to connect, 1 otherwise. +pike code int start_queue(string queue) +pike code { +pike code if(!queue) return 0; +pike blank +pike code if(!connect(host, port)) +pike code return 0; +pike blank +pike code conn->write(sprintf("%c%s\n", 01, queue)); +pike code string resp= conn->read(); +pike code conn->close(); +pike code return 1; +pike code } +pike blank +pike comment //! @decl string|int send_job(string queue, string job) +pike comment //! Send print job consisting of data @i{job@} to printer @i{queue@}. +pike comment //! @returns +pike comment //! Returns 1 if success, 0 otherwise. +pike code int send_job(string queue, string job) +pike code { +pike code string resp; +pike blank +pike code if(!queue) return 0; +pike blank +pike code if(!connect(host, port)) +pike code return 0; +pike comment // werror("connected to " + host + "\n"); +pike blank +pike code string control=""; +pike code control+="H"+gethostname()+"\n"; +pike code #if constant(getuid) && constant(getpwuid) +pike code control+="P"+(getpwuid(getuid())[0]||"nobody")+"\n"; +pike code #else +pike code control+="P-1\n"; +pike code #endif +pike code control+=(jobtype||"l")+"dfA"+ sprintf("%03d%s", jobnum, gethostname())+"\n"; +pike code if(jobname) +pike code { +pike code control+="J" + jobname + "\n"; +pike code control+="N" + jobname + "\n"; +pike code } +pike code else +pike code { +pike code control+="JPike LPD Client Job " + jobnum + "\n"; +pike code control+="NPike LPD Client Job " + jobnum + "\n"; +pike code } +pike code jobnum++; +pike code werror("job file:\n\n" + control + "\n\n"); +pike blank +pike code conn->write(sprintf("%c%s\n", 02, queue)); +pike code resp=conn->read(1); +pike code if((int)resp !=0) +pike code { +pike code werror("receive job failed.\n"); +pike code return 0; +pike code } +pike blank +pike code conn->write(sprintf("%c%s cfA%03d%s\n", 02, (string)sizeof(control), +pike code jobnum,gethostname())); +pike blank +pike code resp=conn->read(1); +pike code if((int)resp !=0) +pike code { +pike code werror("request receive control failed.\n"); +pike code return 0; +pike code } +pike blank +pike code conn->write(sprintf("%s%c", control, 0)); +pike blank +pike code resp=conn->read(1); +pike code if((int)resp !=0) +pike code { +pike code werror("send receive control failed.\n"); +pike code return 0; +pike code } +pike blank +pike code conn->write(sprintf("%c%s dfA%03d%s\n", 03, (string)sizeof(job), jobnum, +pike code gethostname())); +pike code resp=conn->read(1); +pike code if((int)resp !=0) +pike code { +pike code werror("request receive job failed.\n"); +pike code return 0; +pike code } +pike blank +pike blank +pike code conn->write(sprintf("%s%c", job, 0)); +pike blank +pike code resp=conn->read(1); +pike code if((int)resp !=0) +pike code { +pike code werror("send receive job failed.\n"); +pike code return 0; +pike code } +pike blank +pike blank +pike blank +pike comment // read the response. +pike blank +pike comment // resp=conn->read(); +pike code if((int)(resp)!=0) +pike code { +pike code conn->close(); +pike code return 0; +pike code } +pike code conn->close(); +pike comment // start_queue(queue); +pike code return 1; +pike code } +pike blank +pike comment //! @decl int delete_job(string queue, int|void job) +pike comment //! Delete job @i{job@} from printer @i{queue@}. +pike comment //! @returns +pike comment //! Returns 1 on success, 0 otherwise. +pike code int delete_job(string queue, int|void job) +pike code { +pike code if(!queue) return 0; +pike blank +pike code if(!connect(host, port)) +pike code return 0; +pike blank +pike code #if constant(getpwuid) && constant(getuid) +pike code string agent=(getpwuid(getuid())[0]||"nobody"); +pike code #else +pike code string agent="nobody"; +pike code #endif +pike blank +pike code if(job) +pike code conn->write(sprintf("%c%s %s %d\n", 05, queue, agent, job)); +pike code else +pike code conn->write(sprintf("%c%s %s\n", 05, queue, agent)); +pike code string resp= conn->read(); +pike code conn->close(); +pike code return 1; +pike code } +pike blank +pike blank +pike comment //! @decl string|int status(string queue) +pike comment //! Check the status of queue @i{queue@}. +pike comment //! @returns +pike comment //! Returns 0 on failure, otherwise returns the status response from the printer. +pike code string|int status(string queue) +pike code { +pike code if(!queue) return 0; +pike blank +pike code if(!connect(host, port)) +pike code return 0; +pike blank +pike code conn->write(sprintf("%c%s\n", 04, queue)); +pike code string resp= conn->read(); +pike code conn->close(); +pike code return resp; +pike code } +pike blank +pike comment //! Create a new LPD client connection. +pike comment //! @param hostname +pike comment //! Contains the hostname or ipaddress of the print host. +pike comment //! if not provided, defaults to @i{localhost@}. +pike comment //! @param portnum +pike comment //! Contains the port the print host is listening on. +pike comment //! if not provided, defaults to port @i{515@}, the RFC 1179 standard. +pike code void create(string|void hostname, int|void portnum) +pike code { +pike code host=hostname || "localhost"; +pike code port=portnum || 515; +pike code conn=Stdio.File(); +pike code jobnum=1; +pike code } +pike code } +pike blank diff --git a/test/expected_dir/pike2.pmod/pike/blanks b/test/expected_dir/pike2.pmod/pike/blanks deleted file mode 100644 index 72f523f..0000000 --- a/test/expected_dir/pike2.pmod/pike/blanks +++ /dev/null @@ -1 +0,0 @@ -39 \ No newline at end of file diff --git a/test/expected_dir/pike2.pmod/pike/code b/test/expected_dir/pike2.pmod/pike/code deleted file mode 100644 index a6f3edb..0000000 --- a/test/expected_dir/pike2.pmod/pike/code +++ /dev/null @@ -1,157 +0,0 @@ -#pike __REAL_VERSION__ -class client { -string host; -int port; -private object conn; -int jobnum; -string jobtype; -string jobname; -private int connect(string host, int port) -{ -int a=random(10); -int res=conn->open_socket(721 + a); -return conn->connect(host, port); -} -int set_job_type(string type) -{ -type=lower_case(type); -switch (type) { -case "f": -case "text": -jobtype="f"; -break; -case "o": -case "postscript": -case "ps": -jobtype="o"; -break; -default: -case "l": -case "raw": -jobtype="l"; -break; -} -return 1; -} -int set_job_name(string name) -{ -jobname=name; -return 1; -} -int start_queue(string queue) -{ -if(!queue) return 0; -if(!connect(host, port)) -return 0; -conn->write(sprintf("%c%s\n", 01, queue)); -string resp= conn->read(); -conn->close(); -return 1; -} -int send_job(string queue, string job) -{ -string resp; -if(!queue) return 0; -if(!connect(host, port)) -return 0; -string control=""; -control+="H"+gethostname()+"\n"; -#if constant(getuid) && constant(getpwuid) -control+="P"+(getpwuid(getuid())[0]||"nobody")+"\n"; -#else -control+="P-1\n"; -#endif -control+=(jobtype||"l")+"dfA"+ sprintf("%03d%s", jobnum, gethostname())+"\n"; -if(jobname) -{ -control+="J" + jobname + "\n"; -control+="N" + jobname + "\n"; -} -else -{ -control+="JPike LPD Client Job " + jobnum + "\n"; -control+="NPike LPD Client Job " + jobnum + "\n"; -} -jobnum++; -werror("job file:\n\n" + control + "\n\n"); -conn->write(sprintf("%c%s\n", 02, queue)); -resp=conn->read(1); -if((int)resp !=0) -{ -werror("receive job failed.\n"); -return 0; -} -conn->write(sprintf("%c%s cfA%03d%s\n", 02, (string)sizeof(control), -jobnum,gethostname())); -resp=conn->read(1); -if((int)resp !=0) -{ -werror("request receive control failed.\n"); -return 0; -} -conn->write(sprintf("%s%c", control, 0)); -resp=conn->read(1); -if((int)resp !=0) -{ -werror("send receive control failed.\n"); -return 0; -} -conn->write(sprintf("%c%s dfA%03d%s\n", 03, (string)sizeof(job), jobnum, -gethostname())); -resp=conn->read(1); -if((int)resp !=0) -{ -werror("request receive job failed.\n"); -return 0; -} -conn->write(sprintf("%s%c", job, 0)); -resp=conn->read(1); -if((int)resp !=0) -{ -werror("send receive job failed.\n"); -return 0; -} -if((int)(resp)!=0) -{ -conn->close(); -return 0; -} -conn->close(); -return 1; -} -int delete_job(string queue, int|void job) -{ -if(!queue) return 0; -if(!connect(host, port)) -return 0; -#if constant(getpwuid) && constant(getuid) -string agent=(getpwuid(getuid())[0]||"nobody"); -#else -string agent="nobody"; -#endif -if(job) -conn->write(sprintf("%c%s %s %d\n", 05, queue, agent, job)); -else -conn->write(sprintf("%c%s %s\n", 05, queue, agent)); -string resp= conn->read(); -conn->close(); -return 1; -} -string|int status(string queue) -{ -if(!queue) return 0; -if(!connect(host, port)) -return 0; -conn->write(sprintf("%c%s\n", 04, queue)); -string resp= conn->read(); -conn->close(); -return resp; -} -void create(string|void hostname, int|void portnum) -{ -host=hostname || "localhost"; -port=portnum || 515; -conn=Stdio.File(); -jobnum=1; -} -} diff --git a/test/expected_dir/pike2.pmod/pike/comment b/test/expected_dir/pike2.pmod/pike/comment deleted file mode 100644 index 737f3d4..0000000 --- a/test/expected_dir/pike2.pmod/pike/comment +++ /dev/null @@ -1,45 +0,0 @@ -// -// LPD.pmod: an implementation of the BSD lpd protocol (RFC 1179). -// This is a module for pike. -// 3 July 1998 Bill Welliver -// -// $Id: LPD.pmod,v 1.10 2008/01/13 17:02:43 nilsson Exp $ -// -//! A client for communicating with printers and print spoolers that -//! support the BSD lpd protocol (RFC 1179). -// try to open one of the "official" local socket ports. -// not having one doesn't seem to be a problem with most LPD -// servers, but we should at least try. will probably fail -// if two try to open the same local port at once. ymmv. -//! @decl int set_job_type(string type) -//! Set the type of job to be sent to the printer to @i{type@}. -//! Valid types are: text, postscript and raw. -//! @decl int set_job_name(string name) -//! Sets the name of the print job to @i{name@}. -//! @decl int start_queue(string queue) -//! Start the queue @i{queue@} if not already printing. -//! @returns -//! Returns 0 if unable to connect, 1 otherwise. -//! @decl string|int send_job(string queue, string job) -//! Send print job consisting of data @i{job@} to printer @i{queue@}. -//! @returns -//! Returns 1 if success, 0 otherwise. -// werror("connected to " + host + "\n"); -// read the response. -// resp=conn->read(); -// start_queue(queue); -//! @decl int delete_job(string queue, int|void job) -//! Delete job @i{job@} from printer @i{queue@}. -//! @returns -//! Returns 1 on success, 0 otherwise. -//! @decl string|int status(string queue) -//! Check the status of queue @i{queue@}. -//! @returns -//! Returns 0 on failure, otherwise returns the status response from the printer. -//! Create a new LPD client connection. -//! @param hostname -//! Contains the hostname or ipaddress of the print host. -//! if not provided, defaults to @i{localhost@}. -//! @param portnum -//! Contains the port the print host is listening on. -//! if not provided, defaults to port @i{515@}, the RFC 1179 standard. diff --git a/test/expected_dir/py1.py b/test/expected_dir/py1.py new file mode 100644 index 0000000..2f600fb --- /dev/null +++ b/test/expected_dir/py1.py @@ -0,0 +1,18 @@ +python comment # some python code +python comment # lorem +python comment # ipsum +python comment # foo +python blank +python code class Foo: +python comment """ +python comment This is a foo class +python comment It doesn't do anything +python comment Therefore this doc comment is pointless +python comment """ +python blank +python code def __init__(self, bar): +python comment """short doc comment""" +python code print(bar) +python blank +python code def string(self): +python code print('This is a string') diff --git a/test/expected_dir/py1.py/python/blanks b/test/expected_dir/py1.py/python/blanks deleted file mode 100644 index e440e5c..0000000 --- a/test/expected_dir/py1.py/python/blanks +++ /dev/null @@ -1 +0,0 @@ -3 \ No newline at end of file diff --git a/test/expected_dir/py1.py/python/code b/test/expected_dir/py1.py/python/code deleted file mode 100644 index 9547930..0000000 --- a/test/expected_dir/py1.py/python/code +++ /dev/null @@ -1,5 +0,0 @@ -class Foo: -def __init__(self, bar): -print(bar) -def string(self): -print('This is a string') diff --git a/test/expected_dir/py1.py/python/comment b/test/expected_dir/py1.py/python/comment deleted file mode 100644 index ebaa411..0000000 --- a/test/expected_dir/py1.py/python/comment +++ /dev/null @@ -1,10 +0,0 @@ -# some python code -# lorem -# ipsum -# foo -""" -This is a foo class -It doesn't do anything -Therefore this doc comment is pointless -""" -"""short doc comment""" diff --git a/test/expected_dir/rexx1.rex b/test/expected_dir/rexx1.rex new file mode 100644 index 0000000..ff945d4 --- /dev/null +++ b/test/expected_dir/rexx1.rex @@ -0,0 +1,311 @@ +rexx comment /* REXX FLTTBL Cloned from DUMPTBL 960619 to produce a flat +rexx comment version (up to 32K characters wide) of any ISPF +rexx comment table. +rexx blank +rexx comment Written by Frank Clarke, Oldsmar, FL +rexx blank +rexx comment Impact Analysis +rexx comment . SYSPROC LA +rexx comment . SYSPROC TRAPOUT +rexx blank +rexx comment Modification History +rexx comment 19960918 fxc added some error-checking +rexx comment 19970115 fxc upgrade REXXSKEL from v.960606 to v.970113; add +rexx comment RESTARTability; +rexx comment 19991231 fxc upgrade REXXSKEL from v.970113 to v.19991109; +rexx comment RXSKLY2K; DECOMM; LRECL reduced from 32K to "min +rexx comment needed"; +rexx blank +rexx code */ arg argline +rexx code address TSO /* REXXSKEL ver.19991109 */ +rexx code arg parms "((" opts +rexx blank +rexx code signal on syntax +rexx code signal on novalue +rexx blank +rexx code call TOOLKIT_INIT /* conventional start-up -*/ +rexx code rc = Trace(tv) +rexx code info = parms /* to enable parsing */ +rexx blank +rexx code if \sw.inispf then do +rexx code arg line +rexx code line = line "(( RESTARTED" /* tell the next invocation */ +rexx code "ISPSTART CMD("exec_name line")" /* Invoke ISPF if nec. */ +rexx code exit /* ...and restart it */ +rexx code end +rexx blank +rexx code call A_INIT /* -*/ +rexx blank +rexx code "NEWSTACK" +rexx code if \sw.0error_found then, +rexx code call C_TABLE_OPS /* -*/ +rexx code if \sw.0error_found then, +rexx code call D_PUMP_TBL /* -*/ +rexx blank +rexx code "DELSTACK" +rexx blank +rexx code if sw.restarted then do +rexx code rc = OutTrap("ll.") +rexx code exit 4 +rexx code end +rexx blank +rexx code exit /*@ FLTTBL */ +rexx comment /* +rexx comment . ----------------------------------------------------------------- */ +rexx code A_INIT: /*@ */ +rexx code if branch then call BRANCH +rexx code address TSO +rexx blank +rexx code call AA_KEYWDS /* -*/ +rexx code parse var info $tn$ . /* table-name required */ +rexx code if $tn$ = "" then do +rexx code helpmsg = "Tablename is required." +rexx code call HELP +rexx code end +rexx blank +rexx code parse value outdsn "FLATTBLS."$tn$ with, +rexx code outdsn . +rexx blank +rexx code xefef = "efef"x +rexx code if tblds = "" then do +rexx code call AB_FIND_LIBRARY /* -*/ +rexx code if tblds = "" then do +rexx code helpmsg = "Table" $tn$ "was not found in ISPTLIB. Please", +rexx code "restart specifying a library name as shown below." +rexx code call HELP /* ...and don't come back */ +rexx code end +rexx code end +rexx code else, +rexx code if Left(tblds,1) = "'" then tblds = Strip(tblds,,"'") +rexx code else tblds = Userid()"."tblds +rexx blank +rexx code return /*@ A_INIT */ +rexx comment /* +rexx comment . ----------------------------------------------------------------- */ +rexx code AA_KEYWDS: /*@ */ +rexx code if branch then call BRANCH +rexx code address TSO +rexx blank +rexx code tblds = KEYWD("IN") +rexx code outdsn = KEYWD("OUTPUT") +rexx code sortseq = KEYWD("SORT") +rexx code sw.0purge = SWITCH("DELETEBEHIND") +rexx blank +rexx code parse value KEYWD("ADD") "0" with bytes_to_add . +rexx blank +rexx code return /*@ AA_KEYWDS */ +rexx comment /* +rexx comment was not specified. Locate the table in ISPTLIB. +rexx comment . ----------------------------------------------------------------- */ +rexx code AB_FIND_LIBRARY: /*@ */ +rexx code if branch then call BRANCH +rexx code address TSO +rexx blank +rexx code "NEWSTACK" +rexx code "LA ISPTLIB ((STACK LINE" +rexx code pull tliblist +rexx code "DELSTACK" +rexx blank +rexx code do Words(tliblist) /* each library */ +rexx code parse var tliblist tblds tliblist +rexx code if Sysdsn("'"tblds"("$tn$")'") = "OK" then return +rexx code end /* tliblist */ +rexx code tblds = "" +rexx blank +rexx code return /*@ AB_FIND_LIBRARY */ +rexx comment /* +rexx comment . ----------------------------------------------------------------- */ +rexx code C_TABLE_OPS: /*@ */ +rexx code if branch then call BRANCH +rexx code address ISPEXEC +rexx blank +rexx code call CA_OPEN_TBL /* -*/ +rexx code call CS_SPIN_TBL /* -*/ +rexx code call CZ_DROP_TBL /* -*/ +rexx blank +rexx code return /*@ C_TABLE_OPS */ +rexx comment /* +rexx comment . ----------------------------------------------------------------- */ +rexx code CA_OPEN_TBL: /*@ */ +rexx code if branch then call BRANCH +rexx code address ISPEXEC +rexx blank +rexx code "LIBDEF ISPTLIB DATASET ID('"tblds"') STACK" +rexx code "TBSTATS" $tn$ "STATUS1(s1) STATUS2(s2) ROWCURR(rowct)" +rexx code if s1 > 1 then do +rexx code say "Table" $tn$ "not available." +rexx code sw.0error_found = "1"; return +rexx code end; else, +rexx code if s2 = 1 then, /* not open */ +rexx code "TBOPEN " $tn$ "NOWRITE" +rexx code else "TBTOP" $tn$ +rexx code "LIBDEF ISPTLIB" +rexx code if sw.0error_found then return +rexx code "TBQUERY" $tn$ "KEYS(keylist)", +rexx code "NAMES(nmlist)" +rexx code parse var keylist "(" keylist ")" +rexx code parse var nmlist "(" nmlist ")" +rexx code namelist = keylist nmlist +rexx blank +rexx code if sortseq <> "" then "TBSORT" $tn$ "FIELDS("sortseq")" +rexx blank +rexx code return /*@ CA_OPEN_TBL */ +rexx comment /* +rexx comment . Given: contains all the defined names for this table. +rexx comment The table has been TOPped. +rexx comment . ----------------------------------------------------------------- */ +rexx code CS_SPIN_TBL: Procedure expose, /*@ hide everything */ +rexx code expose (tk_globalvars), /* except these */ +rexx code $tn$ namelist xefef tblds rows keylist nmlist maxlen +rexx code cs_tv = Trace() +rexx code if branch then call BRANCH +rexx code address ISPEXEC +rexx blank +rexx code maxlen = 0 /* maximum line length */ +rexx code do forever +rexx code "TBSKIP" $tn$ "SAVENAME(xvars)" +rexx code if rc > 0 then leave /* we're done... */ +rexx code line = "" /* set empty */ +rexx comment /* add blocks of "var .. varvalue .." */ +rexx code do cx = 1 to Words(namelist) +rexx code thiswd = Word(namelist,cx) +rexx code line = line thiswd xefef Value(thiswd) xefef +rexx code end /* cx */ +rexx code rc = Trace("O"); rc = Trace(cs_tv) +rexx code parse var xvars "(" xvars ")" +rexx comment /* add a block of "XVARS .. xvarlist .." */ +rexx code line = line "XVARS" xefef xvars xefef +rexx comment /* add blocks of "xvar .. xvarvalue .." */ +rexx code do cx = 1 to Words(xvars) +rexx code thiswd = Word(xvars,cx) +rexx code line = line thiswd xefef Value(thiswd) xefef +rexx code end /* cx */ +rexx code rc = Trace("O"); rc = Trace(cs_tv) +rexx code maxlen = Max(maxlen,Length(line)) +rexx code queue line +rexx code end /* forever */ +rexx blank +rexx code lines_in_stack = queued() +rexx code line = "Contents of" $tn$ "in" tblds, +rexx code "("lines_in_stack" rows) KEYS("keylist") NAMES("nmlist")." +rexx code push line /* make it the first line */ +rexx code maxlen = Max(maxlen,Length(line)) +rexx code if monitor then say "Maximum line length is" maxlen +rexx blank +rexx code return /*@ CS_SPIN_TBL */ +rexx comment /* +rexx comment . ----------------------------------------------------------------- */ +rexx code CZ_DROP_TBL: /*@ */ +rexx code if branch then call BRANCH +rexx code address ISPEXEC +rexx blank +rexx code if s2 = 1 then, /* table was not open at start*/ +rexx code "TBEND" $tn$ +rexx blank +rexx code return /*@ CZ_DROP_TBL */ +rexx comment /* +rexx comment . ----------------------------------------------------------------- */ +rexx code D_PUMP_TBL: /*@ */ +rexx code if branch then call BRANCH +rexx code address TSO +rexx blank +rexx code if monitor then say, +rexx code "Writing text." +rexx blank +rexx code maxlen = maxlen + 4 + bytes_to_add /* set LRECL */ +rexx code vbmax.0 = "NEW CATALOG UNIT(SYSDA) SPACE(1 5) TRACKS", +rexx code "RECFM(V B) LRECL("maxlen") BLKSIZE(0)" +rexx code vbmax.1 = "SHR" /* if it already exists... */ +rexx blank +rexx code tempstat = Sysdsn(outdsn) = "OK" /* 1=exists, 0=missing */ +rexx code "ALLOC FI($TMP) DA("outdsn") REU" vbmax.tempstat +rexx code rcx = rc +rexx code "EXECIO" queued() "DISKW $TMP (FINIS" +rexx code rcx = max(rcx,rc) +rexx code "FREE FI($TMP)" +rexx blank +rexx code if rcx = 0 & sw.0purge then do +rexx code address ISPEXEC +rexx code "LIBDEF ISPTLIB DATASET ID('"tblds"') STACK" +rexx code "TBERASE" $tn$ +rexx code if rc = 0 then say $tn$ "was deleted" +rexx code "LIBDEF ISPTLIB" +rexx code end +rexx blank +rexx code return /*@ D_PUMP_TBL */ +rexx comment /* +rexx comment . ----------------------------------------------------------------- */ +rexx code LOCAL_PREINIT: /*@ customize opts */ +rexx code if branch then call BRANCH +rexx code address TSO +rexx blank +rexx blank +rexx code return /*@ LOCAL_PREINIT */ +rexx comment /* +rexx comment . ----------------------------------------------------------------- */ +rexx code HELP: /*@ */ +rexx code address TSO;"CLEAR" +rexx code if helpmsg <> "" then do ; say helpmsg; say ""; end +rexx code ex_nam = Left(exec_name,8) /* predictable size */ +rexx code say " "ex_nam" produces a flattened version of any ISPF table " +rexx code say " into a VB-form dataset of minimum necessary LRECL." +rexx code say " " +rexx code say " The field contents are written in KEYPHRS format " +rexx code say " (var .. varval ..) " +rexx code say " key-fields first, followed by name-fields, followed by the " +rexx code say " names of any extension variables key-phrased by 'XVARS', " +rexx code say " followed by the extension variables themselves in KEYPHRS " +rexx code say " format. " +rexx code say " " +rexx code say " The first record on the file identifies the table name, the " +rexx code say " source library, the number of rows processed, and the key- and " +rexx code say " name-fields. " +rexx code say " " +rexx code say " more.... " +rexx code pull +rexx code "CLEAR" +rexx code say " Syntax: "ex_nam" (Required)" +rexx code say " " +rexx code say " (Defaults)" +rexx code say " " +rexx code say " (Defaults)" +rexx code say " " +rexx code say " identifies the table to be dumped. " +rexx code say " " +rexx code say " identifies the ISPF Table library which holds ." +rexx code say " If is not specified, ISPTLIB will be " +rexx code say " searched to find the correct dataset. " +rexx code say " " +rexx code say " (default: FLATTBLS.) names the output file. " +rexx code say " will be created if it does not exist. " +rexx code say " " +rexx code say " causes the table to be sorted as indicated before " +rexx code say " being dumped. " +rexx code say " " +rexx code say " (default=0) causes the LRECL of the output dataset " +rexx code say " to be extended to enable updating. " +rexx code pull +rexx code "CLEAR" +rexx code say " Debugging tools provided include: " +rexx code say " " +rexx code say " MONITOR: displays key information throughout processing. " +rexx code say " Displays most paragraph names upon entry. " +rexx code say " " +rexx code say " NOUPDT: by-pass all update logic. " +rexx code say " " +rexx code say " BRANCH: show all paragraph entries. " +rexx code say " " +rexx code say " TRACE tv: will use value following TRACE to place the " +rexx code say " execution in REXX TRACE Mode. " +rexx code say " " +rexx code say " " +rexx code say " Debugging tools can be accessed in the following manner: " +rexx code say " " +rexx code say " TSO "ex_nam" parameters (( debug-options " +rexx code say " " +rexx code say " For example: " +rexx code say " " +rexx code say " TSO "ex_nam" vt2231 add 17 (( MONITOR TRACE ?R " +rexx code address ISPEXEC "CONTROL DISPLAY REFRESH" +rexx code exit /*@ HELP */ +rexx comment /* REXXSKEL back-end removed for space */ diff --git a/test/expected_dir/rexx1.rex/rexx/blanks b/test/expected_dir/rexx1.rex/rexx/blanks deleted file mode 100644 index 72f523f..0000000 --- a/test/expected_dir/rexx1.rex/rexx/blanks +++ /dev/null @@ -1 +0,0 @@ -39 \ No newline at end of file diff --git a/test/expected_dir/rexx1.rex/rexx/code b/test/expected_dir/rexx1.rex/rexx/code deleted file mode 100644 index 1cc1366..0000000 --- a/test/expected_dir/rexx1.rex/rexx/code +++ /dev/null @@ -1,231 +0,0 @@ -*/ arg argline -address TSO /* REXXSKEL ver.19991109 */ -arg parms "((" opts -signal on syntax -signal on novalue -call TOOLKIT_INIT /* conventional start-up -*/ -rc = Trace(tv) -info = parms /* to enable parsing */ -if \sw.inispf then do -arg line -line = line "(( RESTARTED" /* tell the next invocation */ -"ISPSTART CMD("exec_name line")" /* Invoke ISPF if nec. */ -exit /* ...and restart it */ -end -call A_INIT /* -*/ -"NEWSTACK" -if \sw.0error_found then, -call C_TABLE_OPS /* -*/ -if \sw.0error_found then, -call D_PUMP_TBL /* -*/ -"DELSTACK" -if sw.restarted then do -rc = OutTrap("ll.") -exit 4 -end -exit /*@ FLTTBL */ -A_INIT: /*@ */ -if branch then call BRANCH -address TSO -call AA_KEYWDS /* -*/ -parse var info $tn$ . /* table-name required */ -if $tn$ = "" then do -helpmsg = "Tablename is required." -call HELP -end -parse value outdsn "FLATTBLS."$tn$ with, -outdsn . -xefef = "efef"x -if tblds = "" then do -call AB_FIND_LIBRARY /* -*/ -if tblds = "" then do -helpmsg = "Table" $tn$ "was not found in ISPTLIB. Please", -"restart specifying a library name as shown below." -call HELP /* ...and don't come back */ -end -end -else, -if Left(tblds,1) = "'" then tblds = Strip(tblds,,"'") -else tblds = Userid()"."tblds -return /*@ A_INIT */ -AA_KEYWDS: /*@ */ -if branch then call BRANCH -address TSO -tblds = KEYWD("IN") -outdsn = KEYWD("OUTPUT") -sortseq = KEYWD("SORT") -sw.0purge = SWITCH("DELETEBEHIND") -parse value KEYWD("ADD") "0" with bytes_to_add . -return /*@ AA_KEYWDS */ -AB_FIND_LIBRARY: /*@ */ -if branch then call BRANCH -address TSO -"NEWSTACK" -"LA ISPTLIB ((STACK LINE" -pull tliblist -"DELSTACK" -do Words(tliblist) /* each library */ -parse var tliblist tblds tliblist -if Sysdsn("'"tblds"("$tn$")'") = "OK" then return -end /* tliblist */ -tblds = "" -return /*@ AB_FIND_LIBRARY */ -C_TABLE_OPS: /*@ */ -if branch then call BRANCH -address ISPEXEC -call CA_OPEN_TBL /* -*/ -call CS_SPIN_TBL /* -*/ -call CZ_DROP_TBL /* -*/ -return /*@ C_TABLE_OPS */ -CA_OPEN_TBL: /*@ */ -if branch then call BRANCH -address ISPEXEC -"LIBDEF ISPTLIB DATASET ID('"tblds"') STACK" -"TBSTATS" $tn$ "STATUS1(s1) STATUS2(s2) ROWCURR(rowct)" -if s1 > 1 then do -say "Table" $tn$ "not available." -sw.0error_found = "1"; return -end; else, -if s2 = 1 then, /* not open */ -"TBOPEN " $tn$ "NOWRITE" -else "TBTOP" $tn$ -"LIBDEF ISPTLIB" -if sw.0error_found then return -"TBQUERY" $tn$ "KEYS(keylist)", -"NAMES(nmlist)" -parse var keylist "(" keylist ")" -parse var nmlist "(" nmlist ")" -namelist = keylist nmlist -if sortseq <> "" then "TBSORT" $tn$ "FIELDS("sortseq")" -return /*@ CA_OPEN_TBL */ -CS_SPIN_TBL: Procedure expose, /*@ hide everything */ -expose (tk_globalvars), /* except these */ -$tn$ namelist xefef tblds rows keylist nmlist maxlen -cs_tv = Trace() -if branch then call BRANCH -address ISPEXEC -maxlen = 0 /* maximum line length */ -do forever -"TBSKIP" $tn$ "SAVENAME(xvars)" -if rc > 0 then leave /* we're done... */ -line = "" /* set empty */ -do cx = 1 to Words(namelist) -thiswd = Word(namelist,cx) -line = line thiswd xefef Value(thiswd) xefef -end /* cx */ -rc = Trace("O"); rc = Trace(cs_tv) -parse var xvars "(" xvars ")" -line = line "XVARS" xefef xvars xefef -do cx = 1 to Words(xvars) -thiswd = Word(xvars,cx) -line = line thiswd xefef Value(thiswd) xefef -end /* cx */ -rc = Trace("O"); rc = Trace(cs_tv) -maxlen = Max(maxlen,Length(line)) -queue line -end /* forever */ -lines_in_stack = queued() -line = "Contents of" $tn$ "in" tblds, -"("lines_in_stack" rows) KEYS("keylist") NAMES("nmlist")." -push line /* make it the first line */ -maxlen = Max(maxlen,Length(line)) -if monitor then say "Maximum line length is" maxlen -return /*@ CS_SPIN_TBL */ -CZ_DROP_TBL: /*@ */ -if branch then call BRANCH -address ISPEXEC -if s2 = 1 then, /* table was not open at start*/ -"TBEND" $tn$ -return /*@ CZ_DROP_TBL */ -D_PUMP_TBL: /*@ */ -if branch then call BRANCH -address TSO -if monitor then say, -"Writing text." -maxlen = maxlen + 4 + bytes_to_add /* set LRECL */ -vbmax.0 = "NEW CATALOG UNIT(SYSDA) SPACE(1 5) TRACKS", -"RECFM(V B) LRECL("maxlen") BLKSIZE(0)" -vbmax.1 = "SHR" /* if it already exists... */ -tempstat = Sysdsn(outdsn) = "OK" /* 1=exists, 0=missing */ -"ALLOC FI($TMP) DA("outdsn") REU" vbmax.tempstat -rcx = rc -"EXECIO" queued() "DISKW $TMP (FINIS" -rcx = max(rcx,rc) -"FREE FI($TMP)" -if rcx = 0 & sw.0purge then do -address ISPEXEC -"LIBDEF ISPTLIB DATASET ID('"tblds"') STACK" -"TBERASE" $tn$ -if rc = 0 then say $tn$ "was deleted" -"LIBDEF ISPTLIB" -end -return /*@ D_PUMP_TBL */ -LOCAL_PREINIT: /*@ customize opts */ -if branch then call BRANCH -address TSO -return /*@ LOCAL_PREINIT */ -HELP: /*@ */ -address TSO;"CLEAR" -if helpmsg <> "" then do ; say helpmsg; say ""; end -ex_nam = Left(exec_name,8) /* predictable size */ -say " "ex_nam" produces a flattened version of any ISPF table " -say " into a VB-form dataset of minimum necessary LRECL." -say " " -say " The field contents are written in KEYPHRS format " -say " (var .. varval ..) " -say " key-fields first, followed by name-fields, followed by the " -say " names of any extension variables key-phrased by 'XVARS', " -say " followed by the extension variables themselves in KEYPHRS " -say " format. " -say " " -say " The first record on the file identifies the table name, the " -say " source library, the number of rows processed, and the key- and " -say " name-fields. " -say " " -say " more.... " -pull -"CLEAR" -say " Syntax: "ex_nam" (Required)" -say " " -say " (Defaults)" -say " " -say " (Defaults)" -say " " -say " identifies the table to be dumped. " -say " " -say " identifies the ISPF Table library which holds ." -say " If is not specified, ISPTLIB will be " -say " searched to find the correct dataset. " -say " " -say " (default: FLATTBLS.) names the output file. " -say " will be created if it does not exist. " -say " " -say " causes the table to be sorted as indicated before " -say " being dumped. " -say " " -say " (default=0) causes the LRECL of the output dataset " -say " to be extended to enable updating. " -pull -"CLEAR" -say " Debugging tools provided include: " -say " " -say " MONITOR: displays key information throughout processing. " -say " Displays most paragraph names upon entry. " -say " " -say " NOUPDT: by-pass all update logic. " -say " " -say " BRANCH: show all paragraph entries. " -say " " -say " TRACE tv: will use value following TRACE to place the " -say " execution in REXX TRACE Mode. " -say " " -say " " -say " Debugging tools can be accessed in the following manner: " -say " " -say " TSO "ex_nam" parameters (( debug-options " -say " " -say " For example: " -say " " -say " TSO "ex_nam" vt2231 add 17 (( MONITOR TRACE ?R " -address ISPEXEC "CONTROL DISPLAY REFRESH" -exit /*@ HELP */ diff --git a/test/expected_dir/rexx1.rex/rexx/comment b/test/expected_dir/rexx1.rex/rexx/comment deleted file mode 100644 index 7934af6..0000000 --- a/test/expected_dir/rexx1.rex/rexx/comment +++ /dev/null @@ -1,41 +0,0 @@ -/* REXX FLTTBL Cloned from DUMPTBL 960619 to produce a flat -version (up to 32K characters wide) of any ISPF -table. -Written by Frank Clarke, Oldsmar, FL -Impact Analysis -. SYSPROC LA -. SYSPROC TRAPOUT -Modification History -19960918 fxc added some error-checking -19970115 fxc upgrade REXXSKEL from v.960606 to v.970113; add -RESTARTability; -19991231 fxc upgrade REXXSKEL from v.970113 to v.19991109; -RXSKLY2K; DECOMM; LRECL reduced from 32K to "min -needed"; -/* -. ----------------------------------------------------------------- */ -/* -. ----------------------------------------------------------------- */ -/* - was not specified. Locate the table in ISPTLIB. -. ----------------------------------------------------------------- */ -/* -. ----------------------------------------------------------------- */ -/* -. ----------------------------------------------------------------- */ -/* -. Given: contains all the defined names for this table. -The table has been TOPped. -. ----------------------------------------------------------------- */ -/* add blocks of "var .. varvalue .." */ -/* add a block of "XVARS .. xvarlist .." */ -/* add blocks of "xvar .. xvarvalue .." */ -/* -. ----------------------------------------------------------------- */ -/* -. ----------------------------------------------------------------- */ -/* -. ----------------------------------------------------------------- */ -/* -. ----------------------------------------------------------------- */ -/* REXXSKEL back-end removed for space */ diff --git a/test/expected_dir/rhtml1.rhtml b/test/expected_dir/rhtml1.rhtml new file mode 100644 index 0000000..53d1d03 --- /dev/null +++ b/test/expected_dir/rhtml1.rhtml @@ -0,0 +1,25 @@ +html code +html code +html code Ajax table manipulation attempt +ruby code <%= stylesheet_link_tag "style" %> +ruby code <%= javascript_include_tag :defaults %> +html code +html code +html blank +html code
+ruby code <%= @content_for_layout %> +html code
+html blank +ruby code <%= ruby code %>
+html comment +ruby code <%- multi +ruby code lines of code +ruby comment # even inline comments! +ruby code "damn" # that's sweet +html code %> +ruby code
<%= ruby_code %>
+html code +html code diff --git a/test/expected_dir/rhtml1.rhtml/html/blanks b/test/expected_dir/rhtml1.rhtml/html/blanks deleted file mode 100644 index d8263ee..0000000 --- a/test/expected_dir/rhtml1.rhtml/html/blanks +++ /dev/null @@ -1 +0,0 @@ -2 \ No newline at end of file diff --git a/test/expected_dir/rhtml1.rhtml/html/code b/test/expected_dir/rhtml1.rhtml/html/code deleted file mode 100644 index 40165c5..0000000 --- a/test/expected_dir/rhtml1.rhtml/html/code +++ /dev/null @@ -1,10 +0,0 @@ - - -Ajax table manipulation attempt - - -
-
-%> - - diff --git a/test/expected_dir/rhtml1.rhtml/html/comment b/test/expected_dir/rhtml1.rhtml/html/comment deleted file mode 100644 index eaabbad..0000000 --- a/test/expected_dir/rhtml1.rhtml/html/comment +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/test/expected_dir/rhtml1.rhtml/ruby/code b/test/expected_dir/rhtml1.rhtml/ruby/code deleted file mode 100644 index 32b01ec..0000000 --- a/test/expected_dir/rhtml1.rhtml/ruby/code +++ /dev/null @@ -1,9 +0,0 @@ -<%= stylesheet_link_tag "style" %> -<%= javascript_include_tag :defaults %> -<%= @content_for_layout %> -<%= ruby code %>
-<% tricky code %> -<%- multi -lines of code -"damn" # that's sweet -
<%= ruby_code %>
diff --git a/test/expected_dir/rhtml1.rhtml/ruby/comment b/test/expected_dir/rhtml1.rhtml/ruby/comment deleted file mode 100644 index 7529c9d..0000000 --- a/test/expected_dir/rhtml1.rhtml/ruby/comment +++ /dev/null @@ -1 +0,0 @@ -# even inline comments! diff --git a/test/expected_dir/ruby1.rb b/test/expected_dir/ruby1.rb new file mode 100644 index 0000000..25b7f9c --- /dev/null +++ b/test/expected_dir/ruby1.rb @@ -0,0 +1,22 @@ +ruby code require 'foo' +ruby blank +ruby comment #comment +ruby comment #comment +ruby comment #comment with "string" +ruby blank +ruby code module Foo +ruby code class Bar #comment +ruby code def foo +ruby code "double_quoted string" +ruby code "embedded double_quote \"" +ruby code more_code = true +ruby code 'single_quoted string' +ruby code 'embedded single_quote\'' +ruby code more_code = true +ruby code "multiline dquote +ruby code more quote +ruby code # not a comment +ruby code " +ruby code end +ruby code end +ruby code end diff --git a/test/expected_dir/ruby1.rb/ruby/blanks b/test/expected_dir/ruby1.rb/ruby/blanks deleted file mode 100644 index d8263ee..0000000 --- a/test/expected_dir/ruby1.rb/ruby/blanks +++ /dev/null @@ -1 +0,0 @@ -2 \ No newline at end of file diff --git a/test/expected_dir/ruby1.rb/ruby/code b/test/expected_dir/ruby1.rb/ruby/code deleted file mode 100644 index fbbbd4d..0000000 --- a/test/expected_dir/ruby1.rb/ruby/code +++ /dev/null @@ -1,17 +0,0 @@ -require 'foo' -module Foo -class Bar #comment -def foo -"double_quoted string" -"embedded double_quote \"" -more_code = true -'single_quoted string' -'embedded single_quote\'' -more_code = true -"multiline dquote -more quote -# not a comment -" -end -end -end diff --git a/test/expected_dir/ruby1.rb/ruby/comment b/test/expected_dir/ruby1.rb/ruby/comment deleted file mode 100644 index 5e30320..0000000 --- a/test/expected_dir/ruby1.rb/ruby/comment +++ /dev/null @@ -1,3 +0,0 @@ -#comment -#comment -#comment with "string" diff --git a/test/expected_dir/scala1.scala b/test/expected_dir/scala1.scala new file mode 100644 index 0000000..fa67832 --- /dev/null +++ b/test/expected_dir/scala1.scala @@ -0,0 +1,63 @@ +scala code import scala.actors.Actor +scala blank +scala code case object Ping +scala code case object Pong +scala code case object Stop +scala blank +scala comment /** +scala comment * Ping class +scala comment */ +scala code class Ping(count: int, pong: Actor) extends Actor { +scala code def act() { +scala code var pingsLeft = count - 1 +scala code pong ! Ping +scala code while (true) { +scala code receive { +scala code case Pong => +scala code if (pingsLeft % 1000 == 0) +scala code Console.println("Ping: pong") +scala code if (pingsLeft > 0) { +scala code pong ! Ping +scala code pingsLeft -= 1 +scala code } else { +scala code Console.println("Ping: stop") +scala code pong ! Stop +scala code exit() +scala code } +scala code } +scala code } +scala code } +scala code } +scala blank +scala comment /** +scala comment * Pong class +scala comment */ +scala code class Pong extends Actor { +scala code def act() { +scala code var pongCount = 0 +scala code while (true) { +scala code receive { +scala comment //pong back the ping +scala code case Ping => +scala code if (pongCount % 1000 == 0) +scala code Console.println("Pong: ping "+pongCount) +scala code sender ! Pong +scala code pongCount = pongCount + 1 +scala comment //stop ping ponging +scala code case Stop => +scala code Console.println("Pong: stop") +scala code exit() +scala code } +scala code } +scala code } +scala code } +scala blank +scala comment /* +scala comment * And this is the main application, playing a game of ping pong +scala comment */ +scala code object PingPong extends Application { +scala code val pong = new Pong +scala code val ping = new Ping(100000, pong) +scala code ping.start +scala code pong.start +scala code } diff --git a/test/expected_dir/scala1.scala/scala/blanks b/test/expected_dir/scala1.scala/scala/blanks deleted file mode 100644 index bf0d87a..0000000 --- a/test/expected_dir/scala1.scala/scala/blanks +++ /dev/null @@ -1 +0,0 @@ -4 \ No newline at end of file diff --git a/test/expected_dir/scala1.scala/scala/code b/test/expected_dir/scala1.scala/scala/code deleted file mode 100644 index 3392f0c..0000000 --- a/test/expected_dir/scala1.scala/scala/code +++ /dev/null @@ -1,48 +0,0 @@ -import scala.actors.Actor -case object Ping -case object Pong -case object Stop -class Ping(count: int, pong: Actor) extends Actor { -def act() { -var pingsLeft = count - 1 -pong ! Ping -while (true) { -receive { -case Pong => -if (pingsLeft % 1000 == 0) -Console.println("Ping: pong") -if (pingsLeft > 0) { -pong ! Ping -pingsLeft -= 1 -} else { -Console.println("Ping: stop") -pong ! Stop -exit() -} -} -} -} -} -class Pong extends Actor { -def act() { -var pongCount = 0 -while (true) { -receive { -case Ping => -if (pongCount % 1000 == 0) -Console.println("Pong: ping "+pongCount) -sender ! Pong -pongCount = pongCount + 1 -case Stop => -Console.println("Pong: stop") -exit() -} -} -} -} -object PingPong extends Application { -val pong = new Pong -val ping = new Ping(100000, pong) -ping.start -pong.start -} diff --git a/test/expected_dir/scala1.scala/scala/comment b/test/expected_dir/scala1.scala/scala/comment deleted file mode 100644 index 3aaaee9..0000000 --- a/test/expected_dir/scala1.scala/scala/comment +++ /dev/null @@ -1,11 +0,0 @@ -/** -* Ping class -*/ -/** -* Pong class -*/ -//pong back the ping -//stop ping ponging -/* -* And this is the main application, playing a game of ping pong -*/ diff --git a/test/expected_dir/schema.xsd b/test/expected_dir/schema.xsd new file mode 100644 index 0000000..59df2e6 --- /dev/null +++ b/test/expected_dir/schema.xsd @@ -0,0 +1,68 @@ +xmlschema code +xmlschema comment +xmlschema code +xmlschema code +xmlschema code +xmlschema code 0836217462 +xmlschema code +xmlschema code +xmlschema code Being a Dog Is a Full-Time Job +xmlschema code +xmlschema code +xmlschema code +xmlschema code Charles M Schulz +xmlschema code +xmlschema code +xmlschema code 1922-11-26 +xmlschema code +xmlschema code +xmlschema code 2000-02-12 +xmlschema code +xmlschema code +xmlschema code +xmlschema code +xmlschema code Peppermint Patty +xmlschema code +xmlschema code +xmlschema code 1966-08-22 +xmlschema code +xmlschema code +xmlschema code bold, brash and tomboyish +xmlschema code +xmlschema code +xmlschema code +xmlschema code +xmlschema code Snoopy +xmlschema code +xmlschema code +xmlschema code 1950-10-04 +xmlschema code +xmlschema code +xmlschema code extroverted beagle +xmlschema code +xmlschema code +xmlschema code +xmlschema code +xmlschema code Schroeder +xmlschema code +xmlschema code +xmlschema code 1951-05-30 +xmlschema code +xmlschema code +xmlschema code brought classical music to the Peanuts strip +xmlschema code +xmlschema code +xmlschema code +xmlschema code +xmlschema code Lucy +xmlschema code +xmlschema code +xmlschema code 1952-03-03 +xmlschema code +xmlschema code +xmlschema code bossy, crabby and selfish +xmlschema code +xmlschema code +xmlschema code +xmlschema code diff --git a/test/expected_dir/schema.xsd/xmlschema/blanks b/test/expected_dir/schema.xsd/xmlschema/blanks deleted file mode 100644 index c227083..0000000 --- a/test/expected_dir/schema.xsd/xmlschema/blanks +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/test/expected_dir/schema.xsd/xmlschema/code b/test/expected_dir/schema.xsd/xmlschema/code deleted file mode 100644 index aed5bad..0000000 --- a/test/expected_dir/schema.xsd/xmlschema/code +++ /dev/null @@ -1,66 +0,0 @@ - - - - -0836217462 - - -Being a Dog Is a Full-Time Job - - - -Charles M Schulz - - -1922-11-26 - - -2000-02-12 - - - - -Peppermint Patty - - -1966-08-22 - - -bold, brash and tomboyish - - - - -Snoopy - - -1950-10-04 - - -extroverted beagle - - - - -Schroeder - - -1951-05-30 - - -brought classical music to the Peanuts strip - - - - -Lucy - - -1952-03-03 - - -bossy, crabby and selfish - - - - diff --git a/test/expected_dir/schema.xsd/xmlschema/comment b/test/expected_dir/schema.xsd/xmlschema/comment deleted file mode 100644 index 578e50a..0000000 --- a/test/expected_dir/schema.xsd/xmlschema/comment +++ /dev/null @@ -1,2 +0,0 @@ - diff --git a/test/expected_dir/scheme.scm b/test/expected_dir/scheme.scm new file mode 100644 index 0000000..5db5fdc --- /dev/null +++ b/test/expected_dir/scheme.scm @@ -0,0 +1,32 @@ +scheme code (+ 1 (/ 1 0) 3) +scheme comment ; => A divide by zero error is raised +scheme blank +scheme code (with-failure-continuation +scheme code (lambda (error-record error-k) +scheme code 'error) +scheme code (lambda () (+ 1 (/ 1 0) 3))) +scheme comment ; => The symbol 'error +scheme blank +scheme code (with-failure-continuation +scheme code (lambda (error-record error-k) +scheme code (error-k 2)) +scheme code (lambda () (+ 1 (/ 1 0) 3))) +scheme comment ; => 6 +scheme blank +scheme code (with-failure-continuation +scheme code (lambda (error-record error-k) +scheme code (throw error-record error-k)) +scheme code (lambda () (+ 1 (/ 1 0) 3))) +scheme comment ; => A divide by zero error is raised +scheme blank +scheme code (with-failure-continuation +scheme code (lambda (error-record error-k) +scheme code (throw (make-error '/ "could not perform the division.") error-k)) +scheme code (lambda () (+ 1 (/ 1 0) 3))) +scheme comment ; => An error is raised: Error in /: could not perform the division. +scheme blank +scheme code (with-failure-continuation +scheme code (lambda (error-record error-k) +scheme code (error 'example-function "could not evaluate the expression.")) +scheme code (lambda () (+ 1 (/ 1 0) 3))) +scheme comment ; => An error is raised: Error in example-function: could not evaluate the expression. diff --git a/test/expected_dir/scheme.scm/scheme/blanks b/test/expected_dir/scheme.scm/scheme/blanks deleted file mode 100644 index 7813681..0000000 --- a/test/expected_dir/scheme.scm/scheme/blanks +++ /dev/null @@ -1 +0,0 @@ -5 \ No newline at end of file diff --git a/test/expected_dir/scheme.scm/scheme/code b/test/expected_dir/scheme.scm/scheme/code deleted file mode 100644 index 21821bb..0000000 --- a/test/expected_dir/scheme.scm/scheme/code +++ /dev/null @@ -1,21 +0,0 @@ -(+ 1 (/ 1 0) 3) -(with-failure-continuation -(lambda (error-record error-k) -'error) -(lambda () (+ 1 (/ 1 0) 3))) -(with-failure-continuation -(lambda (error-record error-k) -(error-k 2)) -(lambda () (+ 1 (/ 1 0) 3))) -(with-failure-continuation -(lambda (error-record error-k) -(throw error-record error-k)) -(lambda () (+ 1 (/ 1 0) 3))) -(with-failure-continuation -(lambda (error-record error-k) -(throw (make-error '/ "could not perform the division.") error-k)) -(lambda () (+ 1 (/ 1 0) 3))) -(with-failure-continuation -(lambda (error-record error-k) -(error 'example-function "could not evaluate the expression.")) -(lambda () (+ 1 (/ 1 0) 3))) diff --git a/test/expected_dir/scheme.scm/scheme/comment b/test/expected_dir/scheme.scm/scheme/comment deleted file mode 100644 index 9ca013b..0000000 --- a/test/expected_dir/scheme.scm/scheme/comment +++ /dev/null @@ -1,6 +0,0 @@ -; => A divide by zero error is raised -; => The symbol 'error -; => 6 -; => A divide by zero error is raised -; => An error is raised: Error in /: could not perform the division. -; => An error is raised: Error in example-function: could not evaluate the expression. diff --git a/test/expected_dir/sh1.sh b/test/expected_dir/sh1.sh new file mode 100644 index 0000000..665557c --- /dev/null +++ b/test/expected_dir/sh1.sh @@ -0,0 +1,5 @@ +shell comment #!/bin/sh +shell blank +shell code ls -la +shell comment # comment +shell code echo hello #comment diff --git a/test/expected_dir/sh1.sh/shell/blanks b/test/expected_dir/sh1.sh/shell/blanks deleted file mode 100644 index 56a6051..0000000 --- a/test/expected_dir/sh1.sh/shell/blanks +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/test/expected_dir/sh1.sh/shell/code b/test/expected_dir/sh1.sh/shell/code deleted file mode 100644 index 6c62c92..0000000 --- a/test/expected_dir/sh1.sh/shell/code +++ /dev/null @@ -1,2 +0,0 @@ -ls -la -echo hello #comment diff --git a/test/expected_dir/sh1.sh/shell/comment b/test/expected_dir/sh1.sh/shell/comment deleted file mode 100644 index 904cf48..0000000 --- a/test/expected_dir/sh1.sh/shell/comment +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -# comment diff --git a/test/expected_dir/smalltalk1.st b/test/expected_dir/smalltalk1.st new file mode 100644 index 0000000..07859e5 --- /dev/null +++ b/test/expected_dir/smalltalk1.st @@ -0,0 +1,19 @@ +smalltalk comment "====================================================================== +smalltalk comment | +smalltalk comment | Benchmark for streams +smalltalk comment | +smalltalk comment | +smalltalk comment ======================================================================" +smalltalk blank +smalltalk blank +smalltalk code Eval [ +smalltalk code n := Smalltalk arguments isEmpty +smalltalk code ifTrue: [ 10000 ] +smalltalk code ifFalse: [ 1 max: Smalltalk arguments first asInteger ]. +smalltalk blank +smalltalk code hello := String new writeStream. +smalltalk code n timesRepeat: [ hello nextPutAll: 'hello +smalltalk code \' ]. "this is a comment +smalltalk comment so this line is a comment too\" +smalltalk code hello position displayNl +smalltalk code "but the previous one, and this one too, are not!" ] diff --git a/test/expected_dir/smalltalk1.st/smalltalk/blanks b/test/expected_dir/smalltalk1.st/smalltalk/blanks deleted file mode 100644 index e440e5c..0000000 --- a/test/expected_dir/smalltalk1.st/smalltalk/blanks +++ /dev/null @@ -1 +0,0 @@ -3 \ No newline at end of file diff --git a/test/expected_dir/smalltalk1.st/smalltalk/code b/test/expected_dir/smalltalk1.st/smalltalk/code deleted file mode 100644 index d1ff6de..0000000 --- a/test/expected_dir/smalltalk1.st/smalltalk/code +++ /dev/null @@ -1,9 +0,0 @@ -Eval [ -n := Smalltalk arguments isEmpty -ifTrue: [ 10000 ] -ifFalse: [ 1 max: Smalltalk arguments first asInteger ]. -hello := String new writeStream. -n timesRepeat: [ hello nextPutAll: 'hello -\' ]. "this is a comment -hello position displayNl -"but the previous one, and this one too, are not!" ] diff --git a/test/expected_dir/smalltalk1.st/smalltalk/comment b/test/expected_dir/smalltalk1.st/smalltalk/comment deleted file mode 100644 index fb20617..0000000 --- a/test/expected_dir/smalltalk1.st/smalltalk/comment +++ /dev/null @@ -1,7 +0,0 @@ -"====================================================================== -| -| Benchmark for streams -| -| -======================================================================" -so this line is a comment too\" diff --git a/test/expected_dir/sql1.sql b/test/expected_dir/sql1.sql new file mode 100644 index 0000000..ed8ecd9 --- /dev/null +++ b/test/expected_dir/sql1.sql @@ -0,0 +1,31 @@ +sql comment // ----------------------------------------------------------------------- +sql comment // Filename: minvalue.sql +sql comment // Purpose: Select the Nth lowest value from a table +sql comment // Date: 18-Apr-2001 +sql comment // Author: Deepak Rai, SSE, Satyam Computer Services Ltd. India +sql comment // ----------------------------------------------------------------------- +sql blank +sql comment ## Comment with a hash symbol ## +sql code select level, min('col_name') from my_table +sql code where level = '&n' +sql code connect by prior ('col_name') < 'col_name') +sql code group by level; +sql blank +sql comment /* a block comment +sql comment -- finished here */ +sql blank +sql comment -- Example: +sql comment -- +sql comment -- Given a table called emp with the following columns: +sql comment -- id number +sql comment -- name varchar2(20) +sql comment -- sal number +sql comment -- +sql comment -- For the second lowest salary: +sql comment -- +sql comment -- select level, min(sal) from emp +sql comment -- where level=2 +sql comment -- connect by prior sal < sal +sql comment -- group by level +sql comment -- +sql blank diff --git a/test/expected_dir/sql1.sql/sql/blanks b/test/expected_dir/sql1.sql/sql/blanks deleted file mode 100644 index bf0d87a..0000000 --- a/test/expected_dir/sql1.sql/sql/blanks +++ /dev/null @@ -1 +0,0 @@ -4 \ No newline at end of file diff --git a/test/expected_dir/sql1.sql/sql/code b/test/expected_dir/sql1.sql/sql/code deleted file mode 100644 index c59b1f8..0000000 --- a/test/expected_dir/sql1.sql/sql/code +++ /dev/null @@ -1,4 +0,0 @@ -select level, min('col_name') from my_table -where level = '&n' -connect by prior ('col_name') < 'col_name') -group by level; diff --git a/test/expected_dir/sql1.sql/sql/comment b/test/expected_dir/sql1.sql/sql/comment deleted file mode 100644 index 85fac5d..0000000 --- a/test/expected_dir/sql1.sql/sql/comment +++ /dev/null @@ -1,23 +0,0 @@ -// ----------------------------------------------------------------------- -// Filename: minvalue.sql -// Purpose: Select the Nth lowest value from a table -// Date: 18-Apr-2001 -// Author: Deepak Rai, SSE, Satyam Computer Services Ltd. India -// ----------------------------------------------------------------------- -## Comment with a hash symbol ## -/* a block comment --- finished here */ --- Example: --- --- Given a table called emp with the following columns: --- id number --- name varchar2(20) --- sal number --- --- For the second lowest salary: --- --- select level, min(sal) from emp --- where level=2 --- connect by prior sal < sal --- group by level --- diff --git a/test/expected_dir/stratego.str b/test/expected_dir/stratego.str new file mode 100644 index 0000000..483596d --- /dev/null +++ b/test/expected_dir/stratego.str @@ -0,0 +1,25 @@ +stratego comment /** +stratego comment * Sample code from Stratego XT Manual +stratego comment */ +stratego blank +stratego code rules +stratego code InlineF : +stratego code |[ let f(xs) = e in e'[f(es)] ]| -> +stratego code |[ let f(xs) = e in e'[e[es/xs]] ]| +stratego blank +stratego code InlineV : +stratego code |[ let x = e in e'[x] ]| -> |[ let x = e in e'[e] ]| +stratego blank +stratego code Dead : +stratego code |[ let x = e in e' ]| -> |[ e' ]| +stratego code where (x,e') +stratego blank +stratego code Extract(f,xs) : +stratego code |[ e ]| -> |[ let f(xs) = e in f(xs) ]| +stratego blank +stratego code Hoist : +stratego code |[ let x = e1 in let f(xs) = e2 in e3 ]| -> +stratego code |[ let f(xs) = e2 in let x = e1 in e3 ]| +stratego code where (x, e2) +stratego blank +stratego comment // better watch those apostrophes! diff --git a/test/expected_dir/stratego.str/stratego/blanks b/test/expected_dir/stratego.str/stratego/blanks deleted file mode 100644 index 62f9457..0000000 --- a/test/expected_dir/stratego.str/stratego/blanks +++ /dev/null @@ -1 +0,0 @@ -6 \ No newline at end of file diff --git a/test/expected_dir/stratego.str/stratego/code b/test/expected_dir/stratego.str/stratego/code deleted file mode 100644 index a87e954..0000000 --- a/test/expected_dir/stratego.str/stratego/code +++ /dev/null @@ -1,15 +0,0 @@ -rules -InlineF : -|[ let f(xs) = e in e'[f(es)] ]| -> -|[ let f(xs) = e in e'[e[es/xs]] ]| -InlineV : -|[ let x = e in e'[x] ]| -> |[ let x = e in e'[e] ]| -Dead : -|[ let x = e in e' ]| -> |[ e' ]| -where (x,e') -Extract(f,xs) : -|[ e ]| -> |[ let f(xs) = e in f(xs) ]| -Hoist : -|[ let x = e1 in let f(xs) = e2 in e3 ]| -> -|[ let f(xs) = e2 in let x = e1 in e3 ]| -where (x, e2) diff --git a/test/expected_dir/stratego.str/stratego/comment b/test/expected_dir/stratego.str/stratego/comment deleted file mode 100644 index 517a505..0000000 --- a/test/expected_dir/stratego.str/stratego/comment +++ /dev/null @@ -1,4 +0,0 @@ -/** -* Sample code from Stratego XT Manual -*/ -// better watch those apostrophes! diff --git a/test/expected_dir/structured_basic.b b/test/expected_dir/structured_basic.b new file mode 100644 index 0000000..00a1759 --- /dev/null +++ b/test/expected_dir/structured_basic.b @@ -0,0 +1,20 @@ +structured_basic code INPUT "What is your name: "; U$ +structured_basic code PRINT "Hello "; U$ +structured_basic comment REM Test +structured_basic code INPUT "How many stars do you want: "; N +structured_basic code S$ = "" +structured_basic code FOR I = 1 TO N +structured_basic code S$ = S$ + "*" +structured_basic code NEXT I +structured_basic code PRINT S$ +structured_basic blank +structured_basic comment REM +structured_basic code INPUT "Do you want more stars? "; A$ +structured_basic code IF LEN(A$) = 0 THEN GOTO 110 +structured_basic code A$ = LEFT$(A$, 1) +structured_basic code IF (A$ = "Y") OR (A$ = "y") THEN GOTO 40 +structured_basic code PRINT "Goodbye "; +structured_basic code FOR I = 1 TO 200 +structured_basic code PRINT U$; " "; +structured_basic code NEXT I +structured_basic code PRINT diff --git a/test/expected_dir/structured_basic.b/structured_basic/blanks b/test/expected_dir/structured_basic.b/structured_basic/blanks deleted file mode 100644 index 56a6051..0000000 --- a/test/expected_dir/structured_basic.b/structured_basic/blanks +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/test/expected_dir/structured_basic.b/structured_basic/code b/test/expected_dir/structured_basic.b/structured_basic/code deleted file mode 100644 index eb8a81a..0000000 --- a/test/expected_dir/structured_basic.b/structured_basic/code +++ /dev/null @@ -1,17 +0,0 @@ -INPUT "What is your name: "; U$ -PRINT "Hello "; U$ -INPUT "How many stars do you want: "; N -S$ = "" -FOR I = 1 TO N -S$ = S$ + "*" -NEXT I -PRINT S$ -INPUT "Do you want more stars? "; A$ -IF LEN(A$) = 0 THEN GOTO 110 -A$ = LEFT$(A$, 1) -IF (A$ = "Y") OR (A$ = "y") THEN GOTO 40 -PRINT "Goodbye "; -FOR I = 1 TO 200 -PRINT U$; " "; -NEXT I -PRINT diff --git a/test/expected_dir/structured_basic.b/structured_basic/comment b/test/expected_dir/structured_basic.b/structured_basic/comment deleted file mode 100644 index 8d21989..0000000 --- a/test/expected_dir/structured_basic.b/structured_basic/comment +++ /dev/null @@ -1,2 +0,0 @@ -REM Test -REM diff --git a/test/expected_dir/structured_basic.bas b/test/expected_dir/structured_basic.bas new file mode 100644 index 0000000..00a1759 --- /dev/null +++ b/test/expected_dir/structured_basic.bas @@ -0,0 +1,20 @@ +structured_basic code INPUT "What is your name: "; U$ +structured_basic code PRINT "Hello "; U$ +structured_basic comment REM Test +structured_basic code INPUT "How many stars do you want: "; N +structured_basic code S$ = "" +structured_basic code FOR I = 1 TO N +structured_basic code S$ = S$ + "*" +structured_basic code NEXT I +structured_basic code PRINT S$ +structured_basic blank +structured_basic comment REM +structured_basic code INPUT "Do you want more stars? "; A$ +structured_basic code IF LEN(A$) = 0 THEN GOTO 110 +structured_basic code A$ = LEFT$(A$, 1) +structured_basic code IF (A$ = "Y") OR (A$ = "y") THEN GOTO 40 +structured_basic code PRINT "Goodbye "; +structured_basic code FOR I = 1 TO 200 +structured_basic code PRINT U$; " "; +structured_basic code NEXT I +structured_basic code PRINT diff --git a/test/expected_dir/structured_basic.bas/structured_basic/blanks b/test/expected_dir/structured_basic.bas/structured_basic/blanks deleted file mode 100644 index 56a6051..0000000 --- a/test/expected_dir/structured_basic.bas/structured_basic/blanks +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/test/expected_dir/structured_basic.bas/structured_basic/code b/test/expected_dir/structured_basic.bas/structured_basic/code deleted file mode 100644 index eb8a81a..0000000 --- a/test/expected_dir/structured_basic.bas/structured_basic/code +++ /dev/null @@ -1,17 +0,0 @@ -INPUT "What is your name: "; U$ -PRINT "Hello "; U$ -INPUT "How many stars do you want: "; N -S$ = "" -FOR I = 1 TO N -S$ = S$ + "*" -NEXT I -PRINT S$ -INPUT "Do you want more stars? "; A$ -IF LEN(A$) = 0 THEN GOTO 110 -A$ = LEFT$(A$, 1) -IF (A$ = "Y") OR (A$ = "y") THEN GOTO 40 -PRINT "Goodbye "; -FOR I = 1 TO 200 -PRINT U$; " "; -NEXT I -PRINT diff --git a/test/expected_dir/structured_basic.bas/structured_basic/comment b/test/expected_dir/structured_basic.bas/structured_basic/comment deleted file mode 100644 index 8d21989..0000000 --- a/test/expected_dir/structured_basic.bas/structured_basic/comment +++ /dev/null @@ -1,2 +0,0 @@ -REM Test -REM diff --git a/test/expected_dir/tcl1.tcl b/test/expected_dir/tcl1.tcl new file mode 100644 index 0000000..eeccd1a --- /dev/null +++ b/test/expected_dir/tcl1.tcl @@ -0,0 +1,35 @@ +tcl comment #!/usr/local/bin/tclsh +tcl blank +tcl comment # Dos2Unix +tcl comment # Convert a file to Unix-style line endings +tcl comment # If the file is a directory, then recursively +tcl comment # convert all the files in the directory and below. +tcl comment # +tcl comment # Arguments +tcl comment # f The name of a file or directory. +tcl comment # +tcl comment # Side Effects: +tcl comment # Rewrites the file to have LF line-endings +tcl blank +tcl code proc Dos2Unix {f} { +tcl code puts $f +tcl code if {[file isdirectory $f]} { +tcl code foreach g [glob [file join $f *]] { +tcl code Dos2Unix $g +tcl code } +tcl code } else { +tcl code set in [open $f] +tcl code set out [open $f.new w] +tcl code fconfigure $out -translation lf +tcl code puts -nonewline $out [read $in] +tcl code close $out +tcl code close $in +tcl code file rename -force $f.new $f +tcl code } +tcl code } +tcl blank +tcl comment # Process each command-line argument +tcl blank +tcl code foreach f $argv { +tcl code Dos2Unix $f +tcl code } diff --git a/test/expected_dir/tcl1.tcl/tcl/blanks b/test/expected_dir/tcl1.tcl/tcl/blanks deleted file mode 100644 index bf0d87a..0000000 --- a/test/expected_dir/tcl1.tcl/tcl/blanks +++ /dev/null @@ -1 +0,0 @@ -4 \ No newline at end of file diff --git a/test/expected_dir/tcl1.tcl/tcl/code b/test/expected_dir/tcl1.tcl/tcl/code deleted file mode 100644 index 51f4412..0000000 --- a/test/expected_dir/tcl1.tcl/tcl/code +++ /dev/null @@ -1,19 +0,0 @@ -proc Dos2Unix {f} { -puts $f -if {[file isdirectory $f]} { -foreach g [glob [file join $f *]] { -Dos2Unix $g -} -} else { -set in [open $f] -set out [open $f.new w] -fconfigure $out -translation lf -puts -nonewline $out [read $in] -close $out -close $in -file rename -force $f.new $f -} -} -foreach f $argv { -Dos2Unix $f -} diff --git a/test/expected_dir/tcl1.tcl/tcl/comment b/test/expected_dir/tcl1.tcl/tcl/comment deleted file mode 100644 index 0ed0d7b..0000000 --- a/test/expected_dir/tcl1.tcl/tcl/comment +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/local/bin/tclsh -# Dos2Unix -# Convert a file to Unix-style line endings -# If the file is a directory, then recursively -# convert all the files in the directory and below. -# -# Arguments -# f The name of a file or directory. -# -# Side Effects: -# Rewrites the file to have LF line-endings -# Process each command-line argument diff --git a/test/expected_dir/vala1.vala b/test/expected_dir/vala1.vala new file mode 100644 index 0000000..1453c0d --- /dev/null +++ b/test/expected_dir/vala1.vala @@ -0,0 +1,61 @@ +vala code using GLib; +vala blank +vala blank +vala blank +vala comment // Class which makes the event +vala code public class Game : Object { +vala comment // Note the use of the signal keyword +vala code public signal void score_change (int newScore, ref bool cancel); +vala blank +vala code int _score; +vala blank +vala comment // Score Property +vala code public int score { +vala code get { +vala code return _score; +vala code } +vala code set { +vala code if (_score != value) { +vala code bool cancel = false; +vala code score_change (value, ref cancel); +vala code if (! cancel) +vala code _score = value; +vala code } +vala code } +vala code } +vala code } +vala blank +vala comment // Class which handles the event +vala code public class Referee : Object +vala code { +vala code public Game game { get; construct; } +vala blank +vala code public Referee (construct Game game) { +vala code } +vala blank +vala code construct { +vala comment // Monitor when a score changes in the game +vala code game.score_change += game_score_change; +vala code } +vala blank +vala comment // Notice how this method signature matches the score_change signal's signature +vala code private void game_score_change (Game game, int new_score, ref bool cancel) { +vala code if (new_score < 100) +vala code stdout.printf ("Good Score\n"); +vala code else { +vala code cancel = true; +vala code stdout.printf ("No Score can be that high!\n"); +vala code } +vala code } +vala code } +vala blank +vala comment // Class to test it all +vala code public class GameTest : Object +vala code { +vala code public static void main () { +vala code var game = new Game (); +vala code var referee = new Referee (game); +vala code game.score = 70; +vala code game.score = 110; +vala code } +vala code } diff --git a/test/expected_dir/vala1.vala/vala/blanks b/test/expected_dir/vala1.vala/vala/blanks deleted file mode 100644 index 9a03714..0000000 --- a/test/expected_dir/vala1.vala/vala/blanks +++ /dev/null @@ -1 +0,0 @@ -10 \ No newline at end of file diff --git a/test/expected_dir/vala1.vala/vala/code b/test/expected_dir/vala1.vala/vala/code deleted file mode 100644 index 3d1283c..0000000 --- a/test/expected_dir/vala1.vala/vala/code +++ /dev/null @@ -1,44 +0,0 @@ -using GLib; -public class Game : Object { -public signal void score_change (int newScore, ref bool cancel); -int _score; -public int score { -get { -return _score; -} -set { -if (_score != value) { -bool cancel = false; -score_change (value, ref cancel); -if (! cancel) -_score = value; -} -} -} -} -public class Referee : Object -{ -public Game game { get; construct; } -public Referee (construct Game game) { -} -construct { -game.score_change += game_score_change; -} -private void game_score_change (Game game, int new_score, ref bool cancel) { -if (new_score < 100) -stdout.printf ("Good Score\n"); -else { -cancel = true; -stdout.printf ("No Score can be that high!\n"); -} -} -} -public class GameTest : Object -{ -public static void main () { -var game = new Game (); -var referee = new Referee (game); -game.score = 70; -game.score = 110; -} -} diff --git a/test/expected_dir/vala1.vala/vala/comment b/test/expected_dir/vala1.vala/vala/comment deleted file mode 100644 index 7f2c745..0000000 --- a/test/expected_dir/vala1.vala/vala/comment +++ /dev/null @@ -1,7 +0,0 @@ -// Class which makes the event -// Note the use of the signal keyword -// Score Property -// Class which handles the event -// Monitor when a score changes in the game -// Notice how this method signature matches the score_change signal's signature -// Class to test it all diff --git a/test/expected_dir/vb1.vb b/test/expected_dir/vb1.vb new file mode 100644 index 0000000..d450687 --- /dev/null +++ b/test/expected_dir/vb1.vb @@ -0,0 +1,16 @@ +visualbasic code class foo +visualbasic comment ' comment +visualbasic blank +visualbasic code require File.dirname(__FILE__) + '/../test_helper' +visualbasic code include Lingo +visualbasic blank +visualbasic code class ShellTest < LingoTest +visualbasic code def test_comment +visualbasic code p = Languages::Shell.parse(" #comment") +visualbasic code assert_equal({ 'shell' => { :comment => [" #comment"] } }, p.output_buffers) +visualbasic code end +visualbasic blank +visualbasic code def test_comprehensive +visualbasic code verify_parse("sh1.sh") +visualbasic code end +visualbasic code end diff --git a/test/expected_dir/vbs1.vbs b/test/expected_dir/vbs1.vbs new file mode 100644 index 0000000..639b463 --- /dev/null +++ b/test/expected_dir/vbs1.vbs @@ -0,0 +1,14 @@ +visualbasic blank +visualbasic code require File.dirname(__FILE__) + '/../test_helper' +visualbasic code include Lingo +visualbasic blank +visualbasic code class ShellTest < LingoTest +visualbasic code def test_comment +visualbasic code p = Languages::Shell.parse(" #comment") +visualbasic code assert_equal({ 'shell' => { :comment => [" #comment"] } }, p.output_buffers) +visualbasic code end +visualbasic blank +visualbasic code def test_comprehensive +visualbasic code verify_parse("sh1.sh") +visualbasic code end +visualbasic code end diff --git a/test/expected_dir/vhdl1.vhd b/test/expected_dir/vhdl1.vhd new file mode 100644 index 0000000..64fd306 --- /dev/null +++ b/test/expected_dir/vhdl1.vhd @@ -0,0 +1,92 @@ +vhdl comment ------------------------------------------------------------ +vhdl comment -- Combinational Logic Design +vhdl comment -- (ESD book figure 2.4) +vhdl comment -- by Weijun Zhang, 04/2001 +vhdl comment -- +vhdl comment -- A simple example of VHDL Structure Modeling +vhdl comment -- we might define two components in two separate files, +vhdl comment -- in main file, we use port map statement to instantiate +vhdl comment -- the mapping relationship between each components +vhdl comment -- and the entire circuit. +vhdl comment ------------------------------------------------------------ +vhdl blank +vhdl code library ieee; -- component #1 +vhdl code use ieee.std_logic_1164.all; +vhdl blank +vhdl code entity OR_GATE is +vhdl code port( X: in std_logic; +vhdl code Y: in std_logic; +vhdl code F2: out std_logic +vhdl code ); +vhdl code end OR_GATE; +vhdl blank +vhdl code architecture behv of OR_GATE is +vhdl code begin +vhdl code process(X,Y) +vhdl code begin +vhdl code F2 <= X or Y; -- behavior des. +vhdl code end process; +vhdl code end behv; +vhdl blank +vhdl comment ------------------------------------------------------------- +vhdl blank +vhdl code library ieee; -- component #2 +vhdl code use ieee.std_logic_1164.all; +vhdl blank +vhdl code entity AND_GATE is +vhdl code port( A: in std_logic; +vhdl code B: in std_logic; +vhdl code F1: out std_logic +vhdl code ); +vhdl code end AND_GATE; +vhdl blank +vhdl code architecture behv of AND_GATE is +vhdl code begin +vhdl code process(A,B) +vhdl code begin +vhdl code F1 <= A and B; -- behavior des. +vhdl code end process; +vhdl code end behv; +vhdl blank +vhdl comment -------------------------------------------------------------- +vhdl blank +vhdl code library ieee; -- top level circuit +vhdl code use ieee.std_logic_1164.all; +vhdl code use work.all; +vhdl blank +vhdl code entity comb_ckt is +vhdl code port( input1: in std_logic; +vhdl code input2: in std_logic; +vhdl code input3: in std_logic; +vhdl code output: out std_logic +vhdl code ); +vhdl code end comb_ckt; +vhdl blank +vhdl code architecture struct of comb_ckt is +vhdl blank +vhdl code component AND_GATE is -- as entity of AND_GATE +vhdl code port( A: in std_logic; +vhdl code B: in std_logic; +vhdl code F1: out std_logic +vhdl code ); +vhdl code end component; +vhdl blank +vhdl code component OR_GATE is -- as entity of OR_GATE +vhdl code port( X: in std_logic; +vhdl code Y: in std_logic; +vhdl code F2: out std_logic +vhdl code ); +vhdl code end component; +vhdl blank +vhdl code signal wire: std_logic; -- signal just like wire +vhdl blank +vhdl code begin +vhdl blank +vhdl comment -- use sign "=>" to clarify the pin mapping +vhdl blank +vhdl code Gate1: AND_GATE port map (A=>input1, B=>input2, F1=>wire); +vhdl code Gate2: OR_GATE port map (X=>wire, Y=>input3, F2=>output); +vhdl blank +vhdl code end struct; +vhdl blank +vhdl comment ---------------------------------------------------------------- diff --git a/test/expected_dir/vhdl1.vhd/vhdl/blanks b/test/expected_dir/vhdl1.vhd/vhdl/blanks deleted file mode 100644 index dec2bf5..0000000 --- a/test/expected_dir/vhdl1.vhd/vhdl/blanks +++ /dev/null @@ -1 +0,0 @@ -19 \ No newline at end of file diff --git a/test/expected_dir/vhdl1.vhd/vhdl/code b/test/expected_dir/vhdl1.vhd/vhdl/code deleted file mode 100644 index cfeaccf..0000000 --- a/test/expected_dir/vhdl1.vhd/vhdl/code +++ /dev/null @@ -1,58 +0,0 @@ -library ieee; -- component #1 -use ieee.std_logic_1164.all; -entity OR_GATE is -port( X: in std_logic; -Y: in std_logic; -F2: out std_logic -); -end OR_GATE; -architecture behv of OR_GATE is -begin -process(X,Y) -begin -F2 <= X or Y; -- behavior des. -end process; -end behv; -library ieee; -- component #2 -use ieee.std_logic_1164.all; -entity AND_GATE is -port( A: in std_logic; -B: in std_logic; -F1: out std_logic -); -end AND_GATE; -architecture behv of AND_GATE is -begin -process(A,B) -begin -F1 <= A and B; -- behavior des. -end process; -end behv; -library ieee; -- top level circuit -use ieee.std_logic_1164.all; -use work.all; -entity comb_ckt is -port( input1: in std_logic; -input2: in std_logic; -input3: in std_logic; -output: out std_logic -); -end comb_ckt; -architecture struct of comb_ckt is -component AND_GATE is -- as entity of AND_GATE -port( A: in std_logic; -B: in std_logic; -F1: out std_logic -); -end component; -component OR_GATE is -- as entity of OR_GATE -port( X: in std_logic; -Y: in std_logic; -F2: out std_logic -); -end component; -signal wire: std_logic; -- signal just like wire -begin -Gate1: AND_GATE port map (A=>input1, B=>input2, F1=>wire); -Gate2: OR_GATE port map (X=>wire, Y=>input3, F2=>output); -end struct; diff --git a/test/expected_dir/vhdl1.vhd/vhdl/comment b/test/expected_dir/vhdl1.vhd/vhdl/comment deleted file mode 100644 index 4430e90..0000000 --- a/test/expected_dir/vhdl1.vhd/vhdl/comment +++ /dev/null @@ -1,15 +0,0 @@ ------------------------------------------------------------- --- Combinational Logic Design --- (ESD book figure 2.4) --- by Weijun Zhang, 04/2001 --- --- A simple example of VHDL Structure Modeling --- we might define two components in two separate files, --- in main file, we use port map statement to instantiate --- the mapping relationship between each components --- and the entire circuit. ------------------------------------------------------------- -------------------------------------------------------------- --------------------------------------------------------------- --- use sign "=>" to clarify the pin mapping ----------------------------------------------------------------- diff --git a/test/expected_dir/vhdl1.vhdl b/test/expected_dir/vhdl1.vhdl new file mode 100644 index 0000000..379aaa6 --- /dev/null +++ b/test/expected_dir/vhdl1.vhdl @@ -0,0 +1,40 @@ +vhdl code library ieee; +vhdl code use ieee.std_logic_1164.all; +vhdl blank +vhdl code entity tb is +vhdl code end tb; +vhdl blank +vhdl code architecture behav of tb is +vhdl blank +vhdl comment -- toggle period +vhdl code constant period_c : time := 1 ms; +vhdl blank +vhdl comment -- we'll be poking on this signal +vhdl code signal toggle_s : std_logic_vector(1 downto 0) := "01"; +vhdl blank +vhdl code begin +vhdl blank +vhdl comment ----------------------------------------------------------------------------- +vhdl comment -- Process toggle +vhdl comment -- +vhdl comment -- Purpose: +vhdl comment -- Flip the toggle_s signal periodically. +vhdl comment -- +vhdl code toggle: process +vhdl code begin +vhdl blank +vhdl code wait for period_c/2; +vhdl code toggle_s <= not toggle_s; +vhdl blank +vhdl code end process toggle; +vhdl comment -- +vhdl comment ----------------------------------------------------------------------------- +vhdl blank +vhdl code end behav; +vhdl blank +vhdl code configuration tb_behav_c0 of tb is +vhdl blank +vhdl code for behav +vhdl code end for; +vhdl blank +vhdl code end tb_behav_c0; diff --git a/test/expected_dir/vhdl1.vhdl/vhdl/blanks b/test/expected_dir/vhdl1.vhdl/vhdl/blanks deleted file mode 100644 index 3cacc0b..0000000 --- a/test/expected_dir/vhdl1.vhdl/vhdl/blanks +++ /dev/null @@ -1 +0,0 @@ -12 \ No newline at end of file diff --git a/test/expected_dir/vhdl1.vhdl/vhdl/code b/test/expected_dir/vhdl1.vhdl/vhdl/code deleted file mode 100644 index 2bbdc82..0000000 --- a/test/expected_dir/vhdl1.vhdl/vhdl/code +++ /dev/null @@ -1,18 +0,0 @@ -library ieee; -use ieee.std_logic_1164.all; -entity tb is -end tb; -architecture behav of tb is -constant period_c : time := 1 ms; -signal toggle_s : std_logic_vector(1 downto 0) := "01"; -begin -toggle: process -begin -wait for period_c/2; -toggle_s <= not toggle_s; -end process toggle; -end behav; -configuration tb_behav_c0 of tb is -for behav -end for; -end tb_behav_c0; diff --git a/test/expected_dir/vhdl1.vhdl/vhdl/comment b/test/expected_dir/vhdl1.vhdl/vhdl/comment deleted file mode 100644 index 98b17ed..0000000 --- a/test/expected_dir/vhdl1.vhdl/vhdl/comment +++ /dev/null @@ -1,10 +0,0 @@ --- toggle period --- we'll be poking on this signal ------------------------------------------------------------------------------ --- Process toggle --- --- Purpose: --- Flip the toggle_s signal periodically. --- --- ------------------------------------------------------------------------------ diff --git a/test/expected_dir/visual_basic.bas b/test/expected_dir/visual_basic.bas new file mode 100644 index 0000000..c8331c6 --- /dev/null +++ b/test/expected_dir/visual_basic.bas @@ -0,0 +1,60 @@ +visualbasic code VERSION 5.00 +visualbasic code Object = "{67397AA1-7FB1-11D0-B148-00A0C922E820}#6.0#0"; "MSADODC.OCX" +visualbasic code Object = "{BDC217C8-ED16-11CD-956C-0000C04E4C0A}#1.1#0"; "TABCTL32.OCX" +visualbasic code Object = "{CDE57A40-8B86-11D0-B3C6-00A0C90AEA82}#1.0#0"; "MSDATGRD.OCX" +visualbasic code Object = "{0ECD9B60-23AA-11D0-B351-00A0C9055D8E}#6.0#0"; "MSHFLXGD.OCX" +visualbasic code Object = "{831FDD16-0C5C-11D2-A9FC-0000F8754DA1}#2.0#0"; "MSCOMCTL.OCX" +visualbasic code Begin VB.Form frmMain +visualbasic code BorderStyle = 1 'Fixed Single +visualbasic code ClientHeight = 6555 +visualbasic code ClientLeft = 150 +visualbasic code ClientTop = 435 +visualbasic code ClientWidth = 10620 +visualbasic code LinkTopic = "Form1" +visualbasic code MaxButton = 0 'False +visualbasic code MinButton = 0 'False +visualbasic code ScaleHeight = 6555 +visualbasic code ScaleWidth = 10620 +visualbasic code StartUpPosition = 3 'Windows Default +visualbasic code Attribute VB_Name = "frmMain" +visualbasic code Attribute VB_GlobalNameSpace = False +visualbasic code Attribute VB_Creatable = False +visualbasic code Attribute VB_PredeclaredId = True +visualbasic code Attribute VB_Exposed = False +visualbasic comment '--------------------------------------------------------------------------- +visualbasic comment ' +visualbasic comment ' SOURCE FILE NAME: Demo.frm +visualbasic comment ' +visualbasic comment ' SAMPLE: Visual Basic Demo with user interface for the sample modules +visualbasic comment ' +visualbasic comment ' For more information about samples, refer to the README file. +visualbasic comment ' +visualbasic comment '--------------------------------------------------------------------------- +visualbasic blank +visualbasic code Option Explicit +visualbasic blank +visualbasic code Private con As ADODB.Connection +visualbasic code Private rst As ADODB.Recordset +visualbasic code Private strMsgText As String +visualbasic code Private wShowInstructions As Integer +visualbasic blank +visualbasic comment 'This procedure calls ConnectOLEDB() in the module dbConn to get +visualbasic comment 'a connection object. +visualbasic code Private Sub cmdConnectOLEDB_Click() +visualbasic comment 'define the error handler +visualbasic comment ' On Error GoTo cmdConnectOLEDB_Error +visualbasic blank +visualbasic comment 'connect to database +visualbasic code Set con = ConnectOLEDB() +visualbasic blank +visualbasic comment 'generate a message of success +visualbasic code sbrStatus.Panels(1).Text = "Connect to sample database succeeded!" +visualbasic blank +visualbasic comment 'config status of the buttons +visualbasic code EnableButtons +visualbasic blank +visualbasic comment 'show instructions +visualbasic code If wShowInstructions = vbYes Then +visualbasic code ShowConnectionInstruction +visualbasic code End If +visualbasic code End Sub diff --git a/test/expected_dir/visual_basic.bas/visualbasic/blanks b/test/expected_dir/visual_basic.bas/visualbasic/blanks deleted file mode 100644 index c793025..0000000 --- a/test/expected_dir/visual_basic.bas/visualbasic/blanks +++ /dev/null @@ -1 +0,0 @@ -7 \ No newline at end of file diff --git a/test/expected_dir/visual_basic.bas/visualbasic/code b/test/expected_dir/visual_basic.bas/visualbasic/code deleted file mode 100644 index d0fa5b8..0000000 --- a/test/expected_dir/visual_basic.bas/visualbasic/code +++ /dev/null @@ -1,36 +0,0 @@ -VERSION 5.00 -Object = "{67397AA1-7FB1-11D0-B148-00A0C922E820}#6.0#0"; "MSADODC.OCX" -Object = "{BDC217C8-ED16-11CD-956C-0000C04E4C0A}#1.1#0"; "TABCTL32.OCX" -Object = "{CDE57A40-8B86-11D0-B3C6-00A0C90AEA82}#1.0#0"; "MSDATGRD.OCX" -Object = "{0ECD9B60-23AA-11D0-B351-00A0C9055D8E}#6.0#0"; "MSHFLXGD.OCX" -Object = "{831FDD16-0C5C-11D2-A9FC-0000F8754DA1}#2.0#0"; "MSCOMCTL.OCX" -Begin VB.Form frmMain -BorderStyle = 1 'Fixed Single -ClientHeight = 6555 -ClientLeft = 150 -ClientTop = 435 -ClientWidth = 10620 -LinkTopic = "Form1" -MaxButton = 0 'False -MinButton = 0 'False -ScaleHeight = 6555 -ScaleWidth = 10620 -StartUpPosition = 3 'Windows Default -Attribute VB_Name = "frmMain" -Attribute VB_GlobalNameSpace = False -Attribute VB_Creatable = False -Attribute VB_PredeclaredId = True -Attribute VB_Exposed = False -Option Explicit -Private con As ADODB.Connection -Private rst As ADODB.Recordset -Private strMsgText As String -Private wShowInstructions As Integer -Private Sub cmdConnectOLEDB_Click() -Set con = ConnectOLEDB() -sbrStatus.Panels(1).Text = "Connect to sample database succeeded!" -EnableButtons -If wShowInstructions = vbYes Then -ShowConnectionInstruction -End If -End Sub diff --git a/test/expected_dir/visual_basic.bas/visualbasic/comment b/test/expected_dir/visual_basic.bas/visualbasic/comment deleted file mode 100644 index fc9649a..0000000 --- a/test/expected_dir/visual_basic.bas/visualbasic/comment +++ /dev/null @@ -1,17 +0,0 @@ -'--------------------------------------------------------------------------- -' -' SOURCE FILE NAME: Demo.frm -' -' SAMPLE: Visual Basic Demo with user interface for the sample modules -' -' For more information about samples, refer to the README file. -' -'--------------------------------------------------------------------------- -'This procedure calls ConnectOLEDB() in the module dbConn to get -'a connection object. -'define the error handler -' On Error GoTo cmdConnectOLEDB_Error -'connect to database -'generate a message of success -'config status of the buttons -'show instructions diff --git a/test/expected_dir/xml1.xml b/test/expected_dir/xml1.xml new file mode 100644 index 0000000..db38a87 --- /dev/null +++ b/test/expected_dir/xml1.xml @@ -0,0 +1,14 @@ +xml code +xml comment +xml code +xml code ]]> +xml blank +xml code +xml comment +xml code +xml code +xml blank diff --git a/test/expected_dir/xml1.xml/xml/blanks b/test/expected_dir/xml1.xml/xml/blanks deleted file mode 100644 index d8263ee..0000000 --- a/test/expected_dir/xml1.xml/xml/blanks +++ /dev/null @@ -1 +0,0 @@ -2 \ No newline at end of file diff --git a/test/expected_dir/xml1.xml/xml/code b/test/expected_dir/xml1.xml/xml/code deleted file mode 100644 index 844c38e..0000000 --- a/test/expected_dir/xml1.xml/xml/code +++ /dev/null @@ -1,7 +0,0 @@ - - -]]> - - - diff --git a/test/expected_dir/xml1.xml/xml/comment b/test/expected_dir/xml1.xml/xml/comment deleted file mode 100644 index 4cff3c6..0000000 --- a/test/expected_dir/xml1.xml/xml/comment +++ /dev/null @@ -1,5 +0,0 @@ - almost done with comment ---> - diff --git a/test/test_helper.rb b/test/test_helper.rb index 0a74c84..305b590 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -26,15 +26,11 @@ def default_test end def src_dir - TEST_DIR + "/src_dir" - end - - def scratch_dir - TEST_DIR + "/scratch_dir" + File.expand_path(File.join(TEST_DIR, "src_dir")) end def expected_dir - TEST_DIR + "/expected_dir" + File.expand_path(File.join(TEST_DIR, "expected_dir")) end # verify_parse runs a full test against a specified file. Detector is used to determine @@ -42,100 +38,46 @@ def expected_dir # # The file to be parsed must be in directory test/src_dir. # - # The expected results must be stored on disk in directory test/expected_dir. The format - # of the expected results on disk is a bit cumbersome. To create new test case, you must: + # The expected results must be stored in directory test/expected_dir, and + # must be in the format produced by bin/ohcount --annotate. That is, each line + # of the expected file should be prefixed with the tab-delimited language and semantic. + # + # To create a new test case: # # 1. Create a new source code file in test/src_dir. - # For example, test/src_dir/my_file.ext + # For example, test/src_dir/my_file.ext. # - # 2. Next, create a new directory in test/expected_dir with - # the same name as your test source code file. For example, - # test/expected_dir/my_file.ext/ + # 2. Copy your source file to the test/expected_dir directory. + # Use a text editor to insert the language and semantic at the front of each line. + # These must be tab-delimited from the rest of the line. # - # 3. Within this directory, create directories for each language used in the test source code - # file. For example, test/expected_dir/my_file.ext/my_language/ + # If you've cheated and written your code before your test, then you can simply + # use ohcount itself to create this file: # - # 4. In this language subdirectory, create three files called +code+, +comment+, and +blanks+. - # The +code+ file should contain all of the lines from my_file.ext which are code lines. - # The +comment+ file should contain all comment lines. - # The +blanks+ file is a bit different: it should contain a single line with an integer - # which is the count of blank lines in the original file. + # bin/ohcount --annotate src_dir/my_file.ext > expected_dir/myfile.ext # - # There are numerous examples in the test directories to help you out. + # Be sure to carefully confirm this result or your test will be meaningless! # - def verify_parse(src_filename, filenames = []) - # re-make the output directory - Dir.mkdir scratch_dir unless File.exists? scratch_dir - output_dir = scratch_dir + "/#{ File.basename(src_filename) }" - FileUtils.rm_r(output_dir) if FileTest.directory?(output_dir) - Dir.mkdir output_dir - - complete_src_filename = src_dir + "/#{ src_filename }" - sfc = Ohcount::SimpleFileContext.new(complete_src_filename, filenames) + # There are numerous examples in the test directories to help you out. + def verify_parse(file, filenames=[]) + sfc = Ohcount::SimpleFileContext.new(File.join(src_dir, file), filenames) polyglot = Ohcount::Detector.detect(sfc) - - # parse - buffer = File.new(complete_src_filename).read - Ohcount::Parser.parse_to_dir(:dir => output_dir, - :buffer => buffer, - :polyglot => polyglot) - - # now compare - answer_dir = expected_dir + "/#{ File.basename(src_filename) }" - compare_dir(answer_dir, output_dir) - - # just to be sure, lets compare the total number of lines from the source file and the processed breakdown - compare_line_count(complete_src_filename, output_dir) - end - - - def compare_dir(expected, actual) - # make sure entries are identical - expected_entries = expected.entries.collect { |e| e[expected.size..-1] } - actual_entries = actual.entries.collect { |a| a[actual.size..-1] } - assert_equal expected_entries, actual_entries - - Dir.foreach(expected) do |entry| - next if [".", "..", ".svn"].include?(entry) - case File.ftype(expected+ "/" + entry) - when 'file' - File.open(expected + "/" + entry) do |e| - File.open(actual + "/" + entry) do |a| - assert_equal e.read, a.read, "file #{actual + "/" + entry} differs from expected" - end - end - when 'directory' - compare_dir(expected + "/" + entry, actual + "/" + entry) - else - assert false, "weird ftype" - end - end - end - - - def compare_line_count(src_file, scratch_dir) - code_lines = comment_lines = blanks = 0 - - Find.find(scratch_dir) do |path| - if FileTest.file?(path) - `wc -l #{ path }` =~ /^\s*(\d*)\b/ - case File.basename(path) - when 'code' - code_lines += $1.to_i - when 'comment' - comment_lines += $1.to_i - when 'blanks' - blanks += File.new(path).read.to_i - end + buffer = '' + if polyglot + Ohcount::parse(sfc.contents, polyglot) do |language, semantic, line| + buffer << "#{language}\t#{semantic}\t#{line}" end end + expected = File.read(File.join(expected_dir, file)) - # src file lines - `wc -l #{ src_file }` =~ /^\s*(\d*)\b/ - src_file_lines = $1.to_i + # Uncomment the following lines if you need to see a diff explaining why your test is failing + # if expected != buffer + # File.open("/tmp/ohcount","w") { |f| f.write buffer } + # puts `diff #{File.join(expected_dir, file)} /tmp/ohcount` + # end - # compare - assert_equal src_file_lines, (code_lines + comment_lines + blanks), "wc -l of output (code, comment, blanks) doesn't match the 'wc -l' of original" + puts buffer if expected != buffer + assert expected == buffer, "Parse result of #{File.join(src_dir, file)} did not match expected #{File.join(expected_dir, file)}." end def entities_array(src_string, polyglot, *entities) diff --git a/test/unit/basic_test.rb b/test/unit/basic_test.rb index 66fb7b8..0c28dde 100644 --- a/test/unit/basic_test.rb +++ b/test/unit/basic_test.rb @@ -13,7 +13,7 @@ def test_cb_comments def test_comprehensive verify_parse("classic_basic.b") - verify_parse("visual_basic.bas", "frx1.frx") + verify_parse("visual_basic.bas", ["frx1.frx"]) verify_parse("structured_basic.b") verify_parse("structured_basic.bas") verify_parse("classic_basic.bas") diff --git a/test/unit/diff_test.rb b/test/unit/diff_test.rb deleted file mode 100644 index 91082b2..0000000 --- a/test/unit/diff_test.rb +++ /dev/null @@ -1,43 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::DiffTest < Ohcount::Test - - def test_one - src_dir = File.dirname(__FILE__) + '/../src_dir/' - sloc_infos = Ohcount.diff_files(src_dir + 'diff1_old.html', src_dir + 'diff1_new.html') - - css = Ohcount::SlocInfo.new('css') - css.code_added = 1 - css.comments_added = 1 - - html = Ohcount::SlocInfo.new('html') - html.code_added, html.code_removed = [1,1] - - js = Ohcount::SlocInfo.new('javascript') - js.code_removed = 1 - js.comments_removed = 1 - - assert_equal [css, html, js], sloc_infos - end - - def test_two - src_dir = File.dirname(__FILE__) + '/../src_dir/' - sloc_infos = Ohcount.diff_files(src_dir + 'diff2_old.c', src_dir + 'diff2_new.c') - - c = Ohcount::SlocInfo.new('c') - c.code_added, c.code_removed = [1,1] - c.comments_added, c.comments_removed = [1,1] - - assert_equal [c], sloc_infos - end - - def test_three - src_dir = File.dirname(__FILE__) + '/../src_dir/' - sloc_infos = Ohcount.diff_files(src_dir + 'diff3_old.xml', src_dir + 'diff3_new.xml') - - xml = Ohcount::SlocInfo.new('xml') - xml.code_added, xml.code_removed = [1,1] - - assert_equal [xml], sloc_infos - end -end diff --git a/test/unit/license_sniffer_test.rb b/test/unit/license_sniffer_test.rb index afd4ded..ec0f6f7 100644 --- a/test/unit/license_sniffer_test.rb +++ b/test/unit/license_sniffer_test.rb @@ -2,7 +2,7 @@ class Ohcount::LicensesSnifferTest < Ohcount::Test - # To make test creation easy & straighforward, we use a + # To make test creation easy & straighforward, we use a # file-based convention, as follows: # # test/src_licenses/_t1.c <-- a 'C' file @@ -23,7 +23,9 @@ def test_expected_licenses filename = src_dir + "/" + f next if File.directory?(filename) next if f[0..0] == "." - detected_licenses = LicenseSniffer.licenses_from_source_code(filename) + + sfc = SimpleFileContext.new(filename) + detected_licenses = LicenseSniffer.parse(sfc.contents, Detector.detect(sfc)) # expected_licenses begin @@ -43,4 +45,3 @@ def test_expected_licenses end end - From e9dfb9dce1116f1272457ee86709ffbf35c35360 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Wed, 3 Sep 2008 12:09:19 -0700 Subject: [PATCH 006/387] [FIX] Remove unused file --- test/expected_dir/classic_basic1.classic_basic | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 test/expected_dir/classic_basic1.classic_basic diff --git a/test/expected_dir/classic_basic1.classic_basic b/test/expected_dir/classic_basic1.classic_basic deleted file mode 100644 index e69de29..0000000 From 373d805bca8dba945112dde4af04a3979e5b5cf5 Mon Sep 17 00:00:00 2001 From: Mark Hoebeke Date: Fri, 5 Sep 2008 09:03:23 +0200 Subject: [PATCH 007/387] Added test case for R language support. --- ext/ohcount_native/ragel_parser.c | 2 + ext/ohcount_native/ragel_parsers/R.rl | 107 ++++++++++++++++++ lib/ohcount/detector.rb | 1 + lib/ohcount/sloc_info.rb | 1 + test/detect_files/foo.R | 5 + test/expected_dir/example.R | 200 ++++++++++++++++++++++++++++++++++ test/src_dir/example.R | 200 ++++++++++++++++++++++++++++++++++ test/unit/detector_test.rb | 1 + test/unit/r_test.rb | 18 +++ 9 files changed, 535 insertions(+) create mode 100644 ext/ohcount_native/ragel_parsers/R.rl create mode 100644 test/detect_files/foo.R create mode 100644 test/expected_dir/example.R create mode 100644 test/src_dir/example.R create mode 100644 test/unit/r_test.rb diff --git a/ext/ohcount_native/ragel_parser.c b/ext/ohcount_native/ragel_parser.c index 6985c35..e82e198 100644 --- a/ext/ohcount_native/ragel_parser.c +++ b/ext/ohcount_native/ragel_parser.c @@ -49,6 +49,7 @@ #include "phphtml_parser.h" #include "pike_parser.h" #include "python_parser.h" +#include "R_parser.h" #include "rexx_parser.h" #include "ruby_parser.h" #include "rhtml_parser.h" @@ -127,6 +128,7 @@ struct language languages[] = { { "php", parse_phtml }, { "pike", parse_pike }, { "python", parse_python }, + { "r", parse_r }, { "rexx", parse_rexx }, { "rhtml", parse_rhtml }, { "ruby", parse_ruby }, diff --git a/ext/ohcount_native/ragel_parsers/R.rl b/ext/ohcount_native/ragel_parsers/R.rl new file mode 100644 index 0000000..48451bc --- /dev/null +++ b/ext/ohcount_native/ragel_parsers/R.rl @@ -0,0 +1,107 @@ +// r.rl copied from matlabl.rl written by Mitchell Foral. mitchellcaladbolgnet. +// adapted by Mark Hoebeke mark@hoebekeeu +/************************* Required for every parser *************************/ +#ifndef RAGEL_R_PARSER +#define RAGEL_R_PARSER + +#include "ragel_parser_macros.h" + +// the name of the language +const char *R_LANG = "R"; + +// the languages entities +const char *r_entities[] = { + "space", "comment", "string", "any", +}; + +// constants associated with the entities +enum { + R_SPACE = 0, R_COMMENT, R_STRING, R_ANY +}; + +/*****************************************************************************/ + +%%{ + machine r; + write data; + include common "common.rl"; + + # Line counting machine + + action r_ccallback { + switch(entity) { + case R_SPACE: + ls + break; + case R_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(R_LANG) + break; + case NEWLINE: + std_newline(R_LANG) + } + } + + r_line_comment = ( '#') @comment nonnewline*; + r_comment = r_line_comment; + + r_sq_str = '\'' @code ([^\r\n\f'\\] | '\\' nonnewline)* '\''; + r_dq_str = '"' @code ([^\r\n\f"\\] | '\\' nonnewline)* '"'; + r_string = r_sq_str | r_dq_str; + + r_line := |* + spaces ${ entity = R_SPACE; } => r_ccallback; + r_comment; + r_string; + newline ${ entity = NEWLINE; } => r_ccallback; + ^space ${ entity = R_ANY; } => r_ccallback; + *|; + + # Entity machine + + action r_ecallback { + callback(R_LANG, r_entities[entity], cint(ts), cint(te)); + } + + r_line_comment_entity = ('#') nonnewline*; + r_comment_entity = r_line_comment_entity; + + r_entity := |* + space+ ${ entity = R_SPACE; } => r_ecallback; + r_comment_entity ${ entity = R_COMMENT; } => r_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with R code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_r(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int start, int end) + ) { + init + + %% write init; + cs = (count) ? r_en_r_line : r_en_r_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(R_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index bbe91fb..577403c 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -199,6 +199,7 @@ def self.binary_filename?(filename) '.pmc' => "c", '.pmod' => "pike", '.py' => "python", + '.R' => "r", '.rhtml'=> "rhtml", '.rb' => "ruby", '.rex' => "rexx", diff --git a/lib/ohcount/sloc_info.rb b/lib/ohcount/sloc_info.rb index 35a7026..6fbed57 100644 --- a/lib/ohcount/sloc_info.rb +++ b/lib/ohcount/sloc_info.rb @@ -82,6 +82,7 @@ def empty? 'php' => {:nice_name => 'PHP' , :category => 0}, 'pike' => {:nice_name => 'Pike' , :category => 0}, 'python' => {:nice_name => 'Python' , :category => 0}, + 'r' => {:nice_name => 'R' , :category => 0}, 'rexx' => {:nice_name => 'rexx' , :category => 0}, 'ruby' => {:nice_name => 'Ruby' , :category => 0}, 'scheme' => {:nice_name => 'Scheme' , :category => 0}, diff --git a/test/detect_files/foo.R b/test/detect_files/foo.R new file mode 100644 index 0000000..29f47e4 --- /dev/null +++ b/test/detect_files/foo.R @@ -0,0 +1,5 @@ +dummy<-function() { +# A dummy function to test the R language parser. + 1.0 +} + diff --git a/test/expected_dir/example.R b/test/expected_dir/example.R new file mode 100644 index 0000000..cf1925b --- /dev/null +++ b/test/expected_dir/example.R @@ -0,0 +1,200 @@ +R comment # Build a 'graph-like' object having 'nodes' nodes belonging to 'classes' classes. +R comment # Class distribution is given by 'proba', and connectivity probabilities are given +R comment # by 'intraproba' and 'interproba'. +R code generateGraph<-function(nodes,classes,proba=rep(1/classes,classes), +R code intraproba=0.1,crossproba=0.02) +R code { +R code mat_pi=CreateConnectivityMat(classes,intraproba,crossproba) +R code igraph=Fast2SimuleERMG(nodes,proba,mat_pi[1],mat_pi[2]) +R code adjacency=get.adjacency(igraph$graph) +R code cmgraph=list(nodes=nodes,classes=classes,adjacency=adjacency,nodeclasses=igraph$node.classes,proba=proba, +R code intraproba=intraproba,crossproba=crossproba) +R code attr(cmgraph,'class')<-c('cmgraph') +R code cmgraph +R code } +R blank +R comment # Return explicit member names for the different attributes of graph objects. +R code labels.cmgraph<-function(object,...) +R code { +R code c("Nodes","Classes","Adjacency Matrix","Node Classification","Class Probability Distribution","Intra Class Edge Probability","Cross Class Edge Probability") +R code } +R blank +R comment # Override the summmary function for graph objects. +R code summary.cmgraph<-function(object,...) +R code { +R blank +R code cat(c("Nodes : ",object$nodes,"\n", +R code "Edges : ",length(which(object$adjacency!=0)),"\n", +R code "Classes : ",object$classes,"\n", +R code "Class Probability Distribution: ",object$proba,"\n")) +R code } +R blank +R comment # Override the plot function for graph objects. +R code plot.cmgraph<-function(x,...) +R code { +R code RepresentationXGroup(x$adjacency,x$nodeclasses) +R code } +R blank +R comment # Generate covariable data for the graph 'g'. Covariables are associated to vertex data, and +R comment # their values are drawn according to 2 distributions: one for vertices joining nodes of +R comment # the same class, and another for vertices joining nodes of different classes. +R comment # The two distributions have different means but a single standard deviation. +R code generateCovariablesCondZ<-function(g,sameclustermean=0,otherclustermean=2,sigma=1) +R code { +R code mu=CreateMu(g$classes,sameclustermean,otherclustermean) +R code res=SimDataYcondZ(g$nodeclasses,mu,sigma) +R code cmcovars=list(graph=g,sameclustermean=sameclustermean,otherclustermean=otherclustermean,sigma=sigma,mu=mu,y=res) +R code attr(cmcovars,'class')<-c('cmcovarz','cmcovar') +R code cmcovars +R code } +R blank +R comment # Generate covariable data for the graph 'g'. Covariables are associated to vertex data, and +R comment # their values are drawn according to 2 distributions: one for vertices joining nodes of +R comment # the same class, and another for vertices joining nodes of different classes. +R comment # The two distributions have different means but a single standard deviation. +R comment # This function generates two sets of covariables. +R code generateCovariablesCondXZ<-function(g,sameclustermean=c(0,3),otherclustermean=c(2,5),sigma=1) +R code { +R code mux0=CreateMu(g$classes,sameclustermean[1],otherclustermean[1]) +R code mux1=CreateMu(g$classes,sameclustermean[2],otherclustermean[2]) +R code res=SimDataYcondXZ(g$nodeclasses,g$adjacency,mux0,mux1,sigma) +R code cmcovars=list(graph=g,sameclustermean=sameclustermean,otherclustermean=otherclustermean,sigma=sigma,mu=c(mux0,mux1),y=res) +R code attr(cmcovars,'class')<-c('cmcovarxz','cmcovar') +R code cmcovars +R code } +R blank +R blank +R comment # Override the print function for a cleaner covariable output. +R code print.cmcovar<-function(x,...) +R code { +R code cat("Classes : ",x$graph$classes,"\n", +R code "Intra cluster mean: ",x$sameclustermean,"\n", +R code "Cross cluster mean: ",x$otherclustermean,"\n", +R code "Variance : ",x$sigma,"\n", +R code "Covariables :\n",x$y,"\n") +R code } +R blank +R blank +R comment # Perform parameter estimation on 'graph' given the covariables 'covars'. +R code estimateCondZ<-function(graph,covars,maxiterations,initialclasses,selfloops) +R code { +R code res=EMalgorithm(initialclasses,covars$y,graph$adjacency,maxiterations,FALSE,selfloops) +R code cmestimation=list(mean=res$MuEstimated,variance=res$VarianceEstimated,pi=res$PIEstimated,alpha=res$AlphaEstimated,tau=res$TauEstimated,jexpected=res$EJ,graph=graph) +R code attr(cmestimation,'class')<-c('cmestimationz') +R code cmestimation +R code } +R blank +R comment # Private generic estimation function used to allow various call conventions for estimation functions. +R code privateestimate<-function(covars,graph,maxiterations,initialclasses,selfloops,...) UseMethod("privateestimate") +R blank +R comment # Private estimation function used to allow various call conventions for estimation functions. +R comment # Override of generic function for single covariables. +R code privateestimate.cmcovarz<-function(covars,graph,maxiterations,initialclasses,selfloops,...) +R code { +R code res=estimateCondZ(graph,covars,maxiterations,initialclasses,selfloops) +R code attr(res,'class')<-c(attr(res,'class'),'cmestimation') +R code res +R blank +R code } +R blank +R comment # Perform parameter estimation on 'graph' given the covariables 'covars'. +R code estimateCondXZ<-function(graph,covars,maxiterations,initialclasses,selfloops) +R code { +R comment #resSimXZ = EMalgorithmXZ(TauIni,Y2,Adjacente,30,SelfLoop=FALSE) +R code res=EMalgorithmXZ(initialclasses,covars$y,graph$adjacency,maxiterations,selfloops) +R code cmestimation=list(mean=c(res$MuEstimated1,res$MuEstimated2),variance=res$VarianceEstimated,pi=res$PIEstimated,alpha=res$AlphaEstimated,tau=res$TauEstimated,jexpected=res$EJ,graph=graph) +R code attr(cmestimation,'class')<-c('cmestimationxz') +R code cmestimation +R code } +R blank +R comment # Private estimation function used to allow various call conventions for estimation functions. +R comment # Override of generic function for multiple covariables. +R code privateestimate.cmcovarxz<-function(covars,graph,maxiterations,initialclasses,selfloops,...) +R code { +R code res=estimateCondXZ(graph,covars,maxiterations,initialclasses,selfloops) +R code attr(res,'class')<-c(attr(res,'class'),'cmestimation') +R code res +R code } +R blank +R comment # Generic estimation function applicable to graphs with covariables. +R code estimate<-function(graph,covars,...) UseMethod("estimate") +R blank +R comment # Override of the generic estimation function. Performs the actual function dispatch depending on the class of covariables. +R code estimate.cmgraph<-function(graph,covars,maxiterations=20,initialclasses=t(rmultinom(size=1,prob=graph$proba,n=graph$nodes)),selfloops=FALSE,method=NULL,...) +R code { +R code if (length(method) == 0) { +R code res=privateestimate(covars,graph,maxiterations,initialclasses,selfloops,...) +R code } else { +R code res=method(graph,covars,maxiterations,initialclasses,selfloops) +R code attr(res,'class')<-c(attr(res,'class'),'cmestimation') +R code } +R code res +R code } +R blank +R comment # Override of the generic pliot function for estimation results. +R code plot.cmestimation<-function(x,...) +R code { +R code par(mfrow = c(1,2)) +R code plot(x$jexpected) +R code title("Expected value of J: Convergence criterion") +R blank +R code map=MAP(x$tau) +R code gplot(x$graph$adjacency,vertex.col=map$node.classes+2) +R code title("Network with estimated classes") +R blank +R code } +R blank +R comment # Generic private ICL computation function for graphs and covariables. +R code privatecomputeICL<-function(covars,graph,qmin,qmax,loops,maxiterations,selfloops) UseMethod("privatecomputeICL") +R blank +R blank +R comment # Private ICL computation function for graphs with single covariables. +R code privatecomputeICL.cmcovarz<-function(covars,graph,qmin,qmax,loops,maxiterations,selfloops) +R code { +R code res=ICL(X=graph$adjacency,Y=covars$y,Qmin=qmin,Qmax=qmax,loop=loops,NbIteration=maxiterations,SelfLoop=selfloops,Plot=FALSE) +R code attr(res,'class')<-c('cmiclz') +R code res +R blank +R code } +R blank +R comment # Private ICL computation function for graphs with multiple covariables. +R code privatecomputeICL.cmcovarxz<-function(covars,graph,qmin,qmax,loops,maxiterations,selfloops) +R code { +R code res=ICL(X=graph$adjacency,Y=covars$y,Qmin=qmin,Qmax=qmax,loop=loops,NbIteration=maxiterations,SelfLoop=selfloops,Plot=FALSE) +R code attr(res,'class')<-c('cmiclxz') +R code res +R code } +R blank +R blank +R comment # Generic public ICL computation function applicable to graph objects. +R code computeICL<-function(graph,covars,qmin,qmax,...) UseMethod("computeICL") +R blank +R comment # Override of ICL computation function applicable to graph objects. +R comment # Performs the actual method dispatch to private functions depending on the type of covariables. +R code computeICL.cmgraph<-function(graph,covars,qmin,qmax,loops=10,maxiterations=20,selfloops=FALSE,...) +R code { +R code res=privatecomputeICL(covars,graph,qmin,qmax,loops,maxiterations,selfloops) +R code res$qmin=qmin +R code res$qmax=qmax +R code res$graph=graph +R code res$covars=covars +R code attr(res,'class')<-c(attr(res,'class'),'cmicl') +R code res +R code } +R blank +R comment # Override of the plot function for results of ICL computation. +R code plot.cmicl<-function(x,...) +R code { +R code par(mfrow = c(1,2)) +R code result=x$iclvalues +R code maxi=which(max(result)==result) +R code plot(seq(x$qmin,x$qmax),result,type="b",xlab="Number of classes",ylab="ICL value") +R code points(maxi+x$qmin-1,result[maxi],col="red") +R code title("ICL curve") +R code best=x$EMestimation[[maxi+x$qmin-1]] +R code tau=best$TauEstimated +R code map=MAP(tau) +R code gplot(x$graph$adjacency,vertex.col=map$node.classes+2) +R code title("Network with estimated classes") +R code } +R blank diff --git a/test/src_dir/example.R b/test/src_dir/example.R new file mode 100644 index 0000000..3740c46 --- /dev/null +++ b/test/src_dir/example.R @@ -0,0 +1,200 @@ +# Build a 'graph-like' object having 'nodes' nodes belonging to 'classes' classes. +# Class distribution is given by 'proba', and connectivity probabilities are given +# by 'intraproba' and 'interproba'. +generateGraph<-function(nodes,classes,proba=rep(1/classes,classes), + intraproba=0.1,crossproba=0.02) +{ + mat_pi=CreateConnectivityMat(classes,intraproba,crossproba) + igraph=Fast2SimuleERMG(nodes,proba,mat_pi[1],mat_pi[2]) + adjacency=get.adjacency(igraph$graph) + cmgraph=list(nodes=nodes,classes=classes,adjacency=adjacency,nodeclasses=igraph$node.classes,proba=proba, + intraproba=intraproba,crossproba=crossproba) + attr(cmgraph,'class')<-c('cmgraph') + cmgraph +} + +# Return explicit member names for the different attributes of graph objects. +labels.cmgraph<-function(object,...) +{ + c("Nodes","Classes","Adjacency Matrix","Node Classification","Class Probability Distribution","Intra Class Edge Probability","Cross Class Edge Probability") +} + +# Override the summmary function for graph objects. +summary.cmgraph<-function(object,...) +{ + + cat(c("Nodes : ",object$nodes,"\n", + "Edges : ",length(which(object$adjacency!=0)),"\n", + "Classes : ",object$classes,"\n", + "Class Probability Distribution: ",object$proba,"\n")) +} + +# Override the plot function for graph objects. +plot.cmgraph<-function(x,...) +{ + RepresentationXGroup(x$adjacency,x$nodeclasses) +} + +# Generate covariable data for the graph 'g'. Covariables are associated to vertex data, and +# their values are drawn according to 2 distributions: one for vertices joining nodes of +# the same class, and another for vertices joining nodes of different classes. +# The two distributions have different means but a single standard deviation. +generateCovariablesCondZ<-function(g,sameclustermean=0,otherclustermean=2,sigma=1) +{ + mu=CreateMu(g$classes,sameclustermean,otherclustermean) + res=SimDataYcondZ(g$nodeclasses,mu,sigma) + cmcovars=list(graph=g,sameclustermean=sameclustermean,otherclustermean=otherclustermean,sigma=sigma,mu=mu,y=res) + attr(cmcovars,'class')<-c('cmcovarz','cmcovar') + cmcovars +} + +# Generate covariable data for the graph 'g'. Covariables are associated to vertex data, and +# their values are drawn according to 2 distributions: one for vertices joining nodes of +# the same class, and another for vertices joining nodes of different classes. +# The two distributions have different means but a single standard deviation. +# This function generates two sets of covariables. +generateCovariablesCondXZ<-function(g,sameclustermean=c(0,3),otherclustermean=c(2,5),sigma=1) +{ + mux0=CreateMu(g$classes,sameclustermean[1],otherclustermean[1]) + mux1=CreateMu(g$classes,sameclustermean[2],otherclustermean[2]) + res=SimDataYcondXZ(g$nodeclasses,g$adjacency,mux0,mux1,sigma) + cmcovars=list(graph=g,sameclustermean=sameclustermean,otherclustermean=otherclustermean,sigma=sigma,mu=c(mux0,mux1),y=res) + attr(cmcovars,'class')<-c('cmcovarxz','cmcovar') + cmcovars +} + + +# Override the print function for a cleaner covariable output. +print.cmcovar<-function(x,...) +{ + cat("Classes : ",x$graph$classes,"\n", + "Intra cluster mean: ",x$sameclustermean,"\n", + "Cross cluster mean: ",x$otherclustermean,"\n", + "Variance : ",x$sigma,"\n", + "Covariables :\n",x$y,"\n") +} + + +# Perform parameter estimation on 'graph' given the covariables 'covars'. +estimateCondZ<-function(graph,covars,maxiterations,initialclasses,selfloops) +{ + res=EMalgorithm(initialclasses,covars$y,graph$adjacency,maxiterations,FALSE,selfloops) + cmestimation=list(mean=res$MuEstimated,variance=res$VarianceEstimated,pi=res$PIEstimated,alpha=res$AlphaEstimated,tau=res$TauEstimated,jexpected=res$EJ,graph=graph) + attr(cmestimation,'class')<-c('cmestimationz') + cmestimation +} + +# Private generic estimation function used to allow various call conventions for estimation functions. +privateestimate<-function(covars,graph,maxiterations,initialclasses,selfloops,...) UseMethod("privateestimate") + +# Private estimation function used to allow various call conventions for estimation functions. +# Override of generic function for single covariables. +privateestimate.cmcovarz<-function(covars,graph,maxiterations,initialclasses,selfloops,...) +{ + res=estimateCondZ(graph,covars,maxiterations,initialclasses,selfloops) + attr(res,'class')<-c(attr(res,'class'),'cmestimation') + res + +} + +# Perform parameter estimation on 'graph' given the covariables 'covars'. +estimateCondXZ<-function(graph,covars,maxiterations,initialclasses,selfloops) +{ + #resSimXZ = EMalgorithmXZ(TauIni,Y2,Adjacente,30,SelfLoop=FALSE) + res=EMalgorithmXZ(initialclasses,covars$y,graph$adjacency,maxiterations,selfloops) + cmestimation=list(mean=c(res$MuEstimated1,res$MuEstimated2),variance=res$VarianceEstimated,pi=res$PIEstimated,alpha=res$AlphaEstimated,tau=res$TauEstimated,jexpected=res$EJ,graph=graph) + attr(cmestimation,'class')<-c('cmestimationxz') + cmestimation +} + +# Private estimation function used to allow various call conventions for estimation functions. +# Override of generic function for multiple covariables. +privateestimate.cmcovarxz<-function(covars,graph,maxiterations,initialclasses,selfloops,...) +{ + res=estimateCondXZ(graph,covars,maxiterations,initialclasses,selfloops) + attr(res,'class')<-c(attr(res,'class'),'cmestimation') + res +} + +# Generic estimation function applicable to graphs with covariables. +estimate<-function(graph,covars,...) UseMethod("estimate") + +# Override of the generic estimation function. Performs the actual function dispatch depending on the class of covariables. +estimate.cmgraph<-function(graph,covars,maxiterations=20,initialclasses=t(rmultinom(size=1,prob=graph$proba,n=graph$nodes)),selfloops=FALSE,method=NULL,...) +{ + if (length(method) == 0) { + res=privateestimate(covars,graph,maxiterations,initialclasses,selfloops,...) + } else { + res=method(graph,covars,maxiterations,initialclasses,selfloops) + attr(res,'class')<-c(attr(res,'class'),'cmestimation') + } + res +} + +# Override of the generic pliot function for estimation results. +plot.cmestimation<-function(x,...) +{ + par(mfrow = c(1,2)) + plot(x$jexpected) + title("Expected value of J: Convergence criterion") + + map=MAP(x$tau) + gplot(x$graph$adjacency,vertex.col=map$node.classes+2) + title("Network with estimated classes") + +} + +# Generic private ICL computation function for graphs and covariables. +privatecomputeICL<-function(covars,graph,qmin,qmax,loops,maxiterations,selfloops) UseMethod("privatecomputeICL") + + +# Private ICL computation function for graphs with single covariables. +privatecomputeICL.cmcovarz<-function(covars,graph,qmin,qmax,loops,maxiterations,selfloops) +{ + res=ICL(X=graph$adjacency,Y=covars$y,Qmin=qmin,Qmax=qmax,loop=loops,NbIteration=maxiterations,SelfLoop=selfloops,Plot=FALSE) + attr(res,'class')<-c('cmiclz') + res + +} + +# Private ICL computation function for graphs with multiple covariables. +privatecomputeICL.cmcovarxz<-function(covars,graph,qmin,qmax,loops,maxiterations,selfloops) +{ + res=ICL(X=graph$adjacency,Y=covars$y,Qmin=qmin,Qmax=qmax,loop=loops,NbIteration=maxiterations,SelfLoop=selfloops,Plot=FALSE) + attr(res,'class')<-c('cmiclxz') + res +} + + +# Generic public ICL computation function applicable to graph objects. +computeICL<-function(graph,covars,qmin,qmax,...) UseMethod("computeICL") + +# Override of ICL computation function applicable to graph objects. +# Performs the actual method dispatch to private functions depending on the type of covariables. +computeICL.cmgraph<-function(graph,covars,qmin,qmax,loops=10,maxiterations=20,selfloops=FALSE,...) +{ + res=privatecomputeICL(covars,graph,qmin,qmax,loops,maxiterations,selfloops) + res$qmin=qmin + res$qmax=qmax + res$graph=graph + res$covars=covars + attr(res,'class')<-c(attr(res,'class'),'cmicl') + res +} + +# Override of the plot function for results of ICL computation. +plot.cmicl<-function(x,...) +{ + par(mfrow = c(1,2)) + result=x$iclvalues + maxi=which(max(result)==result) + plot(seq(x$qmin,x$qmax),result,type="b",xlab="Number of classes",ylab="ICL value") + points(maxi+x$qmin-1,result[maxi],col="red") + title("ICL curve") + best=x$EMestimation[[maxi+x$qmin-1]] + tau=best$TauEstimated + map=MAP(tau) + gplot(x$graph$adjacency,vertex.col=map$node.classes+2) + title("Network with estimated classes") +} + diff --git a/test/unit/detector_test.rb b/test/unit/detector_test.rb index 6ca8a2e..c917674 100644 --- a/test/unit/detector_test.rb +++ b/test/unit/detector_test.rb @@ -71,6 +71,7 @@ def test_detect_polyglot assert_equal "eiffel", do_detect("eiffel.e") assert_equal "ocaml", do_detect("ocaml.ml") assert_equal "stratego", do_detect("stratego.str") + assert_equal "r",do_detect("foo.R") end def test_upper_case_extensions diff --git a/test/unit/r_test.rb b/test/unit/r_test.rb new file mode 100644 index 0000000..977605a --- /dev/null +++ b/test/unit/r_test.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class Ohcount::RTest < Ohcount::Test + + def test_line_comment_1 + lb = [Ohcount::LanguageBreakdown.new("R", "", "#comment", 0)] + assert_equal lb, Ohcount::parse(" #comment", "r") + end + + def test_comprehensive + verify_parse("example.R", 'r') + end + + def test_comment_entities + assert_equal('#comment', entities_array(" #comment", 'r', :comment).first) + end + +end From a9ce9108a4ca9911a5d2d422bef11c14fc55c141 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 9 Sep 2008 10:01:42 -0700 Subject: [PATCH 008/387] [FIX] Rename 'R' to 'r' for consistency with other languages. [FIX] Remove redundant entries from EXTENSION_MAP that simply list uppercase versions of extensions. --- ext/ohcount_native/ragel_parsers/{R.rl => r.rl} | 2 +- lib/ohcount/detector.rb | 8 +- test/expected_dir/example.R | 400 ++++++++++++------------ test/unit/r_test.rb | 2 +- 4 files changed, 203 insertions(+), 209 deletions(-) rename ext/ohcount_native/ragel_parsers/{R.rl => r.rl} (99%) diff --git a/ext/ohcount_native/ragel_parsers/R.rl b/ext/ohcount_native/ragel_parsers/r.rl similarity index 99% rename from ext/ohcount_native/ragel_parsers/R.rl rename to ext/ohcount_native/ragel_parsers/r.rl index 48451bc..e9fd8ef 100644 --- a/ext/ohcount_native/ragel_parsers/R.rl +++ b/ext/ohcount_native/ragel_parsers/r.rl @@ -7,7 +7,7 @@ #include "ragel_parser_macros.h" // the name of the language -const char *R_LANG = "R"; +const char *R_LANG = "r"; // the languages entities const char *r_entities[] = { diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index 577403c..74c5b91 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -147,11 +147,6 @@ def self.binary_filename?(filename) '.f90' => :disambiguate_fortran, '.f95' => :disambiguate_fortran, '.f03' => :disambiguate_fortran, - '.F' => :disambiguate_fortran, - '.F77' => :disambiguate_fortran, - '.F90' => :disambiguate_fortran, - '.F95' => :disambiguate_fortran, - '.F03' => :disambiguate_fortran, '.frx' => "visualbasic", '.groovy'=> "groovy", '.h' => :disambiguate_h_header, @@ -199,13 +194,12 @@ def self.binary_filename?(filename) '.pmc' => "c", '.pmod' => "pike", '.py' => "python", - '.R' => "r", + '.r' => "r", '.rhtml'=> "rhtml", '.rb' => "ruby", '.rex' => "rexx", '.rexx' => "rexx", '.s' => "assembler", - '.S' => "assembler", '.sc' => "scheme", '.scala'=> "scala", '.scm' => "scheme", diff --git a/test/expected_dir/example.R b/test/expected_dir/example.R index cf1925b..1058247 100644 --- a/test/expected_dir/example.R +++ b/test/expected_dir/example.R @@ -1,200 +1,200 @@ -R comment # Build a 'graph-like' object having 'nodes' nodes belonging to 'classes' classes. -R comment # Class distribution is given by 'proba', and connectivity probabilities are given -R comment # by 'intraproba' and 'interproba'. -R code generateGraph<-function(nodes,classes,proba=rep(1/classes,classes), -R code intraproba=0.1,crossproba=0.02) -R code { -R code mat_pi=CreateConnectivityMat(classes,intraproba,crossproba) -R code igraph=Fast2SimuleERMG(nodes,proba,mat_pi[1],mat_pi[2]) -R code adjacency=get.adjacency(igraph$graph) -R code cmgraph=list(nodes=nodes,classes=classes,adjacency=adjacency,nodeclasses=igraph$node.classes,proba=proba, -R code intraproba=intraproba,crossproba=crossproba) -R code attr(cmgraph,'class')<-c('cmgraph') -R code cmgraph -R code } -R blank -R comment # Return explicit member names for the different attributes of graph objects. -R code labels.cmgraph<-function(object,...) -R code { -R code c("Nodes","Classes","Adjacency Matrix","Node Classification","Class Probability Distribution","Intra Class Edge Probability","Cross Class Edge Probability") -R code } -R blank -R comment # Override the summmary function for graph objects. -R code summary.cmgraph<-function(object,...) -R code { -R blank -R code cat(c("Nodes : ",object$nodes,"\n", -R code "Edges : ",length(which(object$adjacency!=0)),"\n", -R code "Classes : ",object$classes,"\n", -R code "Class Probability Distribution: ",object$proba,"\n")) -R code } -R blank -R comment # Override the plot function for graph objects. -R code plot.cmgraph<-function(x,...) -R code { -R code RepresentationXGroup(x$adjacency,x$nodeclasses) -R code } -R blank -R comment # Generate covariable data for the graph 'g'. Covariables are associated to vertex data, and -R comment # their values are drawn according to 2 distributions: one for vertices joining nodes of -R comment # the same class, and another for vertices joining nodes of different classes. -R comment # The two distributions have different means but a single standard deviation. -R code generateCovariablesCondZ<-function(g,sameclustermean=0,otherclustermean=2,sigma=1) -R code { -R code mu=CreateMu(g$classes,sameclustermean,otherclustermean) -R code res=SimDataYcondZ(g$nodeclasses,mu,sigma) -R code cmcovars=list(graph=g,sameclustermean=sameclustermean,otherclustermean=otherclustermean,sigma=sigma,mu=mu,y=res) -R code attr(cmcovars,'class')<-c('cmcovarz','cmcovar') -R code cmcovars -R code } -R blank -R comment # Generate covariable data for the graph 'g'. Covariables are associated to vertex data, and -R comment # their values are drawn according to 2 distributions: one for vertices joining nodes of -R comment # the same class, and another for vertices joining nodes of different classes. -R comment # The two distributions have different means but a single standard deviation. -R comment # This function generates two sets of covariables. -R code generateCovariablesCondXZ<-function(g,sameclustermean=c(0,3),otherclustermean=c(2,5),sigma=1) -R code { -R code mux0=CreateMu(g$classes,sameclustermean[1],otherclustermean[1]) -R code mux1=CreateMu(g$classes,sameclustermean[2],otherclustermean[2]) -R code res=SimDataYcondXZ(g$nodeclasses,g$adjacency,mux0,mux1,sigma) -R code cmcovars=list(graph=g,sameclustermean=sameclustermean,otherclustermean=otherclustermean,sigma=sigma,mu=c(mux0,mux1),y=res) -R code attr(cmcovars,'class')<-c('cmcovarxz','cmcovar') -R code cmcovars -R code } -R blank -R blank -R comment # Override the print function for a cleaner covariable output. -R code print.cmcovar<-function(x,...) -R code { -R code cat("Classes : ",x$graph$classes,"\n", -R code "Intra cluster mean: ",x$sameclustermean,"\n", -R code "Cross cluster mean: ",x$otherclustermean,"\n", -R code "Variance : ",x$sigma,"\n", -R code "Covariables :\n",x$y,"\n") -R code } -R blank -R blank -R comment # Perform parameter estimation on 'graph' given the covariables 'covars'. -R code estimateCondZ<-function(graph,covars,maxiterations,initialclasses,selfloops) -R code { -R code res=EMalgorithm(initialclasses,covars$y,graph$adjacency,maxiterations,FALSE,selfloops) -R code cmestimation=list(mean=res$MuEstimated,variance=res$VarianceEstimated,pi=res$PIEstimated,alpha=res$AlphaEstimated,tau=res$TauEstimated,jexpected=res$EJ,graph=graph) -R code attr(cmestimation,'class')<-c('cmestimationz') -R code cmestimation -R code } -R blank -R comment # Private generic estimation function used to allow various call conventions for estimation functions. -R code privateestimate<-function(covars,graph,maxiterations,initialclasses,selfloops,...) UseMethod("privateestimate") -R blank -R comment # Private estimation function used to allow various call conventions for estimation functions. -R comment # Override of generic function for single covariables. -R code privateestimate.cmcovarz<-function(covars,graph,maxiterations,initialclasses,selfloops,...) -R code { -R code res=estimateCondZ(graph,covars,maxiterations,initialclasses,selfloops) -R code attr(res,'class')<-c(attr(res,'class'),'cmestimation') -R code res -R blank -R code } -R blank -R comment # Perform parameter estimation on 'graph' given the covariables 'covars'. -R code estimateCondXZ<-function(graph,covars,maxiterations,initialclasses,selfloops) -R code { -R comment #resSimXZ = EMalgorithmXZ(TauIni,Y2,Adjacente,30,SelfLoop=FALSE) -R code res=EMalgorithmXZ(initialclasses,covars$y,graph$adjacency,maxiterations,selfloops) -R code cmestimation=list(mean=c(res$MuEstimated1,res$MuEstimated2),variance=res$VarianceEstimated,pi=res$PIEstimated,alpha=res$AlphaEstimated,tau=res$TauEstimated,jexpected=res$EJ,graph=graph) -R code attr(cmestimation,'class')<-c('cmestimationxz') -R code cmestimation -R code } -R blank -R comment # Private estimation function used to allow various call conventions for estimation functions. -R comment # Override of generic function for multiple covariables. -R code privateestimate.cmcovarxz<-function(covars,graph,maxiterations,initialclasses,selfloops,...) -R code { -R code res=estimateCondXZ(graph,covars,maxiterations,initialclasses,selfloops) -R code attr(res,'class')<-c(attr(res,'class'),'cmestimation') -R code res -R code } -R blank -R comment # Generic estimation function applicable to graphs with covariables. -R code estimate<-function(graph,covars,...) UseMethod("estimate") -R blank -R comment # Override of the generic estimation function. Performs the actual function dispatch depending on the class of covariables. -R code estimate.cmgraph<-function(graph,covars,maxiterations=20,initialclasses=t(rmultinom(size=1,prob=graph$proba,n=graph$nodes)),selfloops=FALSE,method=NULL,...) -R code { -R code if (length(method) == 0) { -R code res=privateestimate(covars,graph,maxiterations,initialclasses,selfloops,...) -R code } else { -R code res=method(graph,covars,maxiterations,initialclasses,selfloops) -R code attr(res,'class')<-c(attr(res,'class'),'cmestimation') -R code } -R code res -R code } -R blank -R comment # Override of the generic pliot function for estimation results. -R code plot.cmestimation<-function(x,...) -R code { -R code par(mfrow = c(1,2)) -R code plot(x$jexpected) -R code title("Expected value of J: Convergence criterion") -R blank -R code map=MAP(x$tau) -R code gplot(x$graph$adjacency,vertex.col=map$node.classes+2) -R code title("Network with estimated classes") -R blank -R code } -R blank -R comment # Generic private ICL computation function for graphs and covariables. -R code privatecomputeICL<-function(covars,graph,qmin,qmax,loops,maxiterations,selfloops) UseMethod("privatecomputeICL") -R blank -R blank -R comment # Private ICL computation function for graphs with single covariables. -R code privatecomputeICL.cmcovarz<-function(covars,graph,qmin,qmax,loops,maxiterations,selfloops) -R code { -R code res=ICL(X=graph$adjacency,Y=covars$y,Qmin=qmin,Qmax=qmax,loop=loops,NbIteration=maxiterations,SelfLoop=selfloops,Plot=FALSE) -R code attr(res,'class')<-c('cmiclz') -R code res -R blank -R code } -R blank -R comment # Private ICL computation function for graphs with multiple covariables. -R code privatecomputeICL.cmcovarxz<-function(covars,graph,qmin,qmax,loops,maxiterations,selfloops) -R code { -R code res=ICL(X=graph$adjacency,Y=covars$y,Qmin=qmin,Qmax=qmax,loop=loops,NbIteration=maxiterations,SelfLoop=selfloops,Plot=FALSE) -R code attr(res,'class')<-c('cmiclxz') -R code res -R code } -R blank -R blank -R comment # Generic public ICL computation function applicable to graph objects. -R code computeICL<-function(graph,covars,qmin,qmax,...) UseMethod("computeICL") -R blank -R comment # Override of ICL computation function applicable to graph objects. -R comment # Performs the actual method dispatch to private functions depending on the type of covariables. -R code computeICL.cmgraph<-function(graph,covars,qmin,qmax,loops=10,maxiterations=20,selfloops=FALSE,...) -R code { -R code res=privatecomputeICL(covars,graph,qmin,qmax,loops,maxiterations,selfloops) -R code res$qmin=qmin -R code res$qmax=qmax -R code res$graph=graph -R code res$covars=covars -R code attr(res,'class')<-c(attr(res,'class'),'cmicl') -R code res -R code } -R blank -R comment # Override of the plot function for results of ICL computation. -R code plot.cmicl<-function(x,...) -R code { -R code par(mfrow = c(1,2)) -R code result=x$iclvalues -R code maxi=which(max(result)==result) -R code plot(seq(x$qmin,x$qmax),result,type="b",xlab="Number of classes",ylab="ICL value") -R code points(maxi+x$qmin-1,result[maxi],col="red") -R code title("ICL curve") -R code best=x$EMestimation[[maxi+x$qmin-1]] -R code tau=best$TauEstimated -R code map=MAP(tau) -R code gplot(x$graph$adjacency,vertex.col=map$node.classes+2) -R code title("Network with estimated classes") -R code } -R blank +r comment # Build a 'graph-like' object having 'nodes' nodes belonging to 'classes' classes. +r comment # Class distribution is given by 'proba', and connectivity probabilities are given +r comment # by 'intraproba' and 'interproba'. +r code generateGraph<-function(nodes,classes,proba=rep(1/classes,classes), +r code intraproba=0.1,crossproba=0.02) +r code { +r code mat_pi=CreateConnectivityMat(classes,intraproba,crossproba) +r code igraph=Fast2SimuleERMG(nodes,proba,mat_pi[1],mat_pi[2]) +r code adjacency=get.adjacency(igraph$graph) +r code cmgraph=list(nodes=nodes,classes=classes,adjacency=adjacency,nodeclasses=igraph$node.classes,proba=proba, +r code intraproba=intraproba,crossproba=crossproba) +r code attr(cmgraph,'class')<-c('cmgraph') +r code cmgraph +r code } +r blank +r comment # Return explicit member names for the different attributes of graph objects. +r code labels.cmgraph<-function(object,...) +r code { +r code c("Nodes","Classes","Adjacency Matrix","Node Classification","Class Probability Distribution","Intra Class Edge Probability","Cross Class Edge Probability") +r code } +r blank +r comment # Override the summmary function for graph objects. +r code summary.cmgraph<-function(object,...) +r code { +r blank +r code cat(c("Nodes : ",object$nodes,"\n", +r code "Edges : ",length(which(object$adjacency!=0)),"\n", +r code "Classes : ",object$classes,"\n", +r code "Class Probability Distribution: ",object$proba,"\n")) +r code } +r blank +r comment # Override the plot function for graph objects. +r code plot.cmgraph<-function(x,...) +r code { +r code RepresentationXGroup(x$adjacency,x$nodeclasses) +r code } +r blank +r comment # Generate covariable data for the graph 'g'. Covariables are associated to vertex data, and +r comment # their values are drawn according to 2 distributions: one for vertices joining nodes of +r comment # the same class, and another for vertices joining nodes of different classes. +r comment # The two distributions have different means but a single standard deviation. +r code generateCovariablesCondZ<-function(g,sameclustermean=0,otherclustermean=2,sigma=1) +r code { +r code mu=CreateMu(g$classes,sameclustermean,otherclustermean) +r code res=SimDataYcondZ(g$nodeclasses,mu,sigma) +r code cmcovars=list(graph=g,sameclustermean=sameclustermean,otherclustermean=otherclustermean,sigma=sigma,mu=mu,y=res) +r code attr(cmcovars,'class')<-c('cmcovarz','cmcovar') +r code cmcovars +r code } +r blank +r comment # Generate covariable data for the graph 'g'. Covariables are associated to vertex data, and +r comment # their values are drawn according to 2 distributions: one for vertices joining nodes of +r comment # the same class, and another for vertices joining nodes of different classes. +r comment # The two distributions have different means but a single standard deviation. +r comment # This function generates two sets of covariables. +r code generateCovariablesCondXZ<-function(g,sameclustermean=c(0,3),otherclustermean=c(2,5),sigma=1) +r code { +r code mux0=CreateMu(g$classes,sameclustermean[1],otherclustermean[1]) +r code mux1=CreateMu(g$classes,sameclustermean[2],otherclustermean[2]) +r code res=SimDataYcondXZ(g$nodeclasses,g$adjacency,mux0,mux1,sigma) +r code cmcovars=list(graph=g,sameclustermean=sameclustermean,otherclustermean=otherclustermean,sigma=sigma,mu=c(mux0,mux1),y=res) +r code attr(cmcovars,'class')<-c('cmcovarxz','cmcovar') +r code cmcovars +r code } +r blank +r blank +r comment # Override the print function for a cleaner covariable output. +r code print.cmcovar<-function(x,...) +r code { +r code cat("Classes : ",x$graph$classes,"\n", +r code "Intra cluster mean: ",x$sameclustermean,"\n", +r code "Cross cluster mean: ",x$otherclustermean,"\n", +r code "Variance : ",x$sigma,"\n", +r code "Covariables :\n",x$y,"\n") +r code } +r blank +r blank +r comment # Perform parameter estimation on 'graph' given the covariables 'covars'. +r code estimateCondZ<-function(graph,covars,maxiterations,initialclasses,selfloops) +r code { +r code res=EMalgorithm(initialclasses,covars$y,graph$adjacency,maxiterations,FALSE,selfloops) +r code cmestimation=list(mean=res$MuEstimated,variance=res$VarianceEstimated,pi=res$PIEstimated,alpha=res$AlphaEstimated,tau=res$TauEstimated,jexpected=res$EJ,graph=graph) +r code attr(cmestimation,'class')<-c('cmestimationz') +r code cmestimation +r code } +r blank +r comment # Private generic estimation function used to allow various call conventions for estimation functions. +r code privateestimate<-function(covars,graph,maxiterations,initialclasses,selfloops,...) UseMethod("privateestimate") +r blank +r comment # Private estimation function used to allow various call conventions for estimation functions. +r comment # Override of generic function for single covariables. +r code privateestimate.cmcovarz<-function(covars,graph,maxiterations,initialclasses,selfloops,...) +r code { +r code res=estimateCondZ(graph,covars,maxiterations,initialclasses,selfloops) +r code attr(res,'class')<-c(attr(res,'class'),'cmestimation') +r code res +r blank +r code } +r blank +r comment # Perform parameter estimation on 'graph' given the covariables 'covars'. +r code estimateCondXZ<-function(graph,covars,maxiterations,initialclasses,selfloops) +r code { +r comment #resSimXZ = EMalgorithmXZ(TauIni,Y2,Adjacente,30,SelfLoop=FALSE) +r code res=EMalgorithmXZ(initialclasses,covars$y,graph$adjacency,maxiterations,selfloops) +r code cmestimation=list(mean=c(res$MuEstimated1,res$MuEstimated2),variance=res$VarianceEstimated,pi=res$PIEstimated,alpha=res$AlphaEstimated,tau=res$TauEstimated,jexpected=res$EJ,graph=graph) +r code attr(cmestimation,'class')<-c('cmestimationxz') +r code cmestimation +r code } +r blank +r comment # Private estimation function used to allow various call conventions for estimation functions. +r comment # Override of generic function for multiple covariables. +r code privateestimate.cmcovarxz<-function(covars,graph,maxiterations,initialclasses,selfloops,...) +r code { +r code res=estimateCondXZ(graph,covars,maxiterations,initialclasses,selfloops) +r code attr(res,'class')<-c(attr(res,'class'),'cmestimation') +r code res +r code } +r blank +r comment # Generic estimation function applicable to graphs with covariables. +r code estimate<-function(graph,covars,...) UseMethod("estimate") +r blank +r comment # Override of the generic estimation function. Performs the actual function dispatch depending on the class of covariables. +r code estimate.cmgraph<-function(graph,covars,maxiterations=20,initialclasses=t(rmultinom(size=1,prob=graph$proba,n=graph$nodes)),selfloops=FALSE,method=NULL,...) +r code { +r code if (length(method) == 0) { +r code res=privateestimate(covars,graph,maxiterations,initialclasses,selfloops,...) +r code } else { +r code res=method(graph,covars,maxiterations,initialclasses,selfloops) +r code attr(res,'class')<-c(attr(res,'class'),'cmestimation') +r code } +r code res +r code } +r blank +r comment # Override of the generic pliot function for estimation results. +r code plot.cmestimation<-function(x,...) +r code { +r code par(mfrow = c(1,2)) +r code plot(x$jexpected) +r code title("Expected value of J: Convergence criterion") +r blank +r code map=MAP(x$tau) +r code gplot(x$graph$adjacency,vertex.col=map$node.classes+2) +r code title("Network with estimated classes") +r blank +r code } +r blank +r comment # Generic private ICL computation function for graphs and covariables. +r code privatecomputeICL<-function(covars,graph,qmin,qmax,loops,maxiterations,selfloops) UseMethod("privatecomputeICL") +r blank +r blank +r comment # Private ICL computation function for graphs with single covariables. +r code privatecomputeICL.cmcovarz<-function(covars,graph,qmin,qmax,loops,maxiterations,selfloops) +r code { +r code res=ICL(X=graph$adjacency,Y=covars$y,Qmin=qmin,Qmax=qmax,loop=loops,NbIteration=maxiterations,SelfLoop=selfloops,Plot=FALSE) +r code attr(res,'class')<-c('cmiclz') +r code res +r blank +r code } +r blank +r comment # Private ICL computation function for graphs with multiple covariables. +r code privatecomputeICL.cmcovarxz<-function(covars,graph,qmin,qmax,loops,maxiterations,selfloops) +r code { +r code res=ICL(X=graph$adjacency,Y=covars$y,Qmin=qmin,Qmax=qmax,loop=loops,NbIteration=maxiterations,SelfLoop=selfloops,Plot=FALSE) +r code attr(res,'class')<-c('cmiclxz') +r code res +r code } +r blank +r blank +r comment # Generic public ICL computation function applicable to graph objects. +r code computeICL<-function(graph,covars,qmin,qmax,...) UseMethod("computeICL") +r blank +r comment # Override of ICL computation function applicable to graph objects. +r comment # Performs the actual method dispatch to private functions depending on the type of covariables. +r code computeICL.cmgraph<-function(graph,covars,qmin,qmax,loops=10,maxiterations=20,selfloops=FALSE,...) +r code { +r code res=privatecomputeICL(covars,graph,qmin,qmax,loops,maxiterations,selfloops) +r code res$qmin=qmin +r code res$qmax=qmax +r code res$graph=graph +r code res$covars=covars +r code attr(res,'class')<-c(attr(res,'class'),'cmicl') +r code res +r code } +r blank +r comment # Override of the plot function for results of ICL computation. +r code plot.cmicl<-function(x,...) +r code { +r code par(mfrow = c(1,2)) +r code result=x$iclvalues +r code maxi=which(max(result)==result) +r code plot(seq(x$qmin,x$qmax),result,type="b",xlab="Number of classes",ylab="ICL value") +r code points(maxi+x$qmin-1,result[maxi],col="red") +r code title("ICL curve") +r code best=x$EMestimation[[maxi+x$qmin-1]] +r code tau=best$TauEstimated +r code map=MAP(tau) +r code gplot(x$graph$adjacency,vertex.col=map$node.classes+2) +r code title("Network with estimated classes") +r code } +r blank diff --git a/test/unit/r_test.rb b/test/unit/r_test.rb index 977605a..e93df7d 100644 --- a/test/unit/r_test.rb +++ b/test/unit/r_test.rb @@ -3,7 +3,7 @@ class Ohcount::RTest < Ohcount::Test def test_line_comment_1 - lb = [Ohcount::LanguageBreakdown.new("R", "", "#comment", 0)] + lb = [Ohcount::LanguageBreakdown.new("r", "", "#comment", 0)] assert_equal lb, Ohcount::parse(" #comment", "r") end From fbaef4c6e1f7e373eaa89888c1e078ed3c6826c6 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 9 Sep 2008 10:11:02 -0700 Subject: [PATCH 009/387] [FIX] Mac is filename case insenstive; linux is not. --- ext/ohcount_native/ragel_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/ohcount_native/ragel_parser.c b/ext/ohcount_native/ragel_parser.c index e82e198..e86729f 100644 --- a/ext/ohcount_native/ragel_parser.c +++ b/ext/ohcount_native/ragel_parser.c @@ -49,7 +49,7 @@ #include "phphtml_parser.h" #include "pike_parser.h" #include "python_parser.h" -#include "R_parser.h" +#include "r_parser.h" #include "rexx_parser.h" #include "ruby_parser.h" #include "rhtml_parser.h" From 079307461d884749ffe075378b7474addf6d0450 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Fri, 12 Sep 2008 09:07:45 -0700 Subject: [PATCH 010/387] [NEW] Add basic detection for GNU Affero General Public License. Not version sensitive. --- lib/licenses/license_map.rb | 5 +++++ test/expected_licenses/affero_1 | 1 + test/src_licenses/affero_1.rb | 15 +++++++++++++++ 3 files changed, 21 insertions(+) create mode 100644 test/expected_licenses/affero_1 create mode 100644 test/src_licenses/affero_1.rb diff --git a/lib/licenses/license_map.rb b/lib/licenses/license_map.rb index 666941e..dca3fea 100644 --- a/lib/licenses/license_map.rb +++ b/lib/licenses/license_map.rb @@ -22,6 +22,11 @@ def initialize() "Adaptive Public License", /\bAdaptive\s*Public\s*License\b/i ), + SoftwareLicense.new(:affero, + "http://www.affero.org/oagpl.html", + "GNU Affero General Public License", + /\bGNU\s+Affero\s+General\s+Public\s+License\b/i ), + SoftwareLicense.new(:apache, "http://www.opensource.org/licenses/apachepl.php", "Apache Software License", diff --git a/test/expected_licenses/affero_1 b/test/expected_licenses/affero_1 new file mode 100644 index 0000000..077775a --- /dev/null +++ b/test/expected_licenses/affero_1 @@ -0,0 +1 @@ +affero diff --git a/test/src_licenses/affero_1.rb b/test/src_licenses/affero_1.rb new file mode 100644 index 0000000..bda4932 --- /dev/null +++ b/test/src_licenses/affero_1.rb @@ -0,0 +1,15 @@ +# | This program is free software; you can redistribute it and/or modify it under the | +# | terms of the GNU Affero General Public License version 3 as published by the Free | +# | Software Foundation with the addition of the following permission added to Section | +# | 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK IN WHICH THE | +# | COPYRIGHT IS OWNED BY RUBYCAMPUS LLC, RUBYCAMPUS LLC DISCLAIMS THE WARRANTY OF NON | +# | INFRINGEMENT OF THIRD PARTY RIGHTS. | +# | | +# | This program is distributed in the hope that it will be useful, but WITHOUT ANY | +# | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A | +# | PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. | +# | | +# | You should have received a copy of the GNU Affero General Public License along | +# | with this program; if not, see http://www.gnu.org/licenses or write to the Free | +# | Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 | +# | USA. | From 355b33a216f9a90463cd3d16e6f211defd258f09 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Mon, 15 Sep 2008 14:08:10 -0700 Subject: [PATCH 011/387] [FIX] Perl POD can be terminated by EOF --- ext/ohcount_native/ragel_parsers/perl.rl | 2 +- test/expected_dir/perl_pod_to_eof.pl | 1 + test/src_dir/perl_pod_to_eof.pl | 1 + test/unit/perl_test.rb | 4 +--- 4 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 test/expected_dir/perl_pod_to_eof.pl create mode 100644 test/src_dir/perl_pod_to_eof.pl diff --git a/ext/ohcount_native/ragel_parsers/perl.rl b/ext/ohcount_native/ragel_parsers/perl.rl index a88fa12..e7d7c0b 100644 --- a/ext/ohcount_native/ragel_parsers/perl.rl +++ b/ext/ohcount_native/ragel_parsers/perl.rl @@ -54,7 +54,7 @@ enum { ws | ^space @comment - )*; + )* %/commit; perl_comment = perl_line_comment | perl_block_comment; perl_sq_str = diff --git a/test/expected_dir/perl_pod_to_eof.pl b/test/expected_dir/perl_pod_to_eof.pl new file mode 100644 index 0000000..4f2b850 --- /dev/null +++ b/test/expected_dir/perl_pod_to_eof.pl @@ -0,0 +1 @@ +perl comment =head NAME diff --git a/test/src_dir/perl_pod_to_eof.pl b/test/src_dir/perl_pod_to_eof.pl new file mode 100644 index 0000000..88d626a --- /dev/null +++ b/test/src_dir/perl_pod_to_eof.pl @@ -0,0 +1 @@ +=head NAME diff --git a/test/unit/perl_test.rb b/test/unit/perl_test.rb index cfe8df5..c70b8ff 100644 --- a/test/unit/perl_test.rb +++ b/test/unit/perl_test.rb @@ -12,10 +12,8 @@ def test_perl_in_cgi def test_comprehensive verify_parse("perl1.pl") - end - - def test_comprehensive verify_parse("perl_module.pm") + verify_parse("perl_pod_to_eof.pl") # Verifies ticket #267 end def test_comment_entities From 61daf250c3e9e0981323101ab75cad7974023d84 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Mon, 15 Sep 2008 14:17:18 -0700 Subject: [PATCH 012/387] [FIX] Better detection of GPL3 ... add match for "GNU GPL v3" --- lib/licenses/license_map.rb | 2 +- test/expected_licenses/gpl3_t2 | 2 ++ test/src_licenses/gpl3_t2.cs | 4 ++++ test/unit/license_sniffer_test.rb | 4 ++-- 4 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 test/expected_licenses/gpl3_t2 create mode 100644 test/src_licenses/gpl3_t2.cs diff --git a/lib/licenses/license_map.rb b/lib/licenses/license_map.rb index dca3fea..67acea2 100644 --- a/lib/licenses/license_map.rb +++ b/lib/licenses/license_map.rb @@ -125,7 +125,7 @@ def initialize() SoftwareLicense.new(:gpl3, "http://www.gnu.org/licenses/gpl-3.0.html", "GNU General Public License 3.0", - /GNU GENERAL PUBLIC LICENSE.{0,100}Version 3/im, + /GNU (GENERAL PUBLIC LICENSE|GPL).{0,100}(Version |v)3/im, /((at your option) any later version)|(GENERAL PUBLIC LICENSE.*GENERAL PUBLIC LICENSE)/i), SoftwareLicense.new(:lgpl3, diff --git a/test/expected_licenses/gpl3_t2 b/test/expected_licenses/gpl3_t2 new file mode 100644 index 0000000..9beb717 --- /dev/null +++ b/test/expected_licenses/gpl3_t2 @@ -0,0 +1,2 @@ +gpl3 +bsd diff --git a/test/src_licenses/gpl3_t2.cs b/test/src_licenses/gpl3_t2.cs new file mode 100644 index 0000000..ea5798f --- /dev/null +++ b/test/src_licenses/gpl3_t2.cs @@ -0,0 +1,4 @@ +/* + * Licensed under the terms of the GNU GPL v3, with Classpath Linking Exception + * Licensed under the terms of the New BSD License for exclusive use by the Ensemble OS Project + */ diff --git a/test/unit/license_sniffer_test.rb b/test/unit/license_sniffer_test.rb index ec0f6f7..433dc50 100644 --- a/test/unit/license_sniffer_test.rb +++ b/test/unit/license_sniffer_test.rb @@ -25,13 +25,13 @@ def test_expected_licenses next if f[0..0] == "." sfc = SimpleFileContext.new(filename) - detected_licenses = LicenseSniffer.parse(sfc.contents, Detector.detect(sfc)) + detected_licenses = LicenseSniffer.parse(sfc.contents, Detector.detect(sfc)).sort { |a,b| a.to_s <=> b.to_s } # expected_licenses begin f =~ /^([^\.]*)/ expected_filename = $1 - expected_licenses = File.new(expected_dir + "/" + expected_filename).read.split.collect { |l| l.intern } + expected_licenses = File.new(expected_dir + "/" + expected_filename).read.split.sort.collect { |l| l.intern } rescue case $! when Errno::ENOENT From 112e46e86b5a675fb1bbce2ac965ec7999dd518f Mon Sep 17 00:00:00 2001 From: Niel Drummond Date: Fri, 19 Sep 2008 19:10:53 +0200 Subject: [PATCH 013/387] Added haXe parser and test case --- ext/ohcount_native/ragel_parser.c | 2 + ext/ohcount_native/ragel_parsers/haxe.rl | 123 +++++++++++++++++++++++++++++++ lib/ohcount/detector.rb | 1 + lib/ohcount/sloc_info.rb | 1 + test/expected_dir/haxe1.hx | 101 +++++++++++++++++++++++++ test/src_dir/haxe1.hx | 101 +++++++++++++++++++++++++ test/unit/haxe_test.rb | 17 +++++ 7 files changed, 346 insertions(+) create mode 100644 ext/ohcount_native/ragel_parsers/haxe.rl create mode 100644 test/expected_dir/haxe1.hx create mode 100644 test/src_dir/haxe1.hx create mode 100644 test/unit/haxe_test.rb diff --git a/ext/ohcount_native/ragel_parser.c b/ext/ohcount_native/ragel_parser.c index e86729f..9aa02dc 100644 --- a/ext/ohcount_native/ragel_parser.c +++ b/ext/ohcount_native/ragel_parser.c @@ -30,6 +30,7 @@ #include "groovy_parser.h" #include "haml_parser.h" #include "haskell_parser.h" +#include "haxe_parser.h" #include "html_parser.h" #include "java_parser.h" #include "javascript_parser.h" @@ -109,6 +110,7 @@ struct language languages[] = { { "groovy", parse_groovy }, { "haskell", parse_haskell }, { "haml", parse_haml }, + { "haxe", parse_haxe }, { "html", parse_html }, { "java", parse_java }, { "javascript", parse_javascript }, diff --git a/ext/ohcount_native/ragel_parsers/haxe.rl b/ext/ohcount_native/ragel_parsers/haxe.rl new file mode 100644 index 0000000..2626e5e --- /dev/null +++ b/ext/ohcount_native/ragel_parsers/haxe.rl @@ -0,0 +1,123 @@ +// haxe.rl patched by Niel Drummond from actionscript version written by Mitchell Foral. mitchellcaladbolgnet. + +/************************* Required for every parser *************************/ +#ifndef RAGEL_HAXE_PARSER +#define RAGEL_HAXE_PARSER + +#include "ragel_parser_macros.h" + +// the name of the language +const char *HX_LANG = "haxe"; + +// the languages entities +const char *hx_entities[] = { + "space", "comment", "string", "any", +}; + +// constants associated with the entities +enum { + HX_SPACE = 0, HX_COMMENT, HX_STRING, HX_ANY +}; + +/*****************************************************************************/ + +%%{ + machine haxe; + write data; + include common "common.rl"; + + # Line counting machine + + action hx_ccallback { + switch(entity) { + case HX_SPACE: + ls + break; + case HX_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(HX_LANG) + break; + case NEWLINE: + std_newline(HX_LANG) + } + } + + hx_line_comment = + '//' @comment ( + escaped_newline %{ entity = INTERNAL_NL; } %hx_ccallback + | + ws + | + (nonnewline - ws) @comment + )*; + + hx_block_comment = + '/*' @comment ( + newline %{ entity = INTERNAL_NL; } %hx_ccallback + | + ws + | + (nonnewline - ws) @comment + )* :>> '*/'; + hx_comment = hx_line_comment | hx_block_comment; + + hx_sq_str = '\'' @code ([^\r\n\f'\\] | '\\' nonnewline)* '\''; + hx_dq_str = '"' @code ([^\r\n\f"\\] | '\\' nonnewline)* '"'; + hx_string = hx_sq_str | hx_dq_str; + + hx_line := |* + spaces ${ entity = HX_SPACE; } => hx_ccallback; + hx_comment; + hx_string; + newline ${ entity = NEWLINE; } => hx_ccallback; + ^space ${ entity = HX_ANY; } => hx_ccallback; + *|; + + # Entity machine + + action hx_ecallback { + callback(HX_LANG, hx_entities[entity], cint(ts), cint(te)); + } + hx_line_comment_entity = '//' nonnewline*; + hx_block_comment_entity = '/*' any* :>> '*/'; + hx_comment_entity = hx_line_comment_entity | hx_block_comment_entity; + + hx_entity := |* + space+ ${ entity = HX_SPACE; } => hx_ecallback; + hx_comment_entity ${ entity = HX_COMMENT; } => hx_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with Haxe code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_haxe(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int start, int end) + ) { + init + + %% write init; + cs = (count) ? haxe_en_hx_line : haxe_en_hx_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(HX_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index 74c5b91..f18a7b2 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -155,6 +155,7 @@ def self.binary_filename?(filename) '.hpp' => "cpp", '.h++' => "cpp", '.hs' => "haskell", + '.hx' => "haxe", '.hxx' => "cpp", '.hh' => "cpp", '.hrl' => "erlang", diff --git a/lib/ohcount/sloc_info.rb b/lib/ohcount/sloc_info.rb index 6fbed57..6d41350 100644 --- a/lib/ohcount/sloc_info.rb +++ b/lib/ohcount/sloc_info.rb @@ -66,6 +66,7 @@ def empty? 'groovy' => {:nice_name => 'Groovy' , :category => 0}, 'haml' => {:nice_name => 'Haml' , :category => 1}, 'html' => {:nice_name => 'HTML' , :category => 1}, + 'hx' => {:nice_name => 'haXe' , :category => 0}, 'java' => {:nice_name => 'Java' , :category => 0}, 'javascript' => {:nice_name => 'JavaScript' , :category => 0}, 'lisp' => {:nice_name => 'Lisp' , :category => 0}, diff --git a/test/expected_dir/haxe1.hx b/test/expected_dir/haxe1.hx new file mode 100644 index 0000000..f4551b2 --- /dev/null +++ b/test/expected_dir/haxe1.hx @@ -0,0 +1,101 @@ +haxe comment /* +haxe comment # ***** BEGIN LICENSE BLOCK ***** +haxe comment Copyright the original author or authors. +haxe comment Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License"); +haxe comment you may not use this file except in compliance with the License. +haxe comment You may obtain a copy of the License at +haxe comment http://www.mozilla.org/MPL/MPL-1.1.html +haxe comment Unless required by applicable law or agreed to in writing, software +haxe comment distributed under the License is distributed on an "AS IS" BASIS, +haxe comment WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +haxe comment See the License for the specific language governing permissions and +haxe comment limitations under the License. +haxe blank +haxe comment # ***** END LICENSE BLOCK ***** +haxe comment */ +haxe blank +haxe code package sandy.parser; +haxe blank +haxe comment /** +haxe comment * The Parser factory class creates instances of parser classes. +haxe comment * The specific parser can be specified in the create method's second parameter. +haxe comment * +haxe comment * @author Thomas Pfeiffer - kiroukou +haxe comment * @author Niel Drummond - haXe port +haxe comment * +haxe comment * +haxe comment * +haxe comment * @example To parse a 3DS file at runtime: +haxe comment * +haxe comment * +haxe comment * var parser:IParser = Parser.create( "/path/to/my/3dsfile.3ds", Parser.max ); +haxe comment * +haxe comment * +haxe comment */ +haxe blank +haxe code class Parser +haxe code { +haxe comment /** +haxe comment * Parameter that is used to specify that the ASE (ASCII Scene Export) +haxe comment * Parser should be used +haxe comment */ +haxe code public static var ASE:String = "ASE"; +haxe comment /** +haxe comment * Parameter that is used to specify that the 3DS (3D Studio) Parser +haxe comment * should be used +haxe comment */ +haxe code public static var MAX_3DS:String = "3DS"; +haxe comment /** +haxe comment * Parameter that is used to specify that the COLLADA (COLLAborative +haxe comment * Design Activity ) Parser should be used +haxe comment */ +haxe code public static var COLLADA:String = "DAE"; +haxe blank +haxe comment /** +haxe comment * The create method chooses which parser to use. This can be done automatically +haxe comment * by looking at the file extension or by passing the parser type String as the +haxe comment * second parameter. +haxe comment * +haxe comment * @example To parse a 3DS file at runtime: +haxe comment * +haxe comment * +haxe comment * var parser:IParser = Parser.create( "/path/to/my/3dsfile.3ds", Parser.MAX ); +haxe comment * +haxe comment * +haxe comment * @param p_sFile Can be either a string pointing to the location of the +haxe comment * file or an instance of an embedded file +haxe comment * @param p_sParserType The parser type string +haxe comment * @param p_nScale The scale factor +haxe comment * @return The parser to be used +haxe comment */ +haxe code public static function create( p_sFile:Dynamic, ?p_sParserType:String, ?p_nScale:Float ):IParser +haxe code { +haxe code if ( p_nScale == null ) p_nScale = 1; +haxe blank +haxe code var l_sExt:String,l_iParser:IParser = null; +haxe comment // -- +haxe code if( Std.is( p_sFile, String ) && p_sParserType == null ) +haxe code { +haxe code l_sExt = (p_sFile.split('.')).reverse()[0]; +haxe code } +haxe code else +haxe code { +haxe code l_sExt = p_sParserType; +haxe code } +haxe comment // -- +haxe code switch( l_sExt.toUpperCase() ) +haxe code { +haxe code case "ASE": +haxe code l_iParser = new ASEParser( p_sFile, p_nScale ); +haxe code case "OBJ": +haxe code case "DAE": +haxe code l_iParser = new ColladaParser( p_sFile, p_nScale ); +haxe code case "3DS": +haxe code l_iParser = new Parser3DS( p_sFile, p_nScale ); +haxe code default: +haxe code } +haxe comment // -- +haxe code return l_iParser; +haxe code } +haxe code } +haxe blank diff --git a/test/src_dir/haxe1.hx b/test/src_dir/haxe1.hx new file mode 100644 index 0000000..d8292c0 --- /dev/null +++ b/test/src_dir/haxe1.hx @@ -0,0 +1,101 @@ +/* +# ***** BEGIN LICENSE BLOCK ***** +Copyright the original author or authors. +Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.mozilla.org/MPL/MPL-1.1.html +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +# ***** END LICENSE BLOCK ***** +*/ + +package sandy.parser; + +/** + * The Parser factory class creates instances of parser classes. + * The specific parser can be specified in the create method's second parameter. + * + * @author Thomas Pfeiffer - kiroukou + * @author Niel Drummond - haXe port + * + * + * + * @example To parse a 3DS file at runtime: + * + * + * var parser:IParser = Parser.create( "/path/to/my/3dsfile.3ds", Parser.max ); + * + * + */ + +class Parser +{ + /** + * Parameter that is used to specify that the ASE (ASCII Scene Export) + * Parser should be used + */ + public static var ASE:String = "ASE"; + /** + * Parameter that is used to specify that the 3DS (3D Studio) Parser + * should be used + */ + public static var MAX_3DS:String = "3DS"; + /** + * Parameter that is used to specify that the COLLADA (COLLAborative + * Design Activity ) Parser should be used + */ + public static var COLLADA:String = "DAE"; + + /** + * The create method chooses which parser to use. This can be done automatically + * by looking at the file extension or by passing the parser type String as the + * second parameter. + * + * @example To parse a 3DS file at runtime: + * + * + * var parser:IParser = Parser.create( "/path/to/my/3dsfile.3ds", Parser.MAX ); + * + * + * @param p_sFile Can be either a string pointing to the location of the + * file or an instance of an embedded file + * @param p_sParserType The parser type string + * @param p_nScale The scale factor + * @return The parser to be used + */ + public static function create( p_sFile:Dynamic, ?p_sParserType:String, ?p_nScale:Float ):IParser + { + if ( p_nScale == null ) p_nScale = 1; + + var l_sExt:String,l_iParser:IParser = null; + // -- + if( Std.is( p_sFile, String ) && p_sParserType == null ) + { + l_sExt = (p_sFile.split('.')).reverse()[0]; + } + else + { + l_sExt = p_sParserType; + } + // -- + switch( l_sExt.toUpperCase() ) + { + case "ASE": + l_iParser = new ASEParser( p_sFile, p_nScale ); + case "OBJ": + case "DAE": + l_iParser = new ColladaParser( p_sFile, p_nScale ); + case "3DS": + l_iParser = new Parser3DS( p_sFile, p_nScale ); + default: + } + // -- + return l_iParser; + } +} + diff --git a/test/unit/haxe_test.rb b/test/unit/haxe_test.rb new file mode 100644 index 0000000..a2902e6 --- /dev/null +++ b/test/unit/haxe_test.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class Ohcount::HaxeTest < Ohcount::Test + def test_comments + lb = [Ohcount::LanguageBreakdown.new("haxe", "", "//comment", 0)] + assert_equal lb, Ohcount::parse(" //comment", "haxe") + end + + def test_comprehensive + verify_parse("haxe1.hx") + end + + def test_comment_entities + assert_equal('//comment', entities_array(' //comment', 'haxe', :comment).first) + assert_equal('/*comment*/', entities_array(' /*comment*/', 'haxe', :comment).first) + end +end From 2d58d3fc33ecef3bc6bf8dd7c36e438e8a161f84 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 30 Sep 2008 16:50:25 -0700 Subject: [PATCH 014/387] [FIX] "haxe" was incorrectly listed has "hx" in the sloc_info hash --- bin/ohcount | 13 +++++++++++++ lib/ohcount/sloc_info.rb | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/bin/ohcount b/bin/ohcount index 7f73791..61de8c6 100755 --- a/bin/ohcount +++ b/bin/ohcount @@ -216,6 +216,17 @@ HELP printf(" %s\n", file) end + def memoryleak + puts "Parsing one file repeatedly. Watch your RAM vanish...." + sfc = Ohcount::SimpleFileContext.new(files.first, files) + while true + polyglot = Ohcount::Detector.detect(sfc) + if polyglot + Ohcount::parse(sfc.contents, polyglot) {} + end + end + end + def summary STDOUT.write "Examining #{files.size} file(s)" @@ -306,6 +317,8 @@ HELP self.subcommand = :individual when '-l', '--licenses' self.subcommand = :licenses + when '-m', '--memoryleak' + self.subcommand = :memoryleak when '-e', '--entities' self.subcommand = :entities when '-re' diff --git a/lib/ohcount/sloc_info.rb b/lib/ohcount/sloc_info.rb index 6d41350..82040a9 100644 --- a/lib/ohcount/sloc_info.rb +++ b/lib/ohcount/sloc_info.rb @@ -65,8 +65,8 @@ def empty? 'fortranfree' => {:nice_name => 'Fortran (Free-format)', :category => 0}, 'groovy' => {:nice_name => 'Groovy' , :category => 0}, 'haml' => {:nice_name => 'Haml' , :category => 1}, + 'haxe' => {:nice_name => 'HaXe' , :category => 0}, 'html' => {:nice_name => 'HTML' , :category => 1}, - 'hx' => {:nice_name => 'haXe' , :category => 0}, 'java' => {:nice_name => 'Java' , :category => 0}, 'javascript' => {:nice_name => 'JavaScript' , :category => 0}, 'lisp' => {:nice_name => 'Lisp' , :category => 0}, From 1761072384ec461acf905dc9ddf6ecac4a768ae7 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Wed, 1 Oct 2008 10:42:06 -0700 Subject: [PATCH 015/387] [FIX] Better detection of lgpl3 --- lib/licenses/license_map.rb | 2 +- test/expected_licenses/lgpl3_t2 | 1 + test/src_licenses/lgpl3_t2.C | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 test/expected_licenses/lgpl3_t2 create mode 100644 test/src_licenses/lgpl3_t2.C diff --git a/lib/licenses/license_map.rb b/lib/licenses/license_map.rb index 67acea2..d1e5d24 100644 --- a/lib/licenses/license_map.rb +++ b/lib/licenses/license_map.rb @@ -131,7 +131,7 @@ def initialize() SoftwareLicense.new(:lgpl3, "http://www.gnu.org/licenses/lgpl-3.0.html", "GNU Lesser General Public License 3.0", - /((\blgpl\b)|(\bgnu\s*(library|lesser)\s*(general\s*)?(public\s*)?license\b)|(\b(lesser|library)\s*gpl\b)).{0,20}\b3(\.0)?\b/i ), + /((\blgpl\b)|(\bgnu\s*(library|lesser)\s*(general\s*)?(public\s*)?license\b)|(\b(lesser|library)\s*gpl\b)).{0,10}(\bas published by the free software foundation\b)?.{0,10}(\bversion\b)?.{0,10}\b3(\.0)?\b/i ), SoftwareLicense.new(:gpl, "http://www.opensource.org/licenses/gpl-license.php", diff --git a/test/expected_licenses/lgpl3_t2 b/test/expected_licenses/lgpl3_t2 new file mode 100644 index 0000000..52b7d89 --- /dev/null +++ b/test/expected_licenses/lgpl3_t2 @@ -0,0 +1 @@ +lgpl3 diff --git a/test/src_licenses/lgpl3_t2.C b/test/src_licenses/lgpl3_t2.C new file mode 100644 index 0000000..a39c093 --- /dev/null +++ b/test/src_licenses/lgpl3_t2.C @@ -0,0 +1,15 @@ +// This file is part of MyProject. +// Copyright (C) 2005 University of California +// +// MyProject is free software: you can redistribute it and/or modify +// it under the terms of the gnu lesser general public license as published +// by the free software foundation, either version 3 of the license, or +// (at your option) any later version. +// +// MyProject is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License with MyProject. If not, see . From e5cbee5004ac15d4e7801b096bab884d7cbf9713 Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Tue, 28 Oct 2008 12:39:04 -0700 Subject: [PATCH 016/387] [NEW] Major cleanup. Morphed SimpleFileContext into a more general SourceFile, from which most of ohcount's functionality is now available. --- bin/ohcount | 82 ++--- lib/licenses/license_sniffer.rb | 14 - lib/ohcount.rb | 16 +- lib/ohcount/detector.rb | 573 --------------------------------- lib/ohcount/simple_file_context.rb | 68 ---- test/test_helper.rb | 7 +- test/unit/actionscript_test.rb | 17 - test/unit/ada_test.rb | 20 -- test/unit/assembler_test.rb | 21 -- test/unit/autoconf_test.rb | 12 - test/unit/automake_test.rb | 12 - test/unit/awk_test.rb | 22 -- test/unit/basic_test.rb | 26 -- test/unit/bat_test.rb | 16 - test/unit/boo_test.rb | 37 --- test/unit/c_test.rb | 35 -- test/unit/clearsilver_template_test.rb | 20 -- test/unit/clearsilver_test.rb | 14 - test/unit/csharp_test.rb | 19 -- test/unit/css_test.rb | 16 - test/unit/d_test.rb | 43 --- test/unit/dcl_test.rb | 32 -- test/unit/detector_test.rb | 11 +- test/unit/dylan_test.rb | 18 -- test/unit/ebuild_test.rb | 11 - test/unit/eiffel_test.rb | 17 - test/unit/emacs_lisp.rb | 20 -- test/unit/erlang_test.rb | 18 -- test/unit/exheres_test.rb | 12 - test/unit/factor_test.rb | 18 -- test/unit/fortran_test.rb | 15 - test/unit/groovy_test.rb | 18 -- test/unit/haml_test.rb | 23 -- test/unit/haskell_test.rb | 28 -- test/unit/haxe_test.rb | 17 - test/unit/html_test.rb | 14 - test/unit/java_test.rb | 21 -- test/unit/javascript_test.rb | 22 -- test/unit/jsp_test.rb | 20 -- test/unit/license_sniffer_test.rb | 5 +- test/unit/lisp_test.rb | 38 --- test/unit/lua_test.rb | 19 -- test/unit/make_test.rb | 13 - test/unit/matlab_test.rb | 30 -- test/unit/metafont_test.rb | 16 - test/unit/metapost_test.rb | 17 - test/unit/mxml_test.rb | 14 - test/unit/ocaml_test.rb | 17 - test/unit/pascal_test.rb | 19 -- test/unit/perl_test.rb | 23 -- test/unit/php_test.rb | 18 -- test/unit/pike_test.rb | 26 -- test/unit/python_test.rb | 27 -- test/unit/r_test.rb | 18 -- test/unit/rexx_test.rb | 18 -- test/unit/rhtml_test.rb | 24 -- test/unit/ruby_test.rb | 19 -- test/unit/scala_test.rb | 14 - test/unit/scheme_test.rb | 18 -- test/unit/shell_test.rb | 16 - test/unit/smalltalk_test.rb | 18 -- test/unit/sql_test.rb | 32 -- test/unit/stratego_test.rb | 22 -- test/unit/tcl_test.rb | 16 - test/unit/tex_test.rb | 17 - test/unit/vala_test.rb | 18 -- test/unit/vhdl_test.rb | 16 - test/unit/vim_test.rb | 7 - test/unit/visual_basic_test.rb | 17 - test/unit/xml_test.rb | 16 - test/unit/xmlschema_test.rb | 16 - test/unit/xslt_test.rb | 16 - 72 files changed, 39 insertions(+), 2006 deletions(-) delete mode 100644 lib/ohcount/detector.rb delete mode 100644 lib/ohcount/simple_file_context.rb delete mode 100644 test/unit/actionscript_test.rb delete mode 100644 test/unit/ada_test.rb delete mode 100644 test/unit/assembler_test.rb delete mode 100644 test/unit/autoconf_test.rb delete mode 100644 test/unit/automake_test.rb delete mode 100644 test/unit/awk_test.rb delete mode 100644 test/unit/basic_test.rb delete mode 100644 test/unit/bat_test.rb delete mode 100644 test/unit/boo_test.rb delete mode 100644 test/unit/c_test.rb delete mode 100644 test/unit/clearsilver_template_test.rb delete mode 100644 test/unit/clearsilver_test.rb delete mode 100644 test/unit/csharp_test.rb delete mode 100644 test/unit/css_test.rb delete mode 100644 test/unit/d_test.rb delete mode 100644 test/unit/dcl_test.rb delete mode 100644 test/unit/dylan_test.rb delete mode 100644 test/unit/ebuild_test.rb delete mode 100644 test/unit/eiffel_test.rb delete mode 100644 test/unit/emacs_lisp.rb delete mode 100644 test/unit/erlang_test.rb delete mode 100644 test/unit/exheres_test.rb delete mode 100644 test/unit/factor_test.rb delete mode 100644 test/unit/fortran_test.rb delete mode 100644 test/unit/groovy_test.rb delete mode 100644 test/unit/haml_test.rb delete mode 100644 test/unit/haskell_test.rb delete mode 100644 test/unit/haxe_test.rb delete mode 100644 test/unit/html_test.rb delete mode 100644 test/unit/java_test.rb delete mode 100644 test/unit/javascript_test.rb delete mode 100644 test/unit/jsp_test.rb delete mode 100644 test/unit/lisp_test.rb delete mode 100644 test/unit/lua_test.rb delete mode 100644 test/unit/make_test.rb delete mode 100644 test/unit/matlab_test.rb delete mode 100644 test/unit/metafont_test.rb delete mode 100644 test/unit/metapost_test.rb delete mode 100644 test/unit/mxml_test.rb delete mode 100644 test/unit/ocaml_test.rb delete mode 100644 test/unit/pascal_test.rb delete mode 100644 test/unit/perl_test.rb delete mode 100644 test/unit/php_test.rb delete mode 100644 test/unit/pike_test.rb delete mode 100644 test/unit/python_test.rb delete mode 100644 test/unit/r_test.rb delete mode 100644 test/unit/rexx_test.rb delete mode 100644 test/unit/rhtml_test.rb delete mode 100644 test/unit/ruby_test.rb delete mode 100644 test/unit/scala_test.rb delete mode 100644 test/unit/scheme_test.rb delete mode 100644 test/unit/shell_test.rb delete mode 100644 test/unit/smalltalk_test.rb delete mode 100644 test/unit/sql_test.rb delete mode 100644 test/unit/stratego_test.rb delete mode 100644 test/unit/tcl_test.rb delete mode 100644 test/unit/tex_test.rb delete mode 100644 test/unit/vala_test.rb delete mode 100644 test/unit/vhdl_test.rb delete mode 100644 test/unit/vim_test.rb delete mode 100644 test/unit/visual_basic_test.rb delete mode 100644 test/unit/xml_test.rb delete mode 100644 test/unit/xmlschema_test.rb delete mode 100644 test/unit/xslt_test.rb diff --git a/bin/ohcount b/bin/ohcount index 61de8c6..33ca508 100755 --- a/bin/ohcount +++ b/bin/ohcount @@ -51,12 +51,9 @@ class OhcountCommandLine def annotate files.each do |file| - sfc = Ohcount::SimpleFileContext.new(file, files) - polyglot = Ohcount::Detector.detect(sfc) - if polyglot - Ohcount::parse(sfc.contents, polyglot) do |language, semantic, line| - puts "#{language}\t#{semantic}\t#{line}" - end + s = Ohcount::SourceFile.new(file, :filenames => files) + s.parse do |language, semantic, line| + puts "#{language}\t#{semantic}\t#{line}" end end end @@ -64,51 +61,25 @@ class OhcountCommandLine # Find all source code files def detect files.each do |file| - sfc = Ohcount::SimpleFileContext.new(file, files) - polyglot = Ohcount::Detector.detect(sfc) - puts "#{polyglot}\t#{file}" if polyglot - end - end - - # Entities - def entities - langs = Hash.new - files.each do |file| - sfc = Ohcount::SimpleFileContext.new(file, files) - polyglot = Ohcount::Detector.detect(sfc) - if polyglot - Ohcount::parse_entities(sfc.contents, polyglot) do |language, entity, s, e| - unless langs.include? language - langs[language] = Hash.new - langs[language].default = 0 - end - langs[language][entity] += 1 - end - end + s = Ohcount::SourceFile.new(file, :filenames => files) + puts "#{s.polyglot}\t#{file}" if s.polyglot end - p langs # TODO: pretty print end # Licenses def licenses files.each do |file| - sfc = Ohcount::SimpleFileContext.new(file, files) - licenses = LicenseSniffer.parse(sfc.contents, Ohcount::Detector.detect(sfc)) - if licenses.any? - symbols = licenses.collect { |l| LicenseSniffer::LicenseMap.instance.map[l].symbol }.join(",") - puts "#{symbols}\t#{file}" - end + s = Ohcount::SourceFile.new(file, :filenames => files) + next unless s.licenses.any? + symbols = licenses.collect { |l| LicenseSniffer::LicenseMap.instance.map[l].symbol }.join(",") + puts "#{symbols}\t#{file}" end end def raw_entities files.each do |file| - sfc = Ohcount::SimpleFileContext.new(file, files) - polyglot = Ohcount::Detector.detect(sfc) - if polyglot - Ohcount::parse_entities(sfc.contents, polyglot) do |language, entity, s, e| - puts "#{language}\t#{entity}\t#{s}\t#{e}" - end + Ohcount::SourceFile.new(file, :filenames => files).raw_entities do |language, entity, s, e| + puts "#{language}\t#{entity}\t#{s}\t#{e}" end end end @@ -123,7 +94,6 @@ Ohloh source code line counter command line tool. [option] can be one of the following: -a, --annotate -d, --detect - -e, --entities -re -h, --help -s, --summary @@ -141,10 +111,6 @@ Ohloh source code line counter command line tool. For each source code file found, the file name will be emitted to stdout prefixed with a tab-delimited language name. --e, --entities - - Prints the number of entities found for each language parsed. - -h, --help Display this message -i, --individual Count lines of code per file @@ -186,10 +152,9 @@ HELP files.each do |file| counts = {} languages_found=[] - sfc = Ohcount::SimpleFileContext.new(file, files) - polyglot = Ohcount::Detector.detect(sfc) - if polyglot - Ohcount::parse(sfc.contents, polyglot) do |language_name, semantic, line| + s = Ohcount::SourceFile.new(file, :filenames => files) + if s.source_code? + s.parse do |language_name, semantic, line| counts[language_name] ||={:code => 0, :comment => 0, :blank => 0} counts[language_name][semantic] += 1 languages_found << language_name unless languages_found.include?(language_name) @@ -218,12 +183,9 @@ HELP def memoryleak puts "Parsing one file repeatedly. Watch your RAM vanish...." - sfc = Ohcount::SimpleFileContext.new(files.first, files) + s = Ohcount::SourceCode.new(files.first, :filenames => files) while true - polyglot = Ohcount::Detector.detect(sfc) - if polyglot - Ohcount::parse(sfc.contents, polyglot) {} - end + s.parse {} end end @@ -237,14 +199,10 @@ HELP files.each do |file| languages_found = [] - sfc = Ohcount::SimpleFileContext.new(file, files) - polyglot = Ohcount::Detector.detect(sfc) - if polyglot - Ohcount::parse(sfc.contents, polyglot) do |language_name, semantic, line| - counts[language_name] ||= {:code => 0, :comment => 0, :blank => 0} - counts[language_name][semantic] += 1 - languages_found << language_name unless languages_found.include?(language_name) - end + Ohcount::SourceFile.new(file, :filenames => files).parse do |language_name, semantic, line| + counts[language_name] ||= {:code => 0, :comment => 0, :blank => 0} + counts[language_name][semantic] += 1 + languages_found << language_name unless languages_found.include?(language_name) end # Keep a running total of the number of files that include a specific language diff --git a/lib/licenses/license_sniffer.rb b/lib/licenses/license_sniffer.rb index 8886360..78ea0ac 100644 --- a/lib/licenses/license_sniffer.rb +++ b/lib/licenses/license_sniffer.rb @@ -50,18 +50,4 @@ def self.sniff(s) ranges.collect { |r| r[0] }.compact.uniq end - def self.parse(buffer, polyglot) - return [] unless polyglot - comments = '' - Ohcount::parse_entities(buffer, polyglot) do |language, entity, s, e| - if entity == :comment - text = buffer[s...e] # e is non-inclusive, so use ... - text.split(/[\r\n\f]+/).each do |line| - # Strip leading punctuation. - comments << ' ' + $1 if line =~ /^[\s[:punct:]]*(.*?)$/ - end - end - end - sniff(comments) - end end diff --git a/lib/ohcount.rb b/lib/ohcount.rb index 8db7bcf..8b29937 100644 --- a/lib/ohcount.rb +++ b/lib/ohcount.rb @@ -4,17 +4,19 @@ module Ohcount require 'rbconfig' OHCOUNT_ROOT = File.dirname(__FILE__) + "/.." +$: << OHCOUNT_ROOT begin require 'ohcount_native' rescue LoadError - require OHCOUNT_ROOT + "/lib/#{Config::CONFIG['arch']}/ohcount_native" + require "lib/#{Config::CONFIG['arch']}/ohcount_native" end -require OHCOUNT_ROOT + "/lib/ohcount/detector" -require OHCOUNT_ROOT + "/lib/ohcount/language_breakdown" -require OHCOUNT_ROOT + "/lib/ohcount/sloc_info" -require OHCOUNT_ROOT + "/lib/ohcount/scratch_dir" -require OHCOUNT_ROOT + "/lib/ohcount/simple_file_context" +require "lib/detector/base" +require "lib/ohcount/language_breakdown" +require "lib/ohcount/sloc_info" +require "lib/ohcount/scratch_dir" +require "lib/ohcount/source_file" -require OHCOUNT_ROOT + "/lib/licenses/license_sniffer" +require "lib/licenses/license_sniffer" +require "lib/gestalt/base" diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb deleted file mode 100644 index f18a7b2..0000000 --- a/lib/ohcount/detector.rb +++ /dev/null @@ -1,573 +0,0 @@ -# The Detector determines which Monoglot or Polyglot should be -# used to parse a source file. -# -# The Detector primarily uses filename extensions to identify languages. -# -# The hash EXTENSION_MAP maps a filename extension to the name of a parser. -# -# If a filename extension is not enough to determine the correct parser (for -# instance, the *.m extension can indicate either a Matlab or Objective-C file), -# then the EXTENSION_MAP hash will contain a symbol identifying a Ruby method -# which will be invoked. This Ruby method can examine the file -# contents and return the name of the correct parser. -# -# Many source files do not have an extension. The method +disambiguate_nil+ -# is called in these cases. The +file+ command line tool is used to determine -# the type of file and select a parser. -# -# The Detector is covered by DetectorTest. -# -class Ohcount::Detector - - module ContainsM - # A performance hack -- once we've checked for the presence of *.m files, the result - # is stored here to avoid checking twice. - attr_accessor :contains_m - # A performance hack -- once we've checked for the presence of *.pike and *.pmod files, the result - # is stored here to avoid checking twice. - attr_accessor :contains_pike_or_pmod - end - - module ContainsVB - # A performance hack -- once we've checked for the presence of *.frx, *.frm and *.vbp files, the result - # is stored here to avoid checking twice. - attr_accessor :contains_vb - end - - # The primary entry point for the detector. - # Given a file context containing the file name, content, and an array of - # other filenames in the source tree, attempts to detect which - # language family (Monoglot or Polyglot) is in use for this file. - # - # Returns nil if the language is not recognized or if the file does not - # contain any code. - # - # Example: - # - # # List all C files in the 'src' directory - # Dir.entries("src").each do |file| - # context = Ohcount::SimpleFileContext.new(file) - # polyglot = Ohcount::Detector.detect(context) - # puts "#{file}" if polyglot == 'c' - # end - # - def self.detect(file_context) - # start with filename and extension - polyglot = [ - lambda { | f | FILENAME_MAP[File.basename(f.filename)] }, - lambda { | f | EXTENSION_MAP[File.extname(f.filename)] }, - lambda { | f | EXTENSION_MAP[File.extname(f.filename).downcase] } - ].inject(nil) { | a, f | a and break a or f.call(file_context) } - case polyglot - when String - # simplest case - return polyglot if polyglot.is_a?(String) - when Symbol - # extension is ambiguous - requires custom disambiguation - self.send(polyglot, file_context) - when NilClass - return disambiguate_nil(file_context) - else - raise RuntimeError.new("Unknown file detection type") - end - end - - # Based solely on the filename, makes a judgment whether a file is a binary format. - def self.binary_filename?(filename) - ignore = [ - ".svn", - ".jar", - ".tar", - ".gz", - ".tgz", - ".zip", - ".gif", - ".jpg", - ".jpeg", - ".bmp", - ".png", - ".tif", - ".tiff", - ".ogg", - ".aiff", - ".wav", - ".mp3", - ".au", - ".ra", - ".m4a", - ".pdf", - ".mpg", - ".mov", - ".qt", - ".avi", - ".swf" - ] - ignore.include?(File.extname(filename)) - end - - # If an extension maps to a string, that string must be the name of a glot. - # If an extension maps to a Ruby symbol, that symbol must be the name of a - # Ruby method which will return the name of a glot. - EXTENSION_MAP = { - '.ada' => "ada", - '.adb' => "ada", - '.ads' => "ada", - '.as' => "actionscript", - '.asm' => "assembler", - '.awk' => "awk", - '.b' => :disambiguate_non_visual_basic, - '.bas' => :disambiguate_basic, - '.bat' => "bat", - '.bi' => :disambiguate_non_visual_basic, - '.boo' => "boo", - '.c' => "c", - '.C' => "cpp", - '.cc' => "cpp", - '.cpp' => "cpp", - '.css' => "css", - '.c++' => "cpp", - '.cxx' => "cpp", - '.com' => "dcl", - '.el' => "emacslisp", - # '.cbl' => "cobol", - # '.cob' => "cobol", - '.cs' => :disambiguate_cs, - '.dylan'=> "dylan", - '.e' => "eiffel", - '.ebuild'=> "ebuild", - '.eclass'=> "ebuild", - '.kdebuild-1'=> "ebuild", - '.erl' => "erlang", - '.exheres-0' => "exheres", - '.exlib' => "exheres", - '.f' => :disambiguate_fortran, - '.factor' => "factor", - '.ftn' => :disambiguate_fortran, - '.f77' => :disambiguate_fortran, - '.f90' => :disambiguate_fortran, - '.f95' => :disambiguate_fortran, - '.f03' => :disambiguate_fortran, - '.frx' => "visualbasic", - '.groovy'=> "groovy", - '.h' => :disambiguate_h_header, - '.haml' => 'haml', - '.H' => "cpp", - '.hpp' => "cpp", - '.h++' => "cpp", - '.hs' => "haskell", - '.hx' => "haxe", - '.hxx' => "cpp", - '.hh' => "cpp", - '.hrl' => "erlang", - '.htm' => "html", - '.html' => "html", - '.in' => :disambiguate_in, - '.inc' => :disambiguate_inc, - '.java' => "java", - '.js' => "javascript", - '.jsp' => "jsp", - '.lua' => "lua", - '.lsp' => "lisp", - '.lisp' => "lisp", - '.m' => :matlab_or_objective_c, - '.mf' => 'metafont', - '.mk' => 'make', - '.ml' => "ocaml", - '.mli' => "ocaml", - '.mm' => "objective_c", - '.mp' => 'metapost_with_tex', - '.mxml' => 'mxml', - '.nse' => 'lua', - '.pas' => "pascal", - '.pp' => "pascal", - '.php' => "php", - '.php3' => "php", - '.php4' => "php", - '.php5' => "php", - '.p6' => "perl", - '.pl' => "perl", - '.pm' => "perl", - '.perl' => "perl", - '.ph' => "perl", - '.pod' => "perl", - '.t' => "perl", - '.pike' => "pike", - '.pmc' => "c", - '.pmod' => "pike", - '.py' => "python", - '.r' => "r", - '.rhtml'=> "rhtml", - '.rb' => "ruby", - '.rex' => "rexx", - '.rexx' => "rexx", - '.s' => "assembler", - '.sc' => "scheme", - '.scala'=> "scala", - '.scm' => "scheme", - '.sh' => "shell", - '.sql' => "sql", - '.st' => "smalltalk", - '.str' => "stratego", - '.tcl' => "tcl", - '.tpl' => "html", - '.vala' => "vala", - '.vb' => "visualbasic", - '.vba' => "visualbasic", - '.vbs' => "visualbasic", - '.vhd' => "vhdl", - '.vhdl' => "vhdl", - '.vim' => "vim", - '.xml' => "xml", - '.xs' => "c", - '.xsd' => "xmlschema", - '.xsl' => "xslt", - '.d' => 'dmd', - '.di' => 'dmd', - '.tex' => 'tex', - '.ltx' => 'tex', - '.latex'=> 'tex' - } - - # Map full filenames to glots. The right hand side is a string or symbol as - # for EXTENSION_MAP. - FILENAME_MAP = { - 'Makefile' => 'make', - 'GNUmakefile' => 'make', - 'makefile' => 'make', - 'Makefile.am' => 'automake', - 'configure.in' => 'autoconf', - 'configure.ac' => 'autoconf', - 'configure' => 'autoconf' - } - - protected - - # Returns a count of lines in the buffer matching the given regular expression. - def self.lines_matching(buffer, re) - buffer.inject(0) { |total, line| line =~ re ? total+1 : total } - end - - # For *.m files, differentiates Matlab from Objective-C. - # - # This is done with a weighted heuristic that - # scans the *.m file contents for keywords, - # and also checks for the presence of matching *.h files. - def self.matlab_or_objective_c(file_context) - buffer = file_context.contents - - # if there are .h files in same directory, this probably isn't matlab - h_headers = 0.0 - h_headers = -0.5 if file_context.filenames.select { |a| a =~ /\.h$/ }.any? - - # if the contents contain 'function (' on a single line - very likely to be matlab - # if the contents contain lines starting with '%', its probably matlab comments - matlab_signatures = /(^\s*function\s*)|(^\s*%)/ - matlab_sig_score = 0.1 * lines_matching(buffer, matlab_signatures) - - # if the contents contains '//' or '/*', likely objective_c - objective_c_signatures = /(^\s*\/\/\s*)|(^\s*\/\*)|(^[+-])/ - obj_c_sig_score = -0.1 * lines_matching(buffer, objective_c_signatures) - - matlab = h_headers + matlab_sig_score + obj_c_sig_score - - matlab > 0 ? 'matlab' : 'objective_c' - end - - # For *.h files, differentiates C, C++ and Objective-C. - # - # This is done with a weighted heuristic that - # scans the *.h file contents for Objective-C keywords, - # C++ keywords and C++ headers, and also checks for the - # presence of matching *.m files. - def self.disambiguate_h_header(file_context) - buffer = file_context.contents - - # could it be realistically be objective_c ? are there any .m files at all? - # Speed hack - remember our findings in case we get the same filenames over and over - unless defined?(file_context.filenames.contains_m) - file_context.filenames.extend(ContainsM) - file_context.filenames.contains_m = file_context.filenames.select { |a| a =~ /\.m$/ }.any? - file_context.filenames.contains_pike_or_pmod = file_context.filenames.select { |a| a =~ /\.p(ike|mod)$/ }.any? - end - - if file_context.filenames.contains_m - # if the dir contains a matching *.m file, likely objective_c - if file_context.filename =~ /\.h$/ - m_counterpart = file_context.filename.gsub(/\.h$/, ".m") - return 'objective_c' if file_context.filenames.include?(m_counterpart) - end - - # ok - it just might be objective_c, let's check contents for objective_c signatures - objective_c_signatures = /(^\s*@interface)|(^\s*@end)/ - objective_c = lines_matching(buffer, objective_c_signatures) - return 'objective_c' if objective_c > 1 - end - - if file_context.filenames.contains_pike_or_pmod - # The string "pike" and a selection of common Pike keywords. - pike_signatures = /([Pp][Ii][Kk][Ee])|(string )|(mapping)|(multiset)|(import )|(inherit )|(predef)/ - pike = lines_matching(buffer, pike_signatures) - return 'pike' if pike > 0 - end - - disambiguate_c_cpp(buffer) - end - - # A map of headers that indicate C++, but that do not have C++-specific file - # extensions. This list is made from the Standard, plus Technical Report 1. - CPP_HEADERS_MAP = %w[ - algorithm - array - bitset - cassert - ccomplex - cctype - cerrno - cfenv - cfloat - cinttypes - ciso646 - climits - clocale - cmath - csetjmp - csignal - cstdarg - cstdbool - cstddef - cstdint - cstdio - cstdlib - cstring - ctgmath - ctime - cwchar - cwctype - deque - exception - fstream - functional - iomanip - ios - iosfwd - iostream - istream - iterator - limits - list - locale - map - memory - new - numeric - ostream - queue - random - regex - set - sstream - stack - stdexcept - streambuf - string - system_error - tuple - type_traits - typeinfo - unordered_map - unordered_set - utility - valarray - vector - tr1/array - tr1/ccomplex - tr1/cctype - tr1/cfenv - tr1/cfloat - tr1/cinttypes - tr1/climits - tr1/cmath - tr1/complex - tr1/cstdarg - tr1/cstdbool - tr1/cstdint - tr1/cstdio - tr1/cstdlib - tr1/ctgmath - tr1/ctime - tr1/cwchar - tr1/cwctype - tr1/memory - tr1/random - tr1/regex - tr1/tuple - tr1/type_traits - tr1/unordered_map - tr1/unordered_set - tr1/utility - ].inject({}) { | h, k | h[k] = true ; h } - - # A map of keywords that indicate C++. - CPP_KEYWORDS_MAP = %w[ - template - typename - class - namespace - ].inject({}) { | h, k | h[k] = true ; h } - - # For *.h files that we know aren't Objective-C, differentiates C and C++. - # - # This is done with a weighted heuristic that - # scans the *.h file contents for C++ keywords and C++ headers. - def self.disambiguate_c_cpp(buffer) - # Look for C++ headers - return 'cpp' if extract_c_cpp_headers(buffer).detect do | header | - EXTENSION_MAP[File.extname(header)] == 'cpp' or CPP_HEADERS_MAP.include? header - end - - # Look for C++ keywords. This could check for comments, but doesn't. - return 'cpp' if buffer.find do | line | - line.split(/\W/).find do | word | - CPP_KEYWORDS_MAP.include? word - end - end - - # Nothing to suggest C++ - 'c' - end - - # Return a list of files included in a C or C++ source file. - def self.extract_c_cpp_headers(buffer) - buffer.map do | line | - m = line.match(/^#\s*include\s+[<"](.*)[>"]/) and m[1] - end.find_all { | a | a } - end - - # Tests whether the provided buffer contains binary or text content. - # This is not fool-proof -- we basically just check for zero values - # in the early bytes of the buffer. If we find a zero, we know it - # is not (ascii) text. - def self.binary_buffer?(buffer) - 100.times do |i| - return true if buffer[i] == 0 - end - false - end - - # True if the provided buffer includes a '?php' directive - def self.php_instruction?(buffer) - buffer =~ /\?php/ - end - - # For *.in files, checks the prior extension. - # Typically used for template files (eg Makefile.in, auto.c.in, etc). - def self.disambiguate_in(file_context) - # if the filename has an extension prior to the .in - if file_context.filename =~ /\..*\.in$/ - filename = file_context.filename.gsub(/\.in$/, "") - context = Ohcount::SimpleFileContext.new(filename, file_context.filenames, file_context.contents, file_context.file_location) - return detect(context) - end - nil - end - - # For *.inc files, checks for a PHP class. - def self.disambiguate_inc(file_context) - buffer = file_context.contents - return nil if binary_buffer?(buffer) - return 'php' if php_instruction?(buffer) - nil - end - - # For files with extention *.cs, differentiates C# from Clearsilver. - def self.disambiguate_cs(file_context) - buffer = file_context.contents - return 'clearsilver_template' if lines_matching(file_context.contents, /\<\?cs/) > 0 - return 'csharp' - end - - def self.disambiguate_fortran(file_context) - buffer = file_context.contents - - definitely_not_f77 = /^ [^0-9 ]{5}/ - return 'fortranfixed' if lines_matching(buffer, definitely_not_f77) > 0 - - free_form_continuation = /&\s*\n\s*&/m - return 'fortranfree' if buffer.match(free_form_continuation) - - possibly_fixed = /^ [0-9 ]{5}/ - contig_number = /^\s*\d+\s*$/ - buffer.scan(possibly_fixed) {|leader| - return 'fortranfixed' if !(leader =~ contig_number) } - # Might as well be free-form. - return 'fortranfree' - end - - # Attempts to tell apart VB, classic BASIC and structured BASIC. - # First, checks if it is classic BASIC based on syntax. - # If not checks for .vb, .vbp, .frx and .frm files (associated with VB) - # in file context - # - # If these files are absent, assumes structured BASIC - # - def self.disambiguate_basic(file_context) - classic_basic_line = /^\d+\s+\w+.*$/ - vb_filename = /\.fr[mx]$|\.vb([aps]?)$/ - buffer = file_context.contents - if lines_matching(buffer,classic_basic_line) > 0 - return 'classic_basic' - else - unless defined?(file_context.filenames.contains_vb) - file_context.filenames.extend(ContainsVB) - file_context.filenames.contains_vb = file_context.filenames.select { |a| a =~ vb_filename }.any? - end - if file_context.filenames.contains_vb - return 'visualbasic' - else - return 'structured_basic' - end - end - end - - def self.disambiguate_non_visual_basic(file_context) - classic_basic_line = /^\d+\s+\w+.*$/ - buffer = file_context.contents - - if lines_matching(buffer,classic_basic_line) > 0 - return 'classic_basic' - else - return 'structured_basic' - end - end - - # Attempts to determine the Polyglot for files that do not have a - # filename extension. - # - # Relies on the bash +file+ command line tool as its primary method. - # - # There must be a file at file_context.file_location for +file+ - # to operate on. - # - def self.disambiguate_nil(file_context) - file_location = file_context.file_location - output = `file -b '#{ file_location }'` - case output - when /([\w\/]+)(?: -[\w_]+)* script text/, /script text executable for ([\w\/]+)/ - script = $1 - if script =~ /\/(\w*)$/ - script = $1 - end - known_languages = EXTENSION_MAP.values - return script.downcase if known_languages.include?(script.downcase) - when /([\w\-]*) shell script text/ - case $1 - when "Bourne-Again" - return "shell" - end - end - - # dang... no dice - nil - end - -end diff --git a/lib/ohcount/simple_file_context.rb b/lib/ohcount/simple_file_context.rb deleted file mode 100644 index 73774a5..0000000 --- a/lib/ohcount/simple_file_context.rb +++ /dev/null @@ -1,68 +0,0 @@ -module Ohcount - - # The context provides an abstraction layer between ohcount and the - # file being analyzed. - # - # SimpleFileContext provides ohcount with the target filename and a means - # to access the contents of the file. - # - # In simple usage scenarios, the SimpleFileContext can simply point to an actual - # file on disk. In more complex scenarios, the context allows the - # file contents to be delivered to ohcount from a temp file or - # in-memory cache. - # - class SimpleFileContext - # The original name of the file to be analyzed. - # This name will be used when detecting the language. - attr_reader :filename - - # An array of names of other files in the source tree which - # may be helpful when disambiguating the language used by the target file. - # For instance, the presence of an Objective-C *.m file is a clue when - # determining the language used in a *.h header file. - # This array is optional, but language identification may be less accurate - # without it. - attr_reader :filenames - - # The location on disk where the file content can currently be found. - # This might not be the same as the original name of the file. - # For example, file content might be stored in temporary directory. - attr_reader :file_location - - # At a minimum, you must provide the filename. - # - # You may also optionally pass an array of names of other files in the source tree. - # This will assist when disambiguating the language used by the source file. - # If you do not include this array, language identification may be less accurate. - # - # The SimpleFileContext must provide access to the file content. You can do this - # by one of three means, which will be probed in the following order: - # - # 1. You may optionally pass the content of the source file as string +cached_contents+. - # - # 2. You may optionally provide +file_location+ as the name of a file on disk - # which contains the content of this source file. - # - # 3. If you do neither 1 nor 2, then +filename+ will be assumed to be an actual file on - # disk which can be read. - # - def initialize(filename, filenames = [], cached_contents = nil, file_location = nil) - @filename = filename - @filenames = filenames - @cached_contents = cached_contents - @file_location = file_location || filename - end - - # Returns the entire content of the target file as a single string. - def contents - return @cached_contents if @cached_contents - if @file_location - File.open(file_location) do |f| - @cached_contents = f.read - end - end - return @cached_contents - end - end - -end diff --git a/test/test_helper.rb b/test/test_helper.rb index 305b590..d2cf357 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -60,11 +60,10 @@ def expected_dir # # There are numerous examples in the test directories to help you out. def verify_parse(file, filenames=[]) - sfc = Ohcount::SimpleFileContext.new(File.join(src_dir, file), filenames) - polyglot = Ohcount::Detector.detect(sfc) + source = Ohcount::SourceFile.new(File.join(src_dir, file), :filenames => filenames) buffer = '' - if polyglot - Ohcount::parse(sfc.contents, polyglot) do |language, semantic, line| + if source.polyglot + Ohcount::parse(source.contents, source.polyglot) do |language, semantic, line| buffer << "#{language}\t#{semantic}\t#{line}" end end diff --git a/test/unit/actionscript_test.rb b/test/unit/actionscript_test.rb deleted file mode 100644 index 3759081..0000000 --- a/test/unit/actionscript_test.rb +++ /dev/null @@ -1,17 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::ActionscriptTest < Ohcount::Test - def test_comments - lb = [Ohcount::LanguageBreakdown.new("actionscript", "", "//comment", 0)] - assert_equal lb, Ohcount::parse(" //comment", "actionscript") - end - - def test_comprehensive - verify_parse("as1.as") - end - - def test_comment_entities - assert_equal('//comment', entities_array(' //comment', 'actionscript', :comment).first) - assert_equal('/*comment*/', entities_array(' /*comment*/', 'actionscript', :comment).first) - end -end diff --git a/test/unit/ada_test.rb b/test/unit/ada_test.rb deleted file mode 100644 index 5279a8e..0000000 --- a/test/unit/ada_test.rb +++ /dev/null @@ -1,20 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::AdaTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("ada", "", "--comment", 0)] - assert_equal lb, Ohcount::parse(" --comment", "ada") - end - - def test_comprehensive - verify_parse("ada1.ada") - end - - def test_comprehensive_adb - verify_parse("ada1.adb") - end - - def test_comment_entities - assert_equal('--comment', entities_array(' --comment', 'ada', :comment).first) - end -end diff --git a/test/unit/assembler_test.rb b/test/unit/assembler_test.rb deleted file mode 100644 index 9f13377..0000000 --- a/test/unit/assembler_test.rb +++ /dev/null @@ -1,21 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::AssemblerTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("assembler", "", "!comment\n;comment", 0)] - assert_equal lb, Ohcount::parse(" !comment\n ;comment", "assembler") - end - - def test_comprehensive - verify_parse("assembler1.asm") - end - - def test_comprehensive_2 - verify_parse("assembler2.S") - end - - def test_comment_entities - assert_equal(['//comment', '; comment', '!comment'], - entities_array(" //comment\n; comment\n\t!comment", 'assembler', :comment)) - end -end diff --git a/test/unit/autoconf_test.rb b/test/unit/autoconf_test.rb deleted file mode 100644 index 8706b65..0000000 --- a/test/unit/autoconf_test.rb +++ /dev/null @@ -1,12 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::AutoconfTest < Ohcount::Test - def test_comprehensive - verify_parse("configure.ac") - end - - def test_comment_entities - assert_equal('dnl comment', entities_array(" dnl comment", 'autoconf', :comment).first) - end -end - diff --git a/test/unit/automake_test.rb b/test/unit/automake_test.rb deleted file mode 100644 index 57707b2..0000000 --- a/test/unit/automake_test.rb +++ /dev/null @@ -1,12 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::AutomakeTest < Ohcount::Test - def test_comprehensive - verify_parse("Makefile.am") - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'automake', :comment).first) - end -end - diff --git a/test/unit/awk_test.rb b/test/unit/awk_test.rb deleted file mode 100644 index 8e9effc..0000000 --- a/test/unit/awk_test.rb +++ /dev/null @@ -1,22 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::AwkTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("awk", "", "#comment", 0)] - assert_equal lb, Ohcount::parse(" #comment", "awk") - end - - def test_double_slash - lb = [Ohcount::LanguageBreakdown.new("awk", "\"\\\\\"\n", "#comment", 0)] - # awk doesn't recognize backslash escaping of double quote...weird - assert_equal lb, Ohcount::parse("\"\\\\\"\n#comment", "awk") - end - - def test_comprehensive - verify_parse("awk1.awk") - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'awk', :comment).first) - end -end diff --git a/test/unit/basic_test.rb b/test/unit/basic_test.rb deleted file mode 100644 index 0c28dde..0000000 --- a/test/unit/basic_test.rb +++ /dev/null @@ -1,26 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::BasicTest < Ohcount::Test - def test_sb_comments - lb = [Ohcount::LanguageBreakdown.new("structured_basic", "", "REM comment", 0)] - assert_equal lb, Ohcount::parse("REM comment", "structured_basic") - end - - def test_cb_comments - lb = [Ohcount::LanguageBreakdown.new("classic_basic", "", "100 REM comment", 0)] - assert_equal lb, Ohcount::parse(" 100 REM comment", "classic_basic") - end - - def test_comprehensive - verify_parse("classic_basic.b") - verify_parse("visual_basic.bas", ["frx1.frx"]) - verify_parse("structured_basic.b") - verify_parse("structured_basic.bas") - verify_parse("classic_basic.bas") - end - - def test_comment_entities - assert_equal('REM comment', entities_array(" REM comment", 'structured_basic', :comment).first) - assert_equal('\'comment', entities_array(" 'comment", 'classic_basic', :comment).first) - end -end diff --git a/test/unit/bat_test.rb b/test/unit/bat_test.rb deleted file mode 100644 index 1538967..0000000 --- a/test/unit/bat_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::BatTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("bat", "", "REM comment", 0)] - assert_equal lb, Ohcount::parse(" REM comment", "bat") - end - - def test_comprehensive - verify_parse("bat1.bat") - end - - def test_comment_entities - assert_equal('rem comment', entities_array(" rem comment", 'bat', :comment).first) - end -end diff --git a/test/unit/boo_test.rb b/test/unit/boo_test.rb deleted file mode 100644 index 4bfba5b..0000000 --- a/test/unit/boo_test.rb +++ /dev/null @@ -1,37 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::BooTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("boo", "", "#comment", 0)] - assert_equal lb, Ohcount::parse(" #comment", "boo") - end - - def test_block_comment - lb = [Ohcount::LanguageBreakdown.new("boo", "", "/*comment*/", 0)] - assert_equal lb, Ohcount::parse(" /*comment*/", "boo") - end - - def test_nested_block_comment - lb = [Ohcount::LanguageBreakdown.new("boo", "", "/* comment\n/* nested */\nstill a comment */", 0)] - assert_equal lb, Ohcount::parse(" /* comment\n /* nested */\n still a comment */", "boo") - end - - def test_doc_comments - lb = [Ohcount::LanguageBreakdown.new("boo", "", "\"\"\"\ndoc comment\n\"\"\"", 0)] - assert_equal lb, Ohcount::parse("\"\"\"\ndoc comment\n\"\"\"", "boo") - end - - def test_strings - lb = [Ohcount::LanguageBreakdown.new("boo", "\"abc#not a 'comment\"", "", 0)] - assert_equal lb, Ohcount::parse("\"abc#not a 'comment\"", "boo") - end - - def test_comprehensive - verify_parse("boo1.boo") - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'boo', :comment).first) - assert_equal('//comment', entities_array(" //comment", 'boo', :comment).first) - end -end diff --git a/test/unit/c_test.rb b/test/unit/c_test.rb deleted file mode 100644 index fb1e6fd..0000000 --- a/test/unit/c_test.rb +++ /dev/null @@ -1,35 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::CTest < Ohcount::Test - - def test_comments - lb = [Ohcount::LanguageBreakdown.new("c", "", "//comment", 0)] - assert_equal lb, Ohcount::parse(" //comment", "c") - end - - def test_empty_comments - lb = [Ohcount::LanguageBreakdown.new("c", "","//\n", 0)] - assert_equal lb, Ohcount::parse(" //\n", "c") - end - - - def test_block_comment - lb = [Ohcount::LanguageBreakdown.new("c", "","/*c*/", 0)] - assert_equal lb, Ohcount::parse("/*c*/", "c") - end - - def test_comprehensive - verify_parse("c1.c") - verify_parse("c_str.c") - end - - def test_comprehensive_in - verify_parse("c2.h.in") - end - - def test_comment_entities - assert_equal('//comment', entities_array(" //comment", 'c', :comment).first) - assert_equal('/*comment*/', entities_array(" /*comment*/", 'c', :comment).first) - end - -end diff --git a/test/unit/clearsilver_template_test.rb b/test/unit/clearsilver_template_test.rb deleted file mode 100644 index 51b48a8..0000000 --- a/test/unit/clearsilver_template_test.rb +++ /dev/null @@ -1,20 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::ClearsilverTemplateTest < Ohcount::Test - - def test_comment - html_lb = Ohcount::LanguageBreakdown.new("html", "", "", 0) - clearsilver_template_lb = Ohcount::LanguageBreakdown.new("clearsilver", "", "#comment\n", 0) - assert_equal [html_lb, clearsilver_template_lb], Ohcount::parse("", "clearsilver_template") - end - - def test_comprehensive - verify_parse("clearsilver_template1.cs") - end - - def test_comment_entities - assert_equal('', entities_array(" ", 'clearsilver_template', :comment).first) - assert_equal('#comment', entities_array("", 'clearsilver_template', :comment).first) - end - -end diff --git a/test/unit/clearsilver_test.rb b/test/unit/clearsilver_test.rb deleted file mode 100644 index e471bea..0000000 --- a/test/unit/clearsilver_test.rb +++ /dev/null @@ -1,14 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::ClearsilverTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("clearsilver", "", "#comment", 0)] - assert_equal lb, Ohcount::parse(" #comment", "clearsilver") - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'clearsilver', :comment).first) - end - -end diff --git a/test/unit/csharp_test.rb b/test/unit/csharp_test.rb deleted file mode 100644 index 68683b7..0000000 --- a/test/unit/csharp_test.rb +++ /dev/null @@ -1,19 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::CSharpTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("csharp", "", "//comment", 0)] - assert_equal lb, Ohcount::parse(" //comment", "csharp") - end - - def test_comprehensive - verify_parse("cs1.cs") - end - - def test_comment_entities - assert_equal('//comment', entities_array(" //comment", 'csharp', :comment).first) - assert_equal('/*comment*/', entities_array(" /*comment*/", 'csharp', :comment).first) - end - -end diff --git a/test/unit/css_test.rb b/test/unit/css_test.rb deleted file mode 100644 index 2860f66..0000000 --- a/test/unit/css_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::CssTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("css", "", "/*comment*/", 0)] - assert_equal lb, Ohcount::parse(" /*comment*/", "css") - end - - def test_comprehensive - verify_parse("css1.css") - end - - def test_comment_entities - assert_equal('/*comment*/', entities_array(" /*comment*/", 'css', :comment).first) - end -end diff --git a/test/unit/d_test.rb b/test/unit/d_test.rb deleted file mode 100644 index f12cd46..0000000 --- a/test/unit/d_test.rb +++ /dev/null @@ -1,43 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::DTest < Ohcount::Test - - def test_comments - lb = [Ohcount::LanguageBreakdown.new("dmd", "", "//comment", 0)] - assert_equal lb, Ohcount::parse(" //comment", "dmd") - end - - def test_empty_comments - lb = [Ohcount::LanguageBreakdown.new("dmd", "","//\n", 0)] - assert_equal lb, Ohcount::parse(" //\n", "dmd") - end - - def test_strings - lb = [Ohcount::LanguageBreakdown.new("dmd", "'/*' not a comment '*/'", "", 0)] - assert_equal lb, Ohcount::parse("'/*' not a comment '*/'", "dmd") - end - - def test_block_comment - lb = [Ohcount::LanguageBreakdown.new("dmd", "","/*d*/", 0)] - assert_equal lb, Ohcount::parse("/*d*/", "dmd") - - lb = [Ohcount::LanguageBreakdown.new("dmd", "","/+d+/", 0)] - assert_equal lb, Ohcount::parse("/+d+/", "dmd") - end - - def test_nested_block_comment - lb = [Ohcount::LanguageBreakdown.new("dmd", "","/+ /*d*/ not_code(); +/", 0)] - assert_equal lb, Ohcount::parse("/+ /*d*/ not_code(); +/", "dmd") - end - - def test_comprehensive - verify_parse("d1.d") - end - - def test_comment_entities - assert_equal('//comment', entities_array(" //comment", 'dmd', :comment).first) - assert_equal('/*comment*/', entities_array(" /*comment*/", 'dmd', :comment).first) - assert_equal('/+comment+/', entities_array(" /+comment+/", 'dmd', :comment).first) - end - -end diff --git a/test/unit/dcl_test.rb b/test/unit/dcl_test.rb deleted file mode 100644 index 77d6efe..0000000 --- a/test/unit/dcl_test.rb +++ /dev/null @@ -1,32 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::DclTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("dcl", "", "$!comment", 0)] - assert_equal lb, Ohcount::parse("$!comment", "dcl") - end - - def test_code - lb= [Ohcount::LanguageBreakdown.new("dcl", "$code", "", 0)] - assert_equal lb, Ohcount::parse("$code", "dcl") - end - - def test_blank - lb=[Ohcount::LanguageBreakdown.new("dcl", "", "", 1)] - assert_equal lb, Ohcount::parse("\n", "dcl") - end - - def test_input_line - lb=[Ohcount::LanguageBreakdown.new("dcl", "input", "", 0)] - assert_equal lb, Ohcount::parse("input", "dcl") - end - - - def test_comprehensive - verify_parse("dcl.com") - end - - def test_comment_entities - assert_equal('!comment', entities_array(" !comment", 'dcl', :comment).first) - end -end diff --git a/test/unit/detector_test.rb b/test/unit/detector_test.rb index c917674..72ba698 100644 --- a/test/unit/detector_test.rb +++ b/test/unit/detector_test.rb @@ -21,17 +21,15 @@ class Ohcount::DetectorTest < Ohcount::Test def do_detect(filename, filenames = []) - file_location = File.dirname(__FILE__) + "/../detect_files/" + filename - sfc = Ohcount::SimpleFileContext.new(filename, filenames, nil, file_location) - Ohcount::Detector.detect(sfc) + filepath = File.dirname(__FILE__) + "/../detect_files/" + filename + SourceFile.new(filepath, {:filenames => filenames}).polyglot end # Nonrecursively adds files from the file's directory to the context def do_detect_with_siblings(filename) - file_location = File.dirname(__FILE__) + "/../detect_files/" + filename + filepath = File.dirname(__FILE__) + "/../detect_files/" + filename filenames = Dir.entries(File.dirname(__FILE__) + File.dirname("/../detect_files/" + filename)) - [filename] - sfc = Ohcount::SimpleFileContext.new(filename, filenames, nil, file_location) - Ohcount::Detector.detect(sfc) + SourceFile.new(filepath, {:filenames => filename}).detect end def test_matlab_or_objective_c @@ -46,7 +44,6 @@ def text_fortran_fixedfree def test_detect_polyglot assert_equal "c", do_detect("foo.c") - assert_equal "c", do_detect("foo.c") assert_equal "c", do_detect("uses_no_cpp.h") assert_equal "cpp", do_detect("uses_cpp_headers.h") assert_equal "cpp", do_detect("uses_cpp_stdlib_headers.h") diff --git a/test/unit/dylan_test.rb b/test/unit/dylan_test.rb deleted file mode 100644 index aa767e2..0000000 --- a/test/unit/dylan_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::DylanTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("dylan", "", "//comment", 0)] - assert_equal lb, Ohcount::parse(" //comment", "dylan") - end - - def test_comprehensive - verify_parse("dylan1.dylan") - end - - def test_comment_entities - assert_equal('//comment', entities_array(" //comment", 'dylan', :comment).first) - assert_equal('/*comment*/', entities_array(" /*comment*/", 'dylan', :comment).first) - end -end diff --git a/test/unit/ebuild_test.rb b/test/unit/ebuild_test.rb deleted file mode 100644 index 3f4e2b3..0000000 --- a/test/unit/ebuild_test.rb +++ /dev/null @@ -1,11 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::EbuildTest < Ohcount::Test - def test_comprehensive - verify_parse("foo.ebuild") - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'ebuild', :comment).first) - end -end diff --git a/test/unit/eiffel_test.rb b/test/unit/eiffel_test.rb deleted file mode 100644 index 0843082..0000000 --- a/test/unit/eiffel_test.rb +++ /dev/null @@ -1,17 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::EiffelTest < Ohcount::Test - def test_cb_comments - lb = [Ohcount::LanguageBreakdown.new("eiffel", "", "-- comment", 0)] - assert_equal lb, Ohcount::parse(" -- comment", "eiffel") - end - - def test_comprehensive - verify_parse("eiffel.e") - end - - def test_comment_entities - assert_equal('--comment', entities_array(" --comment", 'eiffel', :comment).first) - end - -end diff --git a/test/unit/emacs_lisp.rb b/test/unit/emacs_lisp.rb deleted file mode 100644 index 50b2fd2..0000000 --- a/test/unit/emacs_lisp.rb +++ /dev/null @@ -1,20 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::EmacsLispTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("emacslisp", "", ";;comment", 0)] - assert_equal lb, Ohcount::parse(" ;;comment", "emacslisp") - end - - def test_comprehensive - verify_parse("el1.el") - end - - def test_comment_entities - assert_equal(';comment', entities_array(" ;comment", 'emacslisp', :comment).first) - end - -end - - diff --git a/test/unit/erlang_test.rb b/test/unit/erlang_test.rb deleted file mode 100644 index f6be5a4..0000000 --- a/test/unit/erlang_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::ErlangTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("erlang", "", "%%comment", 0)] - assert_equal lb, Ohcount::parse(" %%comment", "erlang") - end - - def test_comprehensive - verify_parse("erl1.erl") - end - - def test_comment_entities - assert_equal('%comment', entities_array(" %comment", 'erlang', :comment).first) - end - -end diff --git a/test/unit/exheres_test.rb b/test/unit/exheres_test.rb deleted file mode 100644 index 8d615ca..0000000 --- a/test/unit/exheres_test.rb +++ /dev/null @@ -1,12 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::ExheresTest < Ohcount::Test - def test_comprehensive - verify_parse("foo.exheres-0") - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'exheres', :comment).first) - end -end - diff --git a/test/unit/factor_test.rb b/test/unit/factor_test.rb deleted file mode 100644 index 50ebfa0..0000000 --- a/test/unit/factor_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::FactorTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("factor", "", "! comment", 0)] - assert_equal lb, Ohcount::parse(" ! comment", "factor") - end - - def test_strings - lb = [Ohcount::LanguageBreakdown.new("factor", "\"abc!not a 'comment\"", "", 0)] - assert_equal lb, Ohcount::parse("\"abc!not a 'comment\"", "factor") - end - - def test_comprehensive - verify_parse("factor1.factor") - end -end diff --git a/test/unit/fortran_test.rb b/test/unit/fortran_test.rb deleted file mode 100644 index d441f44..0000000 --- a/test/unit/fortran_test.rb +++ /dev/null @@ -1,15 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::FortranTest < Ohcount::Test - - def test_comprehensive - verify_parse("fortranfixed.f") - verify_parse("fortranfree.f") - end - - def test_comment_entities - assert_equal('!comment', entities_array(" !comment", 'fortranfree', :comment).first) - assert_equal('C comment', entities_array("C comment", 'fortranfixed', :comment).first) - end - -end diff --git a/test/unit/groovy_test.rb b/test/unit/groovy_test.rb deleted file mode 100644 index 04793a6..0000000 --- a/test/unit/groovy_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::GroovyTest < Ohcount::Test - def test_comments - lb = [Ohcount::LanguageBreakdown.new("groovy", "", "//comment", 0)] - assert_equal lb, Ohcount::parse(" //comment", "groovy") - end - - def test_comprehensive - verify_parse("groovy1.groovy") - end - - def test_comment_entities - assert_equal('//comment', entities_array(" //comment", 'groovy', :comment).first) - assert_equal('/*comment*/', entities_array(" /*comment*/", 'groovy', :comment).first) - end - -end diff --git a/test/unit/haml_test.rb b/test/unit/haml_test.rb deleted file mode 100644 index d65acb0..0000000 --- a/test/unit/haml_test.rb +++ /dev/null @@ -1,23 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::HamlTest < Ohcount::Test - def test_line_comment - lb = [Ohcount::LanguageBreakdown.new("haml", "", "/ comment", 0)] - assert_equal lb, Ohcount::parse("/ comment", "haml") - end - - def test_element - lb2 = [Ohcount::LanguageBreakdown.new("haml", "%code", "", 0)] - assert_equal lb2, Ohcount::parse(" %code", "haml") - end - - def test_element_entities - assert_equal("%element", entities_array(" %element", 'haml', :element).first) - assert_equal(".class", entities_array(" .class", 'haml', :element_class).first) - assert_equal("#id", entities_array(" #id", 'haml', :element_id).first) - end - - def test_comprehensive - verify_parse("haml.haml") - end -end diff --git a/test/unit/haskell_test.rb b/test/unit/haskell_test.rb deleted file mode 100644 index 51035bc..0000000 --- a/test/unit/haskell_test.rb +++ /dev/null @@ -1,28 +0,0 @@ -# This has been shamelessly copied from java_test.rb because my Ruby is not so -# good and I don't really know what people expect from a Ohcount language test -# -- Reinier Lamers 2008-01-19 -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::HaskellTest < Ohcount::Test - def test_comments - lb = [Ohcount::LanguageBreakdown.new("haskell", "", "--comment", 0)] - assert_equal lb, Ohcount::parse(" --comment", "haskell") - end - - def test_comprehensive - verify_parse("haskell1.hs") - end - - def test_comprehensive_with_carriage_returns - verify_parse("haskell2.hs") - end - - def test_comprehensive_with_nested_comments - verify_parse("haskell3.hs") - end - - def test_comment_entities - assert_equal('--comment', entities_array(" --comment", 'haskell', :comment).first) - assert_equal('{-comment-}', entities_array(" {-comment-}", 'haskell', :comment).first) - end -end diff --git a/test/unit/haxe_test.rb b/test/unit/haxe_test.rb deleted file mode 100644 index a2902e6..0000000 --- a/test/unit/haxe_test.rb +++ /dev/null @@ -1,17 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::HaxeTest < Ohcount::Test - def test_comments - lb = [Ohcount::LanguageBreakdown.new("haxe", "", "//comment", 0)] - assert_equal lb, Ohcount::parse(" //comment", "haxe") - end - - def test_comprehensive - verify_parse("haxe1.hx") - end - - def test_comment_entities - assert_equal('//comment', entities_array(' //comment', 'haxe', :comment).first) - assert_equal('/*comment*/', entities_array(' /*comment*/', 'haxe', :comment).first) - end -end diff --git a/test/unit/html_test.rb b/test/unit/html_test.rb deleted file mode 100644 index f6d007d..0000000 --- a/test/unit/html_test.rb +++ /dev/null @@ -1,14 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::HtmlTest < Ohcount::Test - def test_comprehensive - verify_parse("html1.html") - end - - def test_comment_entities - assert_equal('', entities_array(" ", 'html', :comment).first) - assert_equal('/*comment*/', entities_array("", 'html', :comment).first) - assert_equal('//comment', entities_array("", 'html', :comment).first) - assert_equal('/*comment*/', entities_array("", 'html', :comment).first) - end -end diff --git a/test/unit/java_test.rb b/test/unit/java_test.rb deleted file mode 100644 index 91ca3c8..0000000 --- a/test/unit/java_test.rb +++ /dev/null @@ -1,21 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::JavaTest < Ohcount::Test - def test_comments - lb = [Ohcount::LanguageBreakdown.new("java", "", "//comment", 0)] - assert_equal lb, Ohcount::parse(" //comment", "java") - end - - def test_comprehensive - verify_parse("java1.java") - end - - def test_comprehensive_with_carriage_returns - verify_parse("java2.java") - end - - def test_comment_entities - assert_equal('//comment', entities_array(" //comment", 'java', :comment).first) - assert_equal('/*comment*/', entities_array(" /*comment*/", 'java', :comment).first) - end -end diff --git a/test/unit/javascript_test.rb b/test/unit/javascript_test.rb deleted file mode 100644 index 52da443..0000000 --- a/test/unit/javascript_test.rb +++ /dev/null @@ -1,22 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::JavascriptTest < Ohcount::Test - def test_comments - lb = [Ohcount::LanguageBreakdown.new("javascript", "", "//comment", 0)] - assert_equal lb, Ohcount::parse(" //comment", "javascript") - end - - def test_comprehensive - verify_parse("js1.js") - end - - def test_comp2 - verify_parse("js2.js") - end - - def test_comment_entities - assert_equal('//comment', entities_array(" //comment", 'javascript', :comment).first) - assert_equal('/*comment*/', entities_array(" /*comment*/", 'javascript', :comment).first) - end - -end diff --git a/test/unit/jsp_test.rb b/test/unit/jsp_test.rb deleted file mode 100644 index d307c3f..0000000 --- a/test/unit/jsp_test.rb +++ /dev/null @@ -1,20 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::JspTest < Ohcount::Test - def test_comment - html_lb = Ohcount::LanguageBreakdown.new("html", "%>", "", 0) - java_lb = Ohcount::LanguageBreakdown.new("java", "", "<% //comment\n", 0) - assert_equal [java_lb, html_lb], Ohcount::parse(" <% //comment\n%>", "jsp") - end - - def test_comprehensive - verify_parse("jsp1.jsp") - end - - def test_comment_entities - assert_equal('', entities_array(" ", 'jsp', :comment).first) - assert_equal('/*comment*/', entities_array("", 'jsp', :comment).first) - assert_equal('//comment', entities_array("<%\n//comment\n%>", 'jsp', :comment).first) - assert_equal('/*comment*/', entities_array("<%\n/*comment*/\n%>", 'jsp', :comment).first) - end -end diff --git a/test/unit/license_sniffer_test.rb b/test/unit/license_sniffer_test.rb index 433dc50..d2c40e1 100644 --- a/test/unit/license_sniffer_test.rb +++ b/test/unit/license_sniffer_test.rb @@ -24,8 +24,9 @@ def test_expected_licenses next if File.directory?(filename) next if f[0..0] == "." - sfc = SimpleFileContext.new(filename) - detected_licenses = LicenseSniffer.parse(sfc.contents, Detector.detect(sfc)).sort { |a,b| a.to_s <=> b.to_s } + detected_licenses = Ohcount::SourceFile.new(filename).licenses + # sort them + detected_licenses = detected_licenses.sort { |a,b| a.to_s <=> b.to_s } # expected_licenses begin diff --git a/test/unit/lisp_test.rb b/test/unit/lisp_test.rb deleted file mode 100644 index 14c8db7..0000000 --- a/test/unit/lisp_test.rb +++ /dev/null @@ -1,38 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::LispTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("lisp", "", ";;; comment", 0)] - assert_equal lb, Ohcount::parse(" ;;; comment", "lisp") - end - - def test_doc_string - lb = [Ohcount::LanguageBreakdown.new("lisp", "", '""" comment """', 0)] - assert_equal lb, Ohcount::parse(' """ comment """', "lisp") - end - - def test_doc_string_blank - lb = [Ohcount::LanguageBreakdown.new("lisp", "", '""""""', 0)] - assert_equal lb, Ohcount::parse(' """"""', "lisp") - end - - def test_empty_string - lb = [Ohcount::LanguageBreakdown.new("lisp", '""', "", 0)] - assert_equal lb, Ohcount::parse(' ""', "lisp") - end - - def test_char_string - lb = [Ohcount::LanguageBreakdown.new("lisp", '"a"', "", 0)] - assert_equal lb, Ohcount::parse(' "a"', "lisp") - end - - def test_comprehensive - verify_parse("lsp1.lsp") - end - - def test_comment_entities - assert_equal(';comment', entities_array(" ;comment", 'lisp', :comment).first) - end - -end diff --git a/test/unit/lua_test.rb b/test/unit/lua_test.rb deleted file mode 100644 index cec949c..0000000 --- a/test/unit/lua_test.rb +++ /dev/null @@ -1,19 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::LuaTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("lua", "", "-- comment", 0)] - assert_equal lb, Ohcount::parse(" -- comment", "lua") - end - - def test_comprehensive - verify_parse("lua1.lua") - end - - def test_comment_entities - assert_equal('--comment', entities_array(" --comment", 'lua', :comment).first) - assert_equal("--[[comment\ncomment]]", entities_array(" --[[comment\ncomment]]", 'lua', :comment).first) - end - -end diff --git a/test/unit/make_test.rb b/test/unit/make_test.rb deleted file mode 100644 index 12461c2..0000000 --- a/test/unit/make_test.rb +++ /dev/null @@ -1,13 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::MakefileTest < Ohcount::Test - def test_comprehensive - verify_parse("Makefile") - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'make', :comment).first) - end - -end - diff --git a/test/unit/matlab_test.rb b/test/unit/matlab_test.rb deleted file mode 100644 index dd140da..0000000 --- a/test/unit/matlab_test.rb +++ /dev/null @@ -1,30 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::MatlabTest < Ohcount::Test - - def test_line_comment_1 - lb = [Ohcount::LanguageBreakdown.new("matlab", "", "%comment", 0)] - assert_equal lb, Ohcount::parse(" %comment", "matlab") - end - - def test_octave_syntax_comment - lb = [Ohcount::LanguageBreakdown.new("matlab", "", "#comment", 0)] - assert_equal lb, Ohcount::parse(" #comment", "matlab") - end - - def test_false_line_comment - lb = [Ohcount::LanguageBreakdown.new("matlab", "%{block%} code", "", 0)] - assert_equal lb, Ohcount::parse(" %{block%} code", "matlab") - end - - def test_comprehensive - verify_parse("matlab1.m", 'matlab') - end - - def test_comment_entities - assert_equal('%comment', entities_array(" %comment", 'matlab', :comment).first) - assert_equal('#comment', entities_array(" #comment", 'matlab', :comment).first) - assert_equal('%{comment%}', entities_array(" %{comment%}", 'matlab', :comment).first) - end - -end diff --git a/test/unit/metafont_test.rb b/test/unit/metafont_test.rb deleted file mode 100644 index 890f27c..0000000 --- a/test/unit/metafont_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::MetaFontTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("metafont", "", "% comment", 0)] - assert_equal lb, Ohcount::parse(" % comment", "metafont") - end - - def test_comprehensive - verify_parse("metafont.mf") - end - - def test_comment_entities - assert_equal('%comment', entities_array(" %comment", 'metafont', :comment).first) - end -end diff --git a/test/unit/metapost_test.rb b/test/unit/metapost_test.rb deleted file mode 100644 index 113141c..0000000 --- a/test/unit/metapost_test.rb +++ /dev/null @@ -1,17 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::MetaPostTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("metapost", "", "% comment", 0)] - assert_equal lb, Ohcount::parse(" % comment", "metapost") - end - - def test_comprehensive - verify_parse("metapost.mp") - end - - def test_comment_entities - assert_equal('%comment', entities_array(" %comment", 'metapost', :comment).first) - assert_equal('%comment', entities_array("verbatim\n%comment\netex", 'metapost', :comment).first) - end -end diff --git a/test/unit/mxml_test.rb b/test/unit/mxml_test.rb deleted file mode 100644 index da69ebc..0000000 --- a/test/unit/mxml_test.rb +++ /dev/null @@ -1,14 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::MxmlTest < Ohcount::Test - def test_comprehensive - verify_parse("mxml1.mxml") - end - - def test_comment_entities - assert_equal('', entities_array(" ", 'mxml', :comment).first) - assert_equal('/*comment*/', entities_array("\n/*comment*/\n", 'mxml', :comment).first) - assert_equal('//comment', entities_array("\n//comment\n", 'mxml', :comment).first) - assert_equal('/*comment*/', entities_array("\n/*comment*/\n", 'mxml', :comment).first) - end -end diff --git a/test/unit/ocaml_test.rb b/test/unit/ocaml_test.rb deleted file mode 100644 index 2035b97..0000000 --- a/test/unit/ocaml_test.rb +++ /dev/null @@ -1,17 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::OcamlTest < Ohcount::Test - def test_regular_comments - lb = [Ohcount::LanguageBreakdown.new("ocaml", "", "(* comment *)", 0)] - assert_equal lb, Ohcount::parse(" (* comment *)", "ocaml") - end - - def test_comprehensive - verify_parse("ocaml.ml") - end - - def test_comment_entities - assert_equal('(*comment*)', entities_array(" (*comment*)", 'ocaml', :comment).first) - end - -end diff --git a/test/unit/pascal_test.rb b/test/unit/pascal_test.rb deleted file mode 100644 index 1c0aa07..0000000 --- a/test/unit/pascal_test.rb +++ /dev/null @@ -1,19 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::PascalTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("pascal", "", "//comment", 0)] - assert_equal lb, Ohcount::parse(" //comment", "pascal") - end - - def test_comprehensive - verify_parse("pascal1.pas") - verify_parse("pascal2.pp") - end - - def test_comment_entities - assert_equal('//comment', entities_array(" //comment", 'pascal', :comment).first) - assert_equal('(*comment*)', entities_array(" (*comment*)", 'pascal', :comment).first) - assert_equal('{comment}', entities_array(" {comment}", 'pascal', :comment).first) - end -end diff --git a/test/unit/perl_test.rb b/test/unit/perl_test.rb deleted file mode 100644 index c70b8ff..0000000 --- a/test/unit/perl_test.rb +++ /dev/null @@ -1,23 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::PerlTest < Ohcount::Test - def test_comments - lb = [Ohcount::LanguageBreakdown.new("perl", "", "#comment", 0)] - assert_equal lb, Ohcount::parse(" #comment", "perl") - end - - def test_perl_in_cgi - verify_parse("perl.cgi") - end - - def test_comprehensive - verify_parse("perl1.pl") - verify_parse("perl_module.pm") - verify_parse("perl_pod_to_eof.pl") # Verifies ticket #267 - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'perl', :comment).first) - assert_equal("=head1\ncomment\n=cut", entities_array("=head1\ncomment\n=cut", 'perl', :comment).first) - end -end diff --git a/test/unit/php_test.rb b/test/unit/php_test.rb deleted file mode 100644 index 56a99e0..0000000 --- a/test/unit/php_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::PhpTest < Ohcount::Test - def test_comment - lbhtml = Ohcount::LanguageBreakdown.new("html", "", "", 0) - lbphp = Ohcount::LanguageBreakdown.new("php", "", "//comment\n", 0) - assert_equal [lbhtml, lbphp], Ohcount::parse("", "php") - end - - def test_comprehensive - verify_parse("php1.php") - end - - def test_comment_entities - assert_equal('// comment', entities_array("\n", 'php', :comment).first) - assert_equal('/* comment */', entities_array("\n", 'php', :comment).first) - end -end diff --git a/test/unit/pike_test.rb b/test/unit/pike_test.rb deleted file mode 100644 index 102e487..0000000 --- a/test/unit/pike_test.rb +++ /dev/null @@ -1,26 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::PikeTest < Ohcount::Test - def test_comments - lb = [Ohcount::LanguageBreakdown.new("pike", "", "//comment", 0)] - assert_equal lb, Ohcount::parse(" //comment", "pike") - end - - def test_comments2 - lb = [Ohcount::LanguageBreakdown.new("pike", "", "/*comment*/", 0)] - assert_equal lb, Ohcount::parse(" /*comment*/", "pike") - end - - def test_comprehensive - verify_parse("pike1.pike") - end - - def test_comprehensive_pmod - verify_parse("pike2.pmod") - end - - def test_comment_entities - assert_equal('//comment', entities_array(" //comment", 'pike', :comment).first) - assert_equal('/*comment*/', entities_array(" /*comment*/", 'pike', :comment).first) - end -end diff --git a/test/unit/python_test.rb b/test/unit/python_test.rb deleted file mode 100644 index b666348..0000000 --- a/test/unit/python_test.rb +++ /dev/null @@ -1,27 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::PythonTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("python", "", "#comment", 0)] - assert_equal lb, Ohcount::parse(" #comment", "python") - end - - def test_doc_comment - lb = [Ohcount::LanguageBreakdown.new("python", "", "'''\ndoc comment\n'''", 0)] - assert_equal lb, Ohcount::parse(" '''\n doc comment\n '''", "python") - end - - def test_strings - lb = [Ohcount::LanguageBreakdown.new("python", "\"abc#not a 'comment\"", "", 0)] - assert_equal lb, Ohcount::parse("\"abc#not a 'comment\"", "python") - end - - def test_comprehensive - verify_parse("py1.py") - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'python', :comment).first) - assert_equal('"""comment"""', entities_array(" \"\"\"comment\"\"\"", 'python', :comment).first) - end -end diff --git a/test/unit/r_test.rb b/test/unit/r_test.rb deleted file mode 100644 index e93df7d..0000000 --- a/test/unit/r_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::RTest < Ohcount::Test - - def test_line_comment_1 - lb = [Ohcount::LanguageBreakdown.new("r", "", "#comment", 0)] - assert_equal lb, Ohcount::parse(" #comment", "r") - end - - def test_comprehensive - verify_parse("example.R", 'r') - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'r', :comment).first) - end - -end diff --git a/test/unit/rexx_test.rb b/test/unit/rexx_test.rb deleted file mode 100644 index 82b1287..0000000 --- a/test/unit/rexx_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::RexxTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("rexx", "", "/*comment*/", 0)] - assert_equal lb, Ohcount::parse(" /*comment*/", "rexx") - end - - def test_comprehensive - verify_parse("rexx1.rex") - end - - def test_comment_entities - assert_equal('/*comment*/', entities_array(" /*comment*/", 'rexx', :comment).first) - end - -end diff --git a/test/unit/rhtml_test.rb b/test/unit/rhtml_test.rb deleted file mode 100644 index 117c351..0000000 --- a/test/unit/rhtml_test.rb +++ /dev/null @@ -1,24 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::RhtmlTest < Ohcount::Test - - def test_comment - html_lb = Ohcount::LanguageBreakdown.new("html", "<%\n%>", "", 0) - ruby_lb = Ohcount::LanguageBreakdown.new("ruby", "", "#comment\n", 0) - assert_equal [html_lb, ruby_lb], Ohcount::parse("<%\n #comment\n%>", "rhtml") - end - - def test_comprehensive - verify_parse("rhtml1.rhtml") - end - - def test_comment_entities - assert_equal('', entities_array(" ", 'rhtml', :comment).first) - assert_equal('/*comment*/', entities_array("", 'rhtml', :comment).first) - assert_equal('//comment', entities_array("", 'rhtml', :comment).first) - assert_equal('/*comment*/', entities_array("", 'rhtml', :comment).first) - assert_equal('#comment', entities_array("<%\n#comment\n%>", 'rhtml', :comment).first) - assert_equal("=begin\ncomment\n=end", entities_array("<%\n=begin\ncomment\n=end\n%>", 'rhtml', :comment).first) - end - -end diff --git a/test/unit/ruby_test.rb b/test/unit/ruby_test.rb deleted file mode 100644 index 805d052..0000000 --- a/test/unit/ruby_test.rb +++ /dev/null @@ -1,19 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::RubyTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("ruby", "", "#comment", 0)] - assert_equal lb, Ohcount::parse(" #comment", "ruby") - end - - def test_comprehensive - verify_parse("ruby1.rb") - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'ruby', :comment).first) - assert_equal("=begin\ncomment\n=end", entities_array("=begin\ncomment\n=end", 'ruby', :comment).first) - end - -end diff --git a/test/unit/scala_test.rb b/test/unit/scala_test.rb deleted file mode 100644 index 8d8c6c1..0000000 --- a/test/unit/scala_test.rb +++ /dev/null @@ -1,14 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::ScalaTest < Ohcount::Test - - def test_comprehensive - verify_parse("scala1.scala") - end - - def test_comment_entities - assert_equal('//comment', entities_array(" //comment", 'scala', :comment).first) - assert_equal('/*comment*/', entities_array(" /*comment*/", 'scala', :comment).first) - end - -end diff --git a/test/unit/scheme_test.rb b/test/unit/scheme_test.rb deleted file mode 100644 index 37b4847..0000000 --- a/test/unit/scheme_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::SchemeTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("scheme", "", ";;; comment", 0)] - assert_equal lb, Ohcount::parse(" ;;; comment", "scheme") - end - - def test_comprehensive - verify_parse("scheme.scm") - end - - def test_comment_entities - assert_equal(';comment', entities_array(" ;comment", 'scheme', :comment).first) - end - -end diff --git a/test/unit/shell_test.rb b/test/unit/shell_test.rb deleted file mode 100644 index ac82410..0000000 --- a/test/unit/shell_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::ShellTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("shell", "", "#comment", 0)] - assert_equal lb, Ohcount::parse(" #comment", "shell") - end - - def test_comprehensive - verify_parse("sh1.sh") - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'shell', :comment).first) - end -end diff --git a/test/unit/smalltalk_test.rb b/test/unit/smalltalk_test.rb deleted file mode 100644 index 18505b1..0000000 --- a/test/unit/smalltalk_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::SmalltalkTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("smalltalk", "", '"comment\\"', 0)] - assert_equal lb, Ohcount::parse(' "comment\\"', "smalltalk") - end - - def test_comprehensive - verify_parse("smalltalk1.st") - end - - def test_comment_entities - assert_equal('"comment"', entities_array(" \"comment\"", 'smalltalk', :comment).first) - end - -end diff --git a/test/unit/sql_test.rb b/test/unit/sql_test.rb deleted file mode 100644 index 353c6ec..0000000 --- a/test/unit/sql_test.rb +++ /dev/null @@ -1,32 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::SqlTest < Ohcount::Test - - def test_comments - lb = [Ohcount::LanguageBreakdown.new("sql", "", "--comment", 0)] - assert_equal lb, Ohcount::parse(" --comment", "sql") - end - - def test_empty_comments - lb = [Ohcount::LanguageBreakdown.new("sql", "","--\n", 0)] - assert_equal lb, Ohcount::parse(" --\n", "sql") - end - - def test_block_comment - lb = [Ohcount::LanguageBreakdown.new("sql", "","{sql}", 0)] - assert_equal lb, Ohcount::parse(" {sql}", "sql") - end - - def test_comprehensive - verify_parse("sql1.sql") - end - - def test_comment_entities - assert_equal('--comment', entities_array(" --comment", 'sql', :comment).first) - assert_equal('#comment', entities_array(" #comment", 'sql', :comment).first) - assert_equal('//comment', entities_array(" //comment", 'sql', :comment).first) - assert_equal('/*comment*/', entities_array(" /*comment*/", 'sql', :comment).first) - assert_equal('{comment}', entities_array(" {comment}", 'sql', :comment).first) - end - -end diff --git a/test/unit/stratego_test.rb b/test/unit/stratego_test.rb deleted file mode 100644 index 011b4bb..0000000 --- a/test/unit/stratego_test.rb +++ /dev/null @@ -1,22 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::StrategoTest < Ohcount::Test - def test_line_comments - lb = [Ohcount::LanguageBreakdown.new("stratego", "", "// comment", 0)] - assert_equal lb, Ohcount::parse("// comment", "stratego") - end - - def test_comprehensive - verify_parse("stratego.str") - end - - def test_char_string_entities - assert_equal("'c'", entities_array(" 'c'", 'stratego', :string).first) - # single quote can be used in identiiers - # weak case - assert_not_equal(" c'", entities_array(" c'", 'stratego', :string).first) - # strong case - assert_not_equal("' = e'", entities_array(" c' = e'", 'stratego', :string).first) - end - -end diff --git a/test/unit/tcl_test.rb b/test/unit/tcl_test.rb deleted file mode 100644 index 0ce5b6f..0000000 --- a/test/unit/tcl_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::TclTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("tcl", "", "#comment", 0)] - assert_equal lb, Ohcount::parse(" #comment", "tcl") - end - - def test_comprehensive - verify_parse("tcl1.tcl") - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'tcl', :comment).first) - end -end diff --git a/test/unit/tex_test.rb b/test/unit/tex_test.rb deleted file mode 100644 index ff9cda5..0000000 --- a/test/unit/tex_test.rb +++ /dev/null @@ -1,17 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::TeXTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("tex", "", "%comment", 0)] - assert_equal lb, Ohcount::parse(" %comment", "tex") - end - - def test_comprehensive - verify_parse("foo.tex") - end - - def test_comment_entities - assert_equal('%comment', entities_array(" %comment", 'tex', :comment).first) - end -end diff --git a/test/unit/vala_test.rb b/test/unit/vala_test.rb deleted file mode 100644 index 8acc50f..0000000 --- a/test/unit/vala_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::ValaTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("vala", "", "//comment", 0)] - assert_equal lb, Ohcount::parse(" //comment", "vala") - end - - def test_comprehensive - verify_parse("vala1.vala") - end - - def test_comment_entities - assert_equal('//comment', entities_array(" //comment", 'vala', :comment).first) - assert_equal('/*comment*/', entities_array(" /*comment*/", 'vala', :comment).first) - end -end diff --git a/test/unit/vhdl_test.rb b/test/unit/vhdl_test.rb deleted file mode 100644 index ad0cd93..0000000 --- a/test/unit/vhdl_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::VHDLTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("vhdl", "", "-- comment", 0)] - assert_equal lb, Ohcount::parse(" -- comment", "vhdl") - end - - def test_comprehensive - verify_parse("vhdl1.vhd") - end - - def test_comment_entities - assert_equal('--comment', entities_array(" --comment", 'vhdl', :comment).first) - end -end diff --git a/test/unit/vim_test.rb b/test/unit/vim_test.rb deleted file mode 100644 index 265aaeb..0000000 --- a/test/unit/vim_test.rb +++ /dev/null @@ -1,7 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::VimTest < Ohcount::Test - def test_comprehensive - verify_parse("foo.vim") - end -end diff --git a/test/unit/visual_basic_test.rb b/test/unit/visual_basic_test.rb deleted file mode 100644 index daf90eb..0000000 --- a/test/unit/visual_basic_test.rb +++ /dev/null @@ -1,17 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::VisualBasicTest < Ohcount::Test - def test_comments - lb = [Ohcount::LanguageBreakdown.new("visualbasic", "", "'comment", 0)] - assert_equal lb, Ohcount::parse(" 'comment", "visualbasic") - end - - def test_comprehensive - verify_parse("frx1.frx") - end - - def test_comment_entities - assert_equal('\'comment', entities_array(" 'comment", 'visualbasic', :comment).first) - assert_equal('Rem comment', entities_array(" Rem comment", 'visualbasic', :comment).first) - end -end diff --git a/test/unit/xml_test.rb b/test/unit/xml_test.rb deleted file mode 100644 index 6153b90..0000000 --- a/test/unit/xml_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::XmlTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("xml", "", "", 0)] - assert_equal lb, Ohcount::parse(" ", "xml") - end - - def test_comprehensive - verify_parse("xml1.xml") - end - - def test_comment_entities - assert_equal('', entities_array(" ", 'xml', :comment).first) - end -end diff --git a/test/unit/xmlschema_test.rb b/test/unit/xmlschema_test.rb deleted file mode 100644 index 04ad0b0..0000000 --- a/test/unit/xmlschema_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::XMLSchemaTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("xmlschema", "", "", 0)] - assert_equal lb, Ohcount::parse(" ", "xmlschema") - end - - def test_comprehensive - verify_parse("schema.xsd") - end - - def test_comment_entities - assert_equal('', entities_array(" ", 'xmlschema', :comment).first) - end -end diff --git a/test/unit/xslt_test.rb b/test/unit/xslt_test.rb deleted file mode 100644 index 2eed042..0000000 --- a/test/unit/xslt_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class Ohcount::XsltTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("xslt", "", "", 0)] - assert_equal lb, Ohcount::parse(" ", "xslt") - end - - def test_comprehensive - verify_parse("example.xsl") - end - - def test_comment_entities - assert_equal('', entities_array(" ", 'xslt', :comment).first) - end -end From 10576f36e0076f4b33c45f63b9ef93fec24ba2f5 Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Fri, 31 Oct 2008 06:44:08 -0700 Subject: [PATCH 017/387] [NEW] Ohcount cleanup & reorganizing: introducing SourceFile: the ohcount orienting concept. [NEW] Gestalt functionality: can specify rules for how platforms can be determined --- .gitignore | 1 + Rakefile | 2 +- bin/ohcount | 18 +- lib/detector/base.rb | 578 ++++++++++++++++++++++++ lib/gestalt/base.rb | 70 +++ lib/gestalt/library.rb | 73 +++ lib/gestalt/library_rule.rb | 66 +++ lib/gestalt/platform.rb | 113 +++++ lib/ohcount/source_file.rb | 125 +++++ rules/libraries.rb | 16 + rules/platforms.rb | 20 + rules/tools.rb | 8 + test/gestalt_files/test_linux_1/configure.in | 1 + test/gestalt_files/test_linux_1/foo.c | 102 +++++ test/gestalt_files/test_linux_1/foo.rb | 4 + test/gestalt_files/test_ruby_just_enough/foo.c | 75 +++ test/gestalt_files/test_ruby_just_enough/foo.rb | 15 + test/gestalt_files/test_ruby_not_enough/foo.c | 87 ++++ test/gestalt_files/test_ruby_not_enough/foo.rb | 15 + test/gestalt_files/test_win32_enough/bar.c | 3 + test/gestalt_files/test_win32_enough/foo.c | 3 + test/gestalt_files/test_win32_not_enough/foo.c | 3 + test/test_helper.rb | 4 +- test/unit/gestalt/library_rule_test.rb | 32 ++ test/unit/gestalt/library_test.rb | 47 ++ test/unit/gestalt/platform_test.rb | 46 ++ test/unit/parsers/actionscript_test.rb | 17 + test/unit/parsers/ada_test.rb | 20 + test/unit/parsers/assembler_test.rb | 21 + test/unit/parsers/autoconf_test.rb | 12 + test/unit/parsers/automake_test.rb | 12 + test/unit/parsers/awk_test.rb | 22 + test/unit/parsers/basic_test.rb | 26 ++ test/unit/parsers/bat_test.rb | 16 + test/unit/parsers/boo_test.rb | 37 ++ test/unit/parsers/c_test.rb | 35 ++ test/unit/parsers/clearsilver_template_test.rb | 20 + test/unit/parsers/clearsilver_test.rb | 14 + test/unit/parsers/csharp_test.rb | 19 + test/unit/parsers/css_test.rb | 16 + test/unit/parsers/d_test.rb | 43 ++ test/unit/parsers/dcl_test.rb | 32 ++ test/unit/parsers/dylan_test.rb | 18 + test/unit/parsers/ebuild_test.rb | 11 + test/unit/parsers/eiffel_test.rb | 17 + test/unit/parsers/emacs_lisp.rb | 20 + test/unit/parsers/erlang_test.rb | 18 + test/unit/parsers/exheres_test.rb | 12 + test/unit/parsers/factor_test.rb | 18 + test/unit/parsers/fortran_test.rb | 15 + test/unit/parsers/groovy_test.rb | 18 + test/unit/parsers/haml_test.rb | 23 + test/unit/parsers/haskell_test.rb | 25 + test/unit/parsers/haxe_test.rb | 17 + test/unit/parsers/html_test.rb | 14 + test/unit/parsers/java_test.rb | 21 + test/unit/parsers/javascript_test.rb | 22 + test/unit/parsers/jsp_test.rb | 20 + test/unit/parsers/lisp_test.rb | 38 ++ test/unit/parsers/lua_test.rb | 19 + test/unit/parsers/make_test.rb | 13 + test/unit/parsers/matlab_test.rb | 30 ++ test/unit/parsers/metafont_test.rb | 16 + test/unit/parsers/metapost_test.rb | 17 + test/unit/parsers/mxml_test.rb | 14 + test/unit/parsers/ocaml_test.rb | 17 + test/unit/parsers/pascal_test.rb | 19 + test/unit/parsers/perl_test.rb | 23 + test/unit/parsers/php_test.rb | 18 + test/unit/parsers/pike_test.rb | 26 ++ test/unit/parsers/python_test.rb | 27 ++ test/unit/parsers/r_test.rb | 18 + test/unit/parsers/rexx_test.rb | 18 + test/unit/parsers/rhtml_test.rb | 24 + test/unit/parsers/ruby_test.rb | 19 + test/unit/parsers/scala_test.rb | 14 + test/unit/parsers/scheme_test.rb | 18 + test/unit/parsers/shell_test.rb | 16 + test/unit/parsers/smalltalk_test.rb | 18 + test/unit/parsers/sql_test.rb | 32 ++ test/unit/parsers/stratego_test.rb | 22 + test/unit/parsers/tcl_test.rb | 16 + test/unit/parsers/tex_test.rb | 17 + test/unit/parsers/vala_test.rb | 18 + test/unit/parsers/vhdl_test.rb | 16 + test/unit/parsers/vim_test.rb | 7 + test/unit/parsers/visual_basic_test.rb | 17 + test/unit/parsers/xml_test.rb | 16 + test/unit/parsers/xmlschema_test.rb | 16 + test/unit/parsers/xslt_test.rb | 16 + test/unit/source_file_test.rb | 34 ++ 91 files changed, 2824 insertions(+), 3 deletions(-) create mode 100644 lib/detector/base.rb create mode 100644 lib/gestalt/base.rb create mode 100644 lib/gestalt/library.rb create mode 100644 lib/gestalt/library_rule.rb create mode 100644 lib/gestalt/platform.rb create mode 100644 lib/ohcount/source_file.rb create mode 100644 rules/libraries.rb create mode 100644 rules/platforms.rb create mode 100644 rules/tools.rb create mode 100644 test/gestalt_files/test_linux_1/configure.in create mode 100644 test/gestalt_files/test_linux_1/foo.c create mode 100644 test/gestalt_files/test_linux_1/foo.rb create mode 100644 test/gestalt_files/test_ruby_just_enough/foo.c create mode 100644 test/gestalt_files/test_ruby_just_enough/foo.rb create mode 100644 test/gestalt_files/test_ruby_not_enough/foo.c create mode 100644 test/gestalt_files/test_ruby_not_enough/foo.rb create mode 100644 test/gestalt_files/test_win32_enough/bar.c create mode 100644 test/gestalt_files/test_win32_enough/foo.c create mode 100644 test/gestalt_files/test_win32_not_enough/foo.c create mode 100644 test/unit/gestalt/library_rule_test.rb create mode 100644 test/unit/gestalt/library_test.rb create mode 100644 test/unit/gestalt/platform_test.rb create mode 100644 test/unit/parsers/actionscript_test.rb create mode 100644 test/unit/parsers/ada_test.rb create mode 100644 test/unit/parsers/assembler_test.rb create mode 100644 test/unit/parsers/autoconf_test.rb create mode 100644 test/unit/parsers/automake_test.rb create mode 100644 test/unit/parsers/awk_test.rb create mode 100644 test/unit/parsers/basic_test.rb create mode 100644 test/unit/parsers/bat_test.rb create mode 100644 test/unit/parsers/boo_test.rb create mode 100644 test/unit/parsers/c_test.rb create mode 100644 test/unit/parsers/clearsilver_template_test.rb create mode 100644 test/unit/parsers/clearsilver_test.rb create mode 100644 test/unit/parsers/csharp_test.rb create mode 100644 test/unit/parsers/css_test.rb create mode 100644 test/unit/parsers/d_test.rb create mode 100644 test/unit/parsers/dcl_test.rb create mode 100644 test/unit/parsers/dylan_test.rb create mode 100644 test/unit/parsers/ebuild_test.rb create mode 100644 test/unit/parsers/eiffel_test.rb create mode 100644 test/unit/parsers/emacs_lisp.rb create mode 100644 test/unit/parsers/erlang_test.rb create mode 100644 test/unit/parsers/exheres_test.rb create mode 100644 test/unit/parsers/factor_test.rb create mode 100644 test/unit/parsers/fortran_test.rb create mode 100644 test/unit/parsers/groovy_test.rb create mode 100644 test/unit/parsers/haml_test.rb create mode 100644 test/unit/parsers/haskell_test.rb create mode 100644 test/unit/parsers/haxe_test.rb create mode 100644 test/unit/parsers/html_test.rb create mode 100644 test/unit/parsers/java_test.rb create mode 100644 test/unit/parsers/javascript_test.rb create mode 100644 test/unit/parsers/jsp_test.rb create mode 100644 test/unit/parsers/lisp_test.rb create mode 100644 test/unit/parsers/lua_test.rb create mode 100644 test/unit/parsers/make_test.rb create mode 100644 test/unit/parsers/matlab_test.rb create mode 100644 test/unit/parsers/metafont_test.rb create mode 100644 test/unit/parsers/metapost_test.rb create mode 100644 test/unit/parsers/mxml_test.rb create mode 100644 test/unit/parsers/ocaml_test.rb create mode 100644 test/unit/parsers/pascal_test.rb create mode 100644 test/unit/parsers/perl_test.rb create mode 100644 test/unit/parsers/php_test.rb create mode 100644 test/unit/parsers/pike_test.rb create mode 100644 test/unit/parsers/python_test.rb create mode 100644 test/unit/parsers/r_test.rb create mode 100644 test/unit/parsers/rexx_test.rb create mode 100644 test/unit/parsers/rhtml_test.rb create mode 100644 test/unit/parsers/ruby_test.rb create mode 100644 test/unit/parsers/scala_test.rb create mode 100644 test/unit/parsers/scheme_test.rb create mode 100644 test/unit/parsers/shell_test.rb create mode 100644 test/unit/parsers/smalltalk_test.rb create mode 100644 test/unit/parsers/sql_test.rb create mode 100644 test/unit/parsers/stratego_test.rb create mode 100644 test/unit/parsers/tcl_test.rb create mode 100644 test/unit/parsers/tex_test.rb create mode 100644 test/unit/parsers/vala_test.rb create mode 100644 test/unit/parsers/vhdl_test.rb create mode 100644 test/unit/parsers/vim_test.rb create mode 100644 test/unit/parsers/visual_basic_test.rb create mode 100644 test/unit/parsers/xml_test.rb create mode 100644 test/unit/parsers/xmlschema_test.rb create mode 100644 test/unit/parsers/xslt_test.rb create mode 100644 test/unit/source_file_test.rb diff --git a/.gitignore b/.gitignore index 71a0ace..dbfa000 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ lib/i[3-9]86* lib/x86* *.swp tags +.DS_Store diff --git a/Rakefile b/Rakefile index 410d4af..3d20472 100644 --- a/Rakefile +++ b/Rakefile @@ -100,7 +100,7 @@ end Rake::TestTask.new :ohcount_unit_tests => ARCH_DL do |t| # puts File.dirname(__FILE__) + '/test/unit/*_test.rb' - t.test_files = FileList[File.dirname(__FILE__) + '/test/unit/*_test.rb'] + t.test_files = FileList[File.dirname(__FILE__) + '/test/unit/**/*_test.rb'] # t.verbose = true end diff --git a/bin/ohcount b/bin/ohcount index 33ca508..847d8bd 100755 --- a/bin/ohcount +++ b/bin/ohcount @@ -76,6 +76,15 @@ class OhcountCommandLine end end + # Gestalt + def gestalt + g = Ohcount::Gestalt::Base.new(:files => files) + puts "processing #{files.size} files... (this could take a while)" + g.process! + platforms = g.platforms.any? ? g.platforms.collect { |p| p.to_s }.join(", ") : 'None' + puts "Platforms detected: #{ platforms }" + end + def raw_entities files.each do |file| Ohcount::SourceFile.new(file, :filenames => files).raw_entities do |language, entity, s, e| @@ -113,6 +122,11 @@ Ohloh source code line counter command line tool. -h, --help Display this message +-g, --gestalt Project Properties + + Inspects project contents to determine what platform(s) the project + runs on, as well as any detected tools/IDEs used to develop it. + -i, --individual Count lines of code per file Count lines in all source code files within the given paths, and @@ -271,6 +285,8 @@ HELP self.subcommand = :detect when '-a', '--annotate' self.subcommand = :annotate + when '-g', '--gestalt' + self.subcommand = :gestalt when '-i', '--individual' self.subcommand = :individual when '-l', '--licenses' @@ -294,7 +310,7 @@ HELP end def run! - self.subcommand ||= :summary + self.subcommand ||= :gestalt if self.respond_to?(self.subcommand) self.send(self.subcommand) else diff --git a/lib/detector/base.rb b/lib/detector/base.rb new file mode 100644 index 0000000..2b7614e --- /dev/null +++ b/lib/detector/base.rb @@ -0,0 +1,578 @@ +# The Detector determines which Monoglot or Polyglot should be +# used to parse a source file. +# +# The Detector primarily uses filename extensions to identify languages. +# +# The hash EXTENSION_MAP maps a filename extension to the name of a parser. +# +# If a filename extension is not enough to determine the correct parser (for +# instance, the *.m extension can indicate either a Matlab or Objective-C file), +# then the EXTENSION_MAP hash will contain a symbol identifying a Ruby method +# which will be invoked. This Ruby method can examine the file +# contents and return the name of the correct parser. +# +# Many source files do not have an extension. The method +disambiguate_nil+ +# is called in these cases. The +file+ command line tool is used to determine +# the type of file and select a parser. +# +# The Detector is covered by DetectorTest. +# +module Ohcount + module Detector + class Base + + # A performance hack -- once we've checked for the presence of *.m files, the result + # is stored here to avoid checking twice. + module ContainsM + attr_accessor :contains_m + # A performance hack -- once we've checked for the presence of *.pike and *.pmod files, the result + # is stored here to avoid checking twice. + attr_accessor :contains_pike_or_pmod + end + + # A performance hack -- once we've checked for the presence of *.frx, *.frm and *.vbp files, the result + # is stored here to avoid checking twice. + module ContainsVB + attr_accessor :contains_vb + end + + # The primary entry point for the detector. + # Given a file context containing the file name, content, and an array of + # other filenames in the source tree, attempts to detect which + # language family (Monoglot or Polyglot) is in use for this file. + # + # Returns nil if the language is not recognized or if the file does not + # contain any code. + # + # Example: + # + # # List all C files in the 'src' directory + # Dir.entries("src").each do |file| + # context = Ohcount::SimpleFileContext.new(file) + # polyglot = Ohcount::Detector.detect(context) + # puts "#{file}" if polyglot == 'c' + # end + # + def self.detect(source_file) + # start with filename and extension + polyglot = [ + lambda { | f | FILENAME_MAP[File.basename(source_file.filename)] }, + lambda { | f | EXTENSION_MAP[File.extname(source_file.filename)] }, + lambda { | f | EXTENSION_MAP[File.extname(source_file.filename).downcase] } + ].inject(nil) { | a, f | a and break a or f.call(source_file) } + case polyglot + when String + # simplest case + return polyglot if polyglot.is_a?(String) + when Symbol + # extension is ambiguous - requires custom disambiguation + self.send(polyglot, source_file) + when NilClass + return disambiguate_nil(source_file) + else + raise RuntimeError.new("Unknown file detection type") + end + end + + # Based solely on the filename, makes a judgment whether a file is a binary format. + def self.binary_filename?(filename) + ignore = [ + ".svn", + ".jar", + ".tar", + ".gz", + ".tgz", + ".zip", + ".gif", + ".jpg", + ".jpeg", + ".bmp", + ".png", + ".tif", + ".tiff", + ".ogg", + ".aiff", + ".wav", + ".mp3", + ".au", + ".ra", + ".m4a", + ".pdf", + ".mpg", + ".mov", + ".qt", + ".avi", + ".swf" + ] + ignore.include?(File.extname(filename)) + end + + # If an extension maps to a string, that string must be the name of a glot. + # If an extension maps to a Ruby symbol, that symbol must be the name of a + # Ruby method which will return the name of a glot. + EXTENSION_MAP = { + '.ada' => "ada", + '.adb' => "ada", + '.ads' => "ada", + '.as' => "actionscript", + '.asm' => "assembler", + '.awk' => "awk", + '.b' => :disambiguate_non_visual_basic, + '.bas' => :disambiguate_basic, + '.bat' => "bat", + '.bi' => :disambiguate_non_visual_basic, + '.boo' => "boo", + '.c' => "c", + '.C' => "cpp", + '.cc' => "cpp", + '.cpp' => "cpp", + '.css' => "css", + '.c++' => "cpp", + '.cxx' => "cpp", + '.com' => "dcl", + '.el' => "emacslisp", + '.cs' => :disambiguate_cs, + '.dylan' => "dylan", + '.e' => "eiffel", + '.ebuild' => "ebuild", + '.eclass' => "ebuild", + '.kdebuild-1' => "ebuild", + '.erl' => "erlang", + '.exheres-0' => "exheres", + '.exlib' => "exheres", + '.f' => :disambiguate_fortran, + '.factor' => "factor", + '.ftn' => :disambiguate_fortran, + '.f77' => :disambiguate_fortran, + '.f90' => :disambiguate_fortran, + '.f95' => :disambiguate_fortran, + '.f03' => :disambiguate_fortran, + '.frx' => "visualbasic", + '.groovy' => "groovy", + '.h' => :disambiguate_h_header, + '.haml' => 'haml', + '.H' => "cpp", + '.hpp' => "cpp", + '.h++' => "cpp", + '.hs' => "haskell", + '.hx' => "haxe", + '.hxx' => "cpp", + '.hh' => "cpp", + '.hrl' => "erlang", + '.htm' => "html", + '.html' => "html", + '.in' => :disambiguate_in, + '.inc' => :disambiguate_inc, + '.java' => "java", + '.js' => "javascript", + '.jsp' => "jsp", + '.lua' => "lua", + '.lsp' => "lisp", + '.lisp' => "lisp", + '.m' => :matlab_or_objective_c, + '.mf' => 'metafont', + '.mk' => 'make', + '.ml' => "ocaml", + '.mli' => "ocaml", + '.mm' => "objective_c", + '.mp' => 'metapost_with_tex', + '.mxml' => 'mxml', + '.nse' => 'lua', + '.pas' => "pascal", + '.pp' => "pascal", + '.php' => "php", + '.php3' => "php", + '.php4' => "php", + '.php5' => "php", + '.p6' => "perl", + '.pl' => "perl", + '.pm' => "perl", + '.perl' => "perl", + '.ph' => "perl", + '.pod' => "perl", + '.t' => "perl", + '.pike' => "pike", + '.pmc' => "c", + '.pmod' => "pike", + '.py' => "python", + '.r' => "r", + '.rhtml' => "rhtml", + '.rb' => "ruby", + '.rex' => "rexx", + '.rexx' => "rexx", + '.s' => "assembler", + '.sc' => "scheme", + '.scala' => "scala", + '.scm' => "scheme", + '.sh' => "shell", + '.sql' => "sql", + '.st' => "smalltalk", + '.str' => "stratego", + '.tcl' => "tcl", + '.tpl' => "html", + '.vala' => "vala", + '.vb' => "visualbasic", + '.vba' => "visualbasic", + '.vbs' => "visualbasic", + '.vhd' => "vhdl", + '.vhdl' => "vhdl", + '.vim' => "vim", + '.xml' => "xml", + '.xs' => "c", + '.xsd' => "xmlschema", + '.xsl' => "xslt", + '.d' => 'dmd', + '.di' => 'dmd', + '.tex' => 'tex', + '.ltx' => 'tex', + '.latex' => 'tex' + } + + # Map full filenames to glots. The right hand side is a string or symbol as + # for EXTENSION_MAP. + FILENAME_MAP = { + 'Makefile' => 'make', + 'GNUmakefile' => 'make', + 'makefile' => 'make', + 'Makefile.am' => 'automake', + 'configure.in' => 'autoconf', + 'configure.ac' => 'autoconf', + 'configure' => 'autoconf' + } + + protected + + # Returns a count of lines in the buffer matching the given regular expression. + def self.lines_matching(buffer, re) + buffer.inject(0) { |total, line| line =~ re ? total+1 : total } + end + + # For *.m files, differentiates Matlab from Objective-C. + # + # This is done with a weighted heuristic that + # scans the *.m file contents for keywords, + # and also checks for the presence of matching *.h files. + def self.matlab_or_objective_c(file_context) + buffer = file_context.contents + + # if there are .h files in same directory, this probably isn't matlab + h_headers = 0.0 + h_headers = -0.5 if file_context.filenames.select { |a| a =~ /\.h$/ }.any? + + # if the contents contain 'function (' on a single line - very likely to be matlab + # if the contents contain lines starting with '%', its probably matlab comments + matlab_signatures = /(^\s*function\s*)|(^\s*%)/ + matlab_sig_score = 0.1 * lines_matching(buffer, matlab_signatures) + + # if the contents contains '//' or '/*', likely objective_c + objective_c_signatures = /(^\s*\/\/\s*)|(^\s*\/\*)|(^[+-])/ + obj_c_sig_score = -0.1 * lines_matching(buffer, objective_c_signatures) + + matlab = h_headers + matlab_sig_score + obj_c_sig_score + + matlab > 0 ? 'matlab' : 'objective_c' + end + + # For *.h files, differentiates C, C++ and Objective-C. + # + # This is done with a weighted heuristic that + # scans the *.h file contents for Objective-C keywords, + # C++ keywords and C++ headers, and also checks for the + # presence of matching *.m files. + def self.disambiguate_h_header(file_context) + buffer = file_context.contents + + # could it be realistically be objective_c ? are there any .m files at all? + # Speed hack - remember our findings in case we get the same filenames over and over + unless defined?(file_context.filenames.contains_m) + file_context.filenames.extend(ContainsM) + file_context.filenames.contains_m = file_context.filenames.select { |a| a =~ /\.m$/ }.any? + file_context.filenames.contains_pike_or_pmod = file_context.filenames.select { |a| a =~ /\.p(ike|mod)$/ }.any? + end + + if file_context.filenames.contains_m + # if the dir contains a matching *.m file, likely objective_c + if file_context.filename =~ /\.h$/ + m_counterpart = file_context.filename.gsub(/\.h$/, ".m") + return 'objective_c' if file_context.filenames.include?(m_counterpart) + end + + # ok - it just might be objective_c, let's check contents for objective_c signatures + objective_c_signatures = /(^\s*@interface)|(^\s*@end)/ + objective_c = lines_matching(buffer, objective_c_signatures) + return 'objective_c' if objective_c > 1 + end + + if file_context.filenames.contains_pike_or_pmod + # The string "pike" and a selection of common Pike keywords. + pike_signatures = /([Pp][Ii][Kk][Ee])|(string )|(mapping)|(multiset)|(import )|(inherit )|(predef)/ + pike = lines_matching(buffer, pike_signatures) + return 'pike' if pike > 0 + end + + disambiguate_c_cpp(buffer) + end + + # A map of headers that indicate C++, but that do not have C++-specific file + # extensions. This list is made from the Standard, plus Technical Report 1. + CPP_HEADERS_MAP = %w[ + algorithm + array + bitset + cassert + ccomplex + cctype + cerrno + cfenv + cfloat + cinttypes + ciso646 + climits + clocale + cmath + csetjmp + csignal + cstdarg + cstdbool + cstddef + cstdint + cstdio + cstdlib + cstring + ctgmath + ctime + cwchar + cwctype + deque + exception + fstream + functional + iomanip + ios + iosfwd + iostream + istream + iterator + limits + list + locale + map + memory + new + numeric + ostream + queue + random + regex + set + sstream + stack + stdexcept + streambuf + string + system_error + tuple + type_traits + typeinfo + unordered_map + unordered_set + utility + valarray + vector + tr1/array + tr1/ccomplex + tr1/cctype + tr1/cfenv + tr1/cfloat + tr1/cinttypes + tr1/climits + tr1/cmath + tr1/complex + tr1/cstdarg + tr1/cstdbool + tr1/cstdint + tr1/cstdio + tr1/cstdlib + tr1/ctgmath + tr1/ctime + tr1/cwchar + tr1/cwctype + tr1/memory + tr1/random + tr1/regex + tr1/tuple + tr1/type_traits + tr1/unordered_map + tr1/unordered_set + tr1/utility + ].inject({}) { | h, k | h[k] = true ; h } + + # A map of keywords that indicate C++. + CPP_KEYWORDS_MAP = %w[ + template + typename + class + namespace + ].inject({}) { | h, k | h[k] = true ; h } + + # For *.h files that we know aren't Objective-C, differentiates C and C++. + # + # This is done with a weighted heuristic that + # scans the *.h file contents for C++ keywords and C++ headers. + def self.disambiguate_c_cpp(buffer) + # Look for C++ headers + return 'cpp' if extract_c_cpp_headers(buffer).detect do | header | + EXTENSION_MAP[File.extname(header)] == 'cpp' or CPP_HEADERS_MAP.include? header + end + + # Look for C++ keywords. This could check for comments, but doesn't. + return 'cpp' if buffer.find do | line | + line.split(/\W/).find do | word | + CPP_KEYWORDS_MAP.include? word + end + end + + # Nothing to suggest C++ + 'c' + end + + # Return a list of files included in a C or C++ source file. + def self.extract_c_cpp_headers(buffer) + buffer.map do | line | + m = line.match(/^#\s*include\s+[<"](.*)[>"]/) and m[1] + end.find_all { | a | a } + end + + # Tests whether the provided buffer contains binary or text content. + # This is not fool-proof -- we basically just check for zero values + # in the early bytes of the buffer. If we find a zero, we know it + # is not (ascii) text. + def self.binary_buffer?(buffer) + 100.times do |i| + return true if buffer[i] == 0 + end + false + end + + # True if the provided buffer includes a '?php' directive + def self.php_instruction?(buffer) + buffer =~ /\?php/ + end + + # For *.in files, checks the prior extension. + # Typically used for template files (eg Makefile.in, auto.c.in, etc). + def self.disambiguate_in(source_file) + # if the filename has an extension prior to the .in + if source_file.filename =~ /\..*\.in$/ + undecorated_filename = source_file.filename.gsub(/\.in$/, "") + undecorated_source = Ohcount::SourceFile.new(undecorated_filename, + :filenames => source_file.filenames, + :contents => source_file.contents, + :file_location => source_file.file_location) + return detect(undecorated_source) + end + nil + end + + # For *.inc files, checks for a PHP class. + def self.disambiguate_inc(file_context) + buffer = file_context.contents + return nil if binary_buffer?(buffer) + return 'php' if php_instruction?(buffer) + nil + end + + # For files with extention *.cs, differentiates C# from Clearsilver. + def self.disambiguate_cs(file_context) + buffer = file_context.contents + return 'clearsilver_template' if lines_matching(file_context.contents, /\<\?cs/) > 0 + return 'csharp' + end + + def self.disambiguate_fortran(file_context) + buffer = file_context.contents + + definitely_not_f77 = /^ [^0-9 ]{5}/ + return 'fortranfixed' if lines_matching(buffer, definitely_not_f77) > 0 + + free_form_continuation = /&\s*\n\s*&/m + return 'fortranfree' if buffer.match(free_form_continuation) + + possibly_fixed = /^ [0-9 ]{5}/ + contig_number = /^\s*\d+\s*$/ + buffer.scan(possibly_fixed) {|leader| + return 'fortranfixed' if !(leader =~ contig_number) } + # Might as well be free-form. + return 'fortranfree' + end + + # Attempts to tell apart VB, classic BASIC and structured BASIC. + # First, checks if it is classic BASIC based on syntax. + # If not checks for .vb, .vbp, .frx and .frm files (associated with VB) + # in file context + # + # If these files are absent, assumes structured BASIC + # + def self.disambiguate_basic(file_context) + classic_basic_line = /^\d+\s+\w+.*$/ + vb_filename = /\.fr[mx]$|\.vb([aps]?)$/ + buffer = file_context.contents + if lines_matching(buffer,classic_basic_line) > 0 + return 'classic_basic' + else + unless defined?(file_context.filenames.contains_vb) + file_context.filenames.extend(ContainsVB) + file_context.filenames.contains_vb = file_context.filenames.select { |a| a =~ vb_filename }.any? + end + if file_context.filenames.contains_vb + return 'visualbasic' + else + return 'structured_basic' + end + end + end + + def self.disambiguate_non_visual_basic(file_context) + classic_basic_line = /^\d+\s+\w+.*$/ + buffer = file_context.contents + + if lines_matching(buffer,classic_basic_line) > 0 + return 'classic_basic' + else + return 'structured_basic' + end + end + + # Attempts to determine the Polyglot for files that do not have a + # filename extension. + # + # Relies on the bash +file+ command line tool as its primary method. + # + # There must be a file at file_context.file_location for +file+ + # to operate on. + # + def self.disambiguate_nil(file_context) + file_location = file_context.file_location + output = `file -b '#{ file_location }'` + case output + when /([\w\/]+)(?: -[\w_]+)* script text/, /script text executable for ([\w\/]+)/ + script = $1 + if script =~ /\/(\w*)$/ + script = $1 + end + known_languages = EXTENSION_MAP.values + return script.downcase if known_languages.include?(script.downcase) + when /([\w\-]*) shell script text/ + case $1 + when "Bourne-Again" + return "shell" + end + end + + # dang... no dice + nil + end + + end + end +end diff --git a/lib/gestalt/base.rb b/lib/gestalt/base.rb new file mode 100644 index 0000000..1f17ddb --- /dev/null +++ b/lib/gestalt/base.rb @@ -0,0 +1,70 @@ +require "lib/gestalt/library" +require "lib/gestalt/platform" + +module Ohcount + module Gestalt + class Base + attr_reader :lib_counts + attr_reader :language_counts + attr_reader :platforms + attr_reader :filenames + + def initialize(args = {}) + if args[:dir] + @filenames = Dir.glob(File.join(args[:dir] + "/","**", "*")) + end + @filenames ||= args[:files] + @lib_counts = {} + @platforms = [] + @language_counts = {} + end + + def process! + # process files + filenames.each do |filename| + s = SourceFile.new(filename) + Library.detect_libraries(s).collect { |library| library.to_sym }.each do |l| + @lib_counts[l] ||= 0 + @lib_counts[l] += 1 + end + s.languages.each do |l| + @language_counts[l] = s.send(l).code.to_s.split.size + end + end + + # since platforms can depend on other platforms, + # we perform an iterative process and break when + # no new platforms have been detected. + while true do + prev_platforms = self.platforms.clone + uninfered_platforms.each do |p| + platforms << p if p.triggered?(self) + end + break if prev_platforms == self.platforms + end + end + + def uninfered_platforms + Platform.descendants - @platforms + end + + def includes_language?(language, min_percent = 0) + return false unless language_counts[language] + language_percents[language] >= min_percent + end + + def language_percents + @language_percents ||= begin + total = language_counts.values.inject(0) { |s,c| s+c } + l = {} + language_counts.each do |k,v| + l[k] = 100.0 * v.to_i / total + end + l + end + end + + end + end +end + diff --git a/lib/gestalt/library.rb b/lib/gestalt/library.rb new file mode 100644 index 0000000..f1faedc --- /dev/null +++ b/lib/gestalt/library.rb @@ -0,0 +1,73 @@ +require 'lib/gestalt/library_rule' + +module Ohcount + module Gestalt + + # A library represents the binding to a specific 'library'. The class methods + # allow the detection of the library. + class Library + attr_reader :triggered_rules + + def initialize(*rules) + @triggered_rules = rules + end + + def self.rules + @rules ||= [] + end + + def self.c_headers(*header_names) + rules << CHeaderRule.new(header_names) + end + + def self.files(*filenames) + rules << FileRule.new(filenames) + end + + def self.c_keywords(*keywords) + rules << CKeywordRule.new(keywords) + end + + def to_sym + self.class.to_sym + end + + # when tallying up libraries, its easier to + # use symbol names instead of class names + # to_sym maps FooLib to :foo_lib + def self.to_sym + @symbol ||= begin + to_s =~ /([^:]*)$/ + naked_classname = $1 + chars = naked_classname.scan(/./) + chars[0] = chars[0].downcase + ruby_s = chars.collect do |char| + char.downcase == char ? char : "_" + char.downcase + end.to_s + ruby_s.intern + end + end + + def self.detect_libraries(source_file) + descendants.inject([]) do |a, l| + r = l.triggered_rule(source_file) + r ? ( a << l.new(r)) : a + end + end + + def self.triggered_rule(source_file) + rules.each do |r| + return r if r.trigger?(source_file) + end + nil + end + + # tricky code to let us track the descendants... + class << self + def children() @children ||= [] end + def inherited(other) children << other and super end + def descendants() children.inject([]){|d,c| d.push(c, *c.descendants)} end + end + end + end +end diff --git a/lib/gestalt/library_rule.rb b/lib/gestalt/library_rule.rb new file mode 100644 index 0000000..53a9abf --- /dev/null +++ b/lib/gestalt/library_rule.rb @@ -0,0 +1,66 @@ +module Ohcount + module Gestalt + + class LibraryRule + def ==(other) + return false unless self.class == other.class + return false unless self.instance_variables == other.instance_variables + self.instance_variables.each do |v| + return false unless self.send(v[1..-1]) == other.send(v[1..-1]) + end + true + end + end + + class CHeaderRule < LibraryRule + attr_reader :headers + + def initialize(*headers) + @headers = headers + end + + def trigger?(source_file) + return false unless ['c','cpp'].include?(source_file.polyglot) + regexp.match(source_file.c.code) || regexp.match(source_file.cpp.code) + end + + def regexp + @regexp ||= begin + header_term = "(" + headers.join("|") + ")" + Regexp.new("include\s+['<\"]#{ header_term }[\">']", Regexp::IGNORECASE) + end + end + end + + class FileRule < LibraryRule + attr_reader :filenames + + def initialize(filenames) + @filenames = filenames + end + + def trigger?(source_file) + filenames.include?(source_file.basename) + end + end + + class CKeywordRule < LibraryRule + attr_reader :keywords + + def initialize(*keywords) + @keywords = keywords + end + + def trigger?(source_file) + return false unless ['c','cpp'].include?(source_file.polyglot) + regexp.match(source_file.c.code) || regexp.match(source_file.cpp.code) + end + + def regexp + @regexp ||= begin + Regexp.new("(" + keywords.join("|") + ")") + end + end + end + end +end diff --git a/lib/gestalt/platform.rb b/lib/gestalt/platform.rb new file mode 100644 index 0000000..96637e8 --- /dev/null +++ b/lib/gestalt/platform.rb @@ -0,0 +1,113 @@ +require 'lib/gestalt/library' +#require 'lib/gestalt/platforms/platform' + +module Ohcount + module Gestalt + class Platform + + # platform triggers are assumed to be, at the top level, + # OR-ed. In other words, any one rule will trigger that platform. + # That's why we keep a top-level OrTrigger around. + def self.top_level_or + @top_level_or ||= OrTrigger.new + end + + # we delegate to the top_level_or trigger + def self.method_missing(method, *args) + top_level_or.send(method, *args) + end + + # tricky code to let us track the descendants... + class << self + def children() @children ||= [] end + def inherited(other) children << other and super end + def descendants() children.inject([]){|d,c| d.push(c, *c.descendants)} end + end + end + + # Will trigger if any sub-trigger does + class OrTrigger + attr_reader :triggers + + def initialize(*triggers) + @triggers = triggers + end + + def triggered?(g_attr) + triggers.each do |t| + return t if t.triggered?(g_attr) + end + nil + end + + def trigger_libs(*args) + triggers << LibsTrigger.new(*args) + end + + def trigger_platform(platform) + triggers << PlatformTrigger.new(platform) + end + + def trigger_language(language, options = {}) + triggers << LanguageTrigger.new(language, options) + end + end + + # will trigger if any libs were detected + # options: + # :count => minimum number of detections (default 1) + class LibsTrigger + attr_reader :lib_symbols + attr_reader :count + + def initialize(*args) + options = args.last.is_a?(::Hash) ? args.pop : {} + @count = options.delete(:count) || 1 + raise "Unrecognized LibsTrigger options '#{ options.keys.inspect }'" if options.any? + @lib_symbols = args + end + + def triggered?(g) + c = count + lib_symbols.each do |ls| + c -= g.lib_counts[ls].to_i + return self if c <= 0 + end + nil + end + end + + class PlatformTrigger + attr_reader :platform + + def initialize(platform) + @platform = platform + end + + def triggered?(g) + g.platforms.include?(platform) + end + end + + class LanguageTrigger + attr_reader :language + attr_reader :min_percent + + def initialize(language, options= {}) + @min_percent = options.delete(:min_percent) || 0 + raise "Unrecognized LanguageTrigger options '#{ options.keys.inspect }'" if options.any? + @language = language + end + + def triggered?(g) + return self if g.includes_language?(language, min_percent) + end + + end + end +end + +# require the dynamic rules +require OHCOUNT_ROOT + '/rules/libraries' +require OHCOUNT_ROOT + '/rules/platforms' + diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb new file mode 100644 index 0000000..08b87b7 --- /dev/null +++ b/lib/ohcount/source_file.rb @@ -0,0 +1,125 @@ +module Ohcount + + # SourceFile abstracts a source code file and allows easy querying of ohcount-related + # information. + # + # It provides some abstractions to enable ohloh to call it in its own, weird, way. + # For example, in simple usage scenarios, the SimpleFileContext can simply point + # to an actual file on disk. In more complex scenarios, the context allows the + # file contents to be delivered to ohcount from a temp file or in-memory cache. + # + class SourceFile + # The filename we're dealing with. + attr_reader :filename + + # An array of names of other files in the source tree which + # may be helpful when disambiguating the language used by the target file. + # For instance, the presence of an Objective-C *.m file is a clue when + # determining the language used in a *.h header file. + # This array is optional, but language identification may be less accurate + # without it. + attr_reader :filenames + + # The location on disk where the file content can currently be found. + # This might not be the same as the original name of the file. + # For example, file content might be stored in temporary directory. + attr_reader :file_location + + # At a minimum, you must provide the filename. + # + # You may also optionally pass an array of names of other files in the source tree. + # This will assist when disambiguating the language used by the source file. + # If you do not include this array, language identification may be less accurate. + # + # The SimpleFileContext must provide access to the file content. You can do this + # by one of three means, which will be probed in the following order: + # + # 1. You may optionally pass the content of the source file as string +cached_contents+. + # + # 2. You may optionally provide +file_location+ as the name of a file on disk + # which contains the content of this source file. + # + # 3. If you do neither 1 nor 2, then +filename+ will be assumed to be an actual file on + # disk which can be read. + # + def initialize(filename, options = {}) + @filename = filename + @filenames = options[:filenames] || [] + @contents = options[:contents] + @file_location = options[:file_location] || @filename + end + + def contents + @contents ||= File.open(@file_location || @filename) do |io| + io.read + end + end + + def polyglot + @polyglot ||= Ohcount::Detector::Base.detect(self) + end + + def basename + File.basename(filename) + end + + # returns TRUE if this source_file is recognized as being + # some type of source code + def source_code? + !!polyglot + end + + def parse + # dont reparse for nothing + return if parsed? && !block_given? + + @languages = {} + return unless polyglot + Ohcount::parse(contents, polyglot) do |language, semantic, line| + @languages[language] ||= HashWithDotAccess.new + @languages[language][semantic] ||= '' + @languages[language][semantic] << line + yield(language, semantic, line) if block_given? + end + end + + def parsed? + !(@languages.nil?) + end + + def languages + parse unless @languages + @languages.keys + end + + def licenses + @licenses ||= begin + comments = '' + parse do |language, semantic, line| + next unless semantic == :comment + # Strip leading punctuation. + comments << ' ' + $1 if line =~ /^[\s[:punct:]]*(.*?)$/ + end + LicenseSniffer.sniff(comments) + end + end + + def raw_entities(&block) + return unless source_code? + Ohcount::parse_entities(contents, polyglot, &block) + end + + # we support sourcefile.ruby + def method_missing(method, *args) + parse + return @languages[method] || HashWithDotAccess.new + end + + end +end + +class HashWithDotAccess < Hash + def method_missing(method, *args) + self[method] if args.empty? + end +end diff --git a/rules/libraries.rb b/rules/libraries.rb new file mode 100644 index 0000000..5af4722 --- /dev/null +++ b/rules/libraries.rb @@ -0,0 +1,16 @@ +# Libraries +# +module Ohcount + module Gestalt + + class GnuLib < Library + c_headers 'pthread.h', 'xstrtol.h', 'xreadlink.h', 'fatal-signal.h', 'diacrit.h' + end + + class WindowsConstants < Library + c_headers 'windows.h' + c_keywords 'WM_PAINT', 'ReleaseDC', 'WndProc' + end + + end +end diff --git a/rules/platforms.rb b/rules/platforms.rb new file mode 100644 index 0000000..87c0707 --- /dev/null +++ b/rules/platforms.rb @@ -0,0 +1,20 @@ +# platforms + +include Ohcount::Gestalt + +class POSIX < Platform + trigger_libs :gnu_lib + trigger_language :autoconf +end + +class Win32 < Platform + trigger_libs :windows_constants, :count => 2 +end + +class Linux < Platform + trigger_platform POSIX +end + +class Ruby < Platform + trigger_language :ruby, :min_percent => 15 +end diff --git a/rules/tools.rb b/rules/tools.rb new file mode 100644 index 0000000..c906753 --- /dev/null +++ b/rules/tools.rb @@ -0,0 +1,8 @@ +# Tools +class VisualStudio < Tool + c_headers 'pthread.h', 'xstrtol.h', 'xreadlink.h', 'fatal-signal.h', 'diacrit.h' +end + +class Eclipse < Tool + files 'Makefile.conf' +end diff --git a/test/gestalt_files/test_linux_1/configure.in b/test/gestalt_files/test_linux_1/configure.in new file mode 100644 index 0000000..0e76864 --- /dev/null +++ b/test/gestalt_files/test_linux_1/configure.in @@ -0,0 +1 @@ +a line of code diff --git a/test/gestalt_files/test_linux_1/foo.c b/test/gestalt_files/test_linux_1/foo.c new file mode 100644 index 0000000..dcbbbf8 --- /dev/null +++ b/test/gestalt_files/test_linux_1/foo.c @@ -0,0 +1,102 @@ +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; +int = 0; diff --git a/test/gestalt_files/test_linux_1/foo.rb b/test/gestalt_files/test_linux_1/foo.rb new file mode 100644 index 0000000..7505dbc --- /dev/null +++ b/test/gestalt_files/test_linux_1/foo.rb @@ -0,0 +1,4 @@ +# this is ruby code +class Foo + attr_reader :bar +end diff --git a/test/gestalt_files/test_ruby_just_enough/foo.c b/test/gestalt_files/test_ruby_just_enough/foo.c new file mode 100644 index 0000000..64e6c46 --- /dev/null +++ b/test/gestalt_files/test_ruby_just_enough/foo.c @@ -0,0 +1,75 @@ +int i = 1; +int i = 2; +int i = 3; +int i = 4; +int i = 5; +int i = 6; +int i = 7; +int i = 8; +int i = 9; +int i = 10; +int i = 11; +int i = 12; +int i = 13; +int i = 14; +int i = 15; +int i = 16; +int i = 17; +int i = 18; +int i = 19; +int i = 20; +int i = 21; +int i = 22; +int i = 23; +int i = 24; +int i = 25; +int i = 26; +int i = 27; +int i = 28; +int i = 29; +int i = 30; +int i = 31; +int i = 32; +int i = 33; +int i = 34; +int i = 35; +int i = 36; +int i = 37; +int i = 38; +int i = 39; +int i = 40; +int i = 41; +int i = 42; +int i = 43; +int i = 44; +int i = 45; +int i = 46; +int i = 47; +int i = 48; +int i = 49; +int i = 50; +int i = 51; +int i = 52; +int i = 53; +int i = 54; +int i = 55; +int i = 56; +int i = 57; +int i = 58; +int i = 59; +int i = 60; +int i = 61; +int i = 62; +int i = 63; +int i = 64; +int i = 65; +int i = 66; +int i = 67; +int i = 68; +int i = 69; +int i = 70; +int i = 71; +int i = 72; +int i = 73; +int i = 74; +int i = 75; diff --git a/test/gestalt_files/test_ruby_just_enough/foo.rb b/test/gestalt_files/test_ruby_just_enough/foo.rb new file mode 100644 index 0000000..6cfd7a3 --- /dev/null +++ b/test/gestalt_files/test_ruby_just_enough/foo.rb @@ -0,0 +1,15 @@ +a = 1 +a = 2 +a = 3 +a = 4 +a = 5 +a = 6 +a = 7 +a = 8 +a = 9 +a = 10 +a = 11 +a = 12 +a = 13 +a = 14 +a = 15 diff --git a/test/gestalt_files/test_ruby_not_enough/foo.c b/test/gestalt_files/test_ruby_not_enough/foo.c new file mode 100644 index 0000000..bc21e75 --- /dev/null +++ b/test/gestalt_files/test_ruby_not_enough/foo.c @@ -0,0 +1,87 @@ +int i = 1; +int i = 2; +int i = 3; +int i = 4; +int i = 5; +int i = 6; +int i = 7; +int i = 8; +int i = 9; +int i = 10; +int i = 11; +int i = 12; +int i = 13; +int i = 14; +int i = 15; +int i = 16; +int i = 17; +int i = 18; +int i = 19; +int i = 20; +int i = 21; +int i = 22; +int i = 23; +int i = 24; +int i = 25; +int i = 26; +int i = 27; +int i = 28; +int i = 29; +int i = 30; +int i = 31; +int i = 32; +int i = 33; +int i = 34; +int i = 35; +int i = 36; +int i = 37; +int i = 38; +int i = 39; +int i = 40; +int i = 41; +int i = 42; +int i = 43; +int i = 44; +int i = 45; +int i = 46; +int i = 47; +int i = 48; +int i = 49; +int i = 50; +int i = 51; +int i = 52; +int i = 53; +int i = 54; +int i = 55; +int i = 56; +int i = 57; +int i = 58; +int i = 59; +int i = 60; +int i = 61; +int i = 62; +int i = 63; +int i = 64; +int i = 65; +int i = 66; +int i = 67; +int i = 68; +int i = 69; +int i = 70; +int i = 71; +int i = 72; +int i = 73; +int i = 74; +int i = 75; +int i = 76; +int i = 77; +int i = 78; +int i = 79; +int i = 80; +int i = 81; +int i = 82; +int i = 83; +int i = 84; +int i = 85; +int i = 86; +int i = 87; diff --git a/test/gestalt_files/test_ruby_not_enough/foo.rb b/test/gestalt_files/test_ruby_not_enough/foo.rb new file mode 100644 index 0000000..6cfd7a3 --- /dev/null +++ b/test/gestalt_files/test_ruby_not_enough/foo.rb @@ -0,0 +1,15 @@ +a = 1 +a = 2 +a = 3 +a = 4 +a = 5 +a = 6 +a = 7 +a = 8 +a = 9 +a = 10 +a = 11 +a = 12 +a = 13 +a = 14 +a = 15 diff --git a/test/gestalt_files/test_win32_enough/bar.c b/test/gestalt_files/test_win32_enough/bar.c new file mode 100644 index 0000000..e7919b8 --- /dev/null +++ b/test/gestalt_files/test_win32_enough/bar.c @@ -0,0 +1,3 @@ +// a commented WndProc +WndProc *wndproc; + diff --git a/test/gestalt_files/test_win32_enough/foo.c b/test/gestalt_files/test_win32_enough/foo.c new file mode 100644 index 0000000..13de7b2 --- /dev/null +++ b/test/gestalt_files/test_win32_enough/foo.c @@ -0,0 +1,3 @@ +// another commented WndProc +WndProc *wndproc; + diff --git a/test/gestalt_files/test_win32_not_enough/foo.c b/test/gestalt_files/test_win32_not_enough/foo.c new file mode 100644 index 0000000..e7919b8 --- /dev/null +++ b/test/gestalt_files/test_win32_not_enough/foo.c @@ -0,0 +1,3 @@ +// a commented WndProc +WndProc *wndproc; + diff --git a/test/test_helper.rb b/test/test_helper.rb index d2cf357..cf94976 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -2,7 +2,9 @@ require 'fileutils' require 'find' -TEST_DIR = File.dirname(__FILE__) +unless defined?(TEST_DIR) + TEST_DIR = File.dirname(__FILE__) +end require TEST_DIR + '/../lib/ohcount' # Ohcount::Test is a base class which includes several helper methods for parser testing. diff --git a/test/unit/gestalt/library_rule_test.rb b/test/unit/gestalt/library_rule_test.rb new file mode 100644 index 0000000..a4fe234 --- /dev/null +++ b/test/unit/gestalt/library_rule_test.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class LibraryRuleTest < Test::Unit::TestCase + + def test_trigger_c_header + r = Ohcount::Gestalt::CHeaderRule.new('foo.h') + s = Ohcount::SourceFile.new('header.h', :contents => <<-H_FILE + // a comment + include 'foo.h' + H_FILE + ) + assert r.trigger?(s) + end + + def test_c_keyword_rule + r = Ohcount::Gestalt::CKeywordRule.new('WM_PAINT') + s = Ohcount::SourceFile.new('header.h', :contents => <<-H_FILE + // a comment + (WM_PAINT) + H_FILE + ) + assert r.trigger?(s) + end + + def test_file_rule + r = Ohcount::Gestalt::FileRule.new('header.h') + s = Ohcount::SourceFile.new('header.h') + assert r.trigger?(s) + end +end + + diff --git a/test/unit/gestalt/library_test.rb b/test/unit/gestalt/library_test.rb new file mode 100644 index 0000000..99c39c9 --- /dev/null +++ b/test/unit/gestalt/library_test.rb @@ -0,0 +1,47 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +include Ohcount +include Ohcount::Gestalt + +class TestLibrary < Ohcount::Gestalt::Library + c_headers "foobar.h" +end + +class LibraryTest < Test::Unit::TestCase + def test_descendants + assert Library.descendants.include?(TestLibrary) + end + + def test_gnulib + s = SourceFile.new("foo.h", :filenames => [], :contents => <<-INLINE_C + include ; + INLINE_C + ) + assert_detected_lib(s, GnuLib, CHeaderRule) + + s = SourceFile.new("foo.h", :filenames => [], :contents => <<-INLINE_C + include 'diacrit.h'; + INLINE_C + ) + assert_detected_lib(s, GnuLib, CHeaderRule) + end + + def test_windows_constants + s = SourceFile.new("foo.c", :filenames => [], :contents => <<-INLINE_C + wc.lpfnWndProc = (WNDPROC) WndProc; + INLINE_C + ) + assert_detected_lib(s, WindowsConstants, CKeywordRule) + end + + protected + + def assert_detected_lib(source_file, lib, triggered_rule) + libs = Ohcount::Gestalt::Library.detect_libraries(source_file) + assert_equal 1, libs.size + assert_equal lib, libs[0].class + + assert_equal 1, libs[0].triggered_rules.size + assert_equal triggered_rule, libs[0].triggered_rules[0].class + end +end diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb new file mode 100644 index 0000000..361c3d2 --- /dev/null +++ b/test/unit/gestalt/platform_test.rb @@ -0,0 +1,46 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +include Ohcount +include Ohcount::Gestalt + +class PlatformTest < Test::Unit::TestCase + +# def test_initialize +# b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_win32')) +# assert_equal [gestalt_file_dir('test_win32/foo.c')], b.filenames +# end + +# def test_win32_not_enough +# b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_win32_not_enough')) +# b.process! +# assert_equal [], b.platforms +# end +# +# def test_win32_enough +# b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_win32_enough')) +# b.process! +# assert_equal [Win32], b.platforms +# end + + def test_linux_1 + b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_linux_1')) + b.process! + assert_equal [POSIX, Linux], b.platforms + end + +# def test_ruby_just_enough +# b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_ruby_just_enough')) +# b.process! +# assert_equal [Ruby], b.platforms +# end +# +# def test_ruby_not_enough +# b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_ruby_not_enough')) +# b.process! +# assert_equal [], b.platforms +# end +# + def gestalt_file_dir(path = '') + File.expand_path(File.dirname(__FILE__) + "/../../gestalt_files/" + path) + end +end diff --git a/test/unit/parsers/actionscript_test.rb b/test/unit/parsers/actionscript_test.rb new file mode 100644 index 0000000..13efba0 --- /dev/null +++ b/test/unit/parsers/actionscript_test.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::ActionscriptTest < Ohcount::Test + def test_comments + lb = [Ohcount::LanguageBreakdown.new("actionscript", "", "//comment", 0)] + assert_equal lb, Ohcount::parse(" //comment", "actionscript") + end + + def test_comprehensive + verify_parse("as1.as") + end + + def test_comment_entities + assert_equal('//comment', entities_array(' //comment', 'actionscript', :comment).first) + assert_equal('/*comment*/', entities_array(' /*comment*/', 'actionscript', :comment).first) + end +end diff --git a/test/unit/parsers/ada_test.rb b/test/unit/parsers/ada_test.rb new file mode 100644 index 0000000..d9d32e7 --- /dev/null +++ b/test/unit/parsers/ada_test.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::AdaTest < Ohcount::Test + def test_comment + lb = [Ohcount::LanguageBreakdown.new("ada", "", "--comment", 0)] + assert_equal lb, Ohcount::parse(" --comment", "ada") + end + + def test_comprehensive + verify_parse("ada1.ada") + end + + def test_comprehensive_adb + verify_parse("ada1.adb") + end + + def test_comment_entities + assert_equal('--comment', entities_array(' --comment', 'ada', :comment).first) + end +end diff --git a/test/unit/parsers/assembler_test.rb b/test/unit/parsers/assembler_test.rb new file mode 100644 index 0000000..75595f3 --- /dev/null +++ b/test/unit/parsers/assembler_test.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::AssemblerTest < Ohcount::Test + def test_comment + lb = [Ohcount::LanguageBreakdown.new("assembler", "", "!comment\n;comment", 0)] + assert_equal lb, Ohcount::parse(" !comment\n ;comment", "assembler") + end + + def test_comprehensive + verify_parse("assembler1.asm") + end + + def test_comprehensive_2 + verify_parse("assembler2.S") + end + + def test_comment_entities + assert_equal(['//comment', '; comment', '!comment'], + entities_array(" //comment\n; comment\n\t!comment", 'assembler', :comment)) + end +end diff --git a/test/unit/parsers/autoconf_test.rb b/test/unit/parsers/autoconf_test.rb new file mode 100644 index 0000000..91fcb03 --- /dev/null +++ b/test/unit/parsers/autoconf_test.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::AutoconfTest < Ohcount::Test + def test_comprehensive + verify_parse("configure.ac") + end + + def test_comment_entities + assert_equal('dnl comment', entities_array(" dnl comment", 'autoconf', :comment).first) + end +end + diff --git a/test/unit/parsers/automake_test.rb b/test/unit/parsers/automake_test.rb new file mode 100644 index 0000000..1663be1 --- /dev/null +++ b/test/unit/parsers/automake_test.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::AutomakeTest < Ohcount::Test + def test_comprehensive + verify_parse("Makefile.am") + end + + def test_comment_entities + assert_equal('#comment', entities_array(" #comment", 'automake', :comment).first) + end +end + diff --git a/test/unit/parsers/awk_test.rb b/test/unit/parsers/awk_test.rb new file mode 100644 index 0000000..63cf62f --- /dev/null +++ b/test/unit/parsers/awk_test.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::AwkTest < Ohcount::Test + def test_comment + lb = [Ohcount::LanguageBreakdown.new("awk", "", "#comment", 0)] + assert_equal lb, Ohcount::parse(" #comment", "awk") + end + + def test_double_slash + lb = [Ohcount::LanguageBreakdown.new("awk", "\"\\\\\"\n", "#comment", 0)] + # awk doesn't recognize backslash escaping of double quote...weird + assert_equal lb, Ohcount::parse("\"\\\\\"\n#comment", "awk") + end + + def test_comprehensive + verify_parse("awk1.awk") + end + + def test_comment_entities + assert_equal('#comment', entities_array(" #comment", 'awk', :comment).first) + end +end diff --git a/test/unit/parsers/basic_test.rb b/test/unit/parsers/basic_test.rb new file mode 100644 index 0000000..2450af0 --- /dev/null +++ b/test/unit/parsers/basic_test.rb @@ -0,0 +1,26 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::BasicTest < Ohcount::Test + def test_sb_comments + lb = [Ohcount::LanguageBreakdown.new("structured_basic", "", "REM comment", 0)] + assert_equal lb, Ohcount::parse("REM comment", "structured_basic") + end + + def test_cb_comments + lb = [Ohcount::LanguageBreakdown.new("classic_basic", "", "100 REM comment", 0)] + assert_equal lb, Ohcount::parse(" 100 REM comment", "classic_basic") + end + + def test_comprehensive + verify_parse("classic_basic.b") + verify_parse("visual_basic.bas", ["frx1.frx"]) + verify_parse("structured_basic.b") + verify_parse("structured_basic.bas") + verify_parse("classic_basic.bas") + end + + def test_comment_entities + assert_equal('REM comment', entities_array(" REM comment", 'structured_basic', :comment).first) + assert_equal('\'comment', entities_array(" 'comment", 'classic_basic', :comment).first) + end +end diff --git a/test/unit/parsers/bat_test.rb b/test/unit/parsers/bat_test.rb new file mode 100644 index 0000000..784a282 --- /dev/null +++ b/test/unit/parsers/bat_test.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::BatTest < Ohcount::Test + def test_comment + lb = [Ohcount::LanguageBreakdown.new("bat", "", "REM comment", 0)] + assert_equal lb, Ohcount::parse(" REM comment", "bat") + end + + def test_comprehensive + verify_parse("bat1.bat") + end + + def test_comment_entities + assert_equal('rem comment', entities_array(" rem comment", 'bat', :comment).first) + end +end diff --git a/test/unit/parsers/boo_test.rb b/test/unit/parsers/boo_test.rb new file mode 100644 index 0000000..e2cd985 --- /dev/null +++ b/test/unit/parsers/boo_test.rb @@ -0,0 +1,37 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::BooTest < Ohcount::Test + def test_comment + lb = [Ohcount::LanguageBreakdown.new("boo", "", "#comment", 0)] + assert_equal lb, Ohcount::parse(" #comment", "boo") + end + + def test_block_comment + lb = [Ohcount::LanguageBreakdown.new("boo", "", "/*comment*/", 0)] + assert_equal lb, Ohcount::parse(" /*comment*/", "boo") + end + + def test_nested_block_comment + lb = [Ohcount::LanguageBreakdown.new("boo", "", "/* comment\n/* nested */\nstill a comment */", 0)] + assert_equal lb, Ohcount::parse(" /* comment\n /* nested */\n still a comment */", "boo") + end + + def test_doc_comments + lb = [Ohcount::LanguageBreakdown.new("boo", "", "\"\"\"\ndoc comment\n\"\"\"", 0)] + assert_equal lb, Ohcount::parse("\"\"\"\ndoc comment\n\"\"\"", "boo") + end + + def test_strings + lb = [Ohcount::LanguageBreakdown.new("boo", "\"abc#not a 'comment\"", "", 0)] + assert_equal lb, Ohcount::parse("\"abc#not a 'comment\"", "boo") + end + + def test_comprehensive + verify_parse("boo1.boo") + end + + def test_comment_entities + assert_equal('#comment', entities_array(" #comment", 'boo', :comment).first) + assert_equal('//comment', entities_array(" //comment", 'boo', :comment).first) + end +end diff --git a/test/unit/parsers/c_test.rb b/test/unit/parsers/c_test.rb new file mode 100644 index 0000000..b050073 --- /dev/null +++ b/test/unit/parsers/c_test.rb @@ -0,0 +1,35 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::CTest < Ohcount::Test + + def test_comments + lb = [Ohcount::LanguageBreakdown.new("c", "", "//comment", 0)] + assert_equal lb, Ohcount::parse(" //comment", "c") + end + + def test_empty_comments + lb = [Ohcount::LanguageBreakdown.new("c", "","//\n", 0)] + assert_equal lb, Ohcount::parse(" //\n", "c") + end + + + def test_block_comment + lb = [Ohcount::LanguageBreakdown.new("c", "","/*c*/", 0)] + assert_equal lb, Ohcount::parse("/*c*/", "c") + end + + def test_comprehensive + verify_parse("c1.c") + verify_parse("c_str.c") + end + + def test_comprehensive_in + verify_parse("c2.h.in") + end + + def test_comment_entities + assert_equal('//comment', entities_array(" //comment", 'c', :comment).first) + assert_equal('/*comment*/', entities_array(" /*comment*/", 'c', :comment).first) + end + +end diff --git a/test/unit/parsers/clearsilver_template_test.rb b/test/unit/parsers/clearsilver_template_test.rb new file mode 100644 index 0000000..618f328 --- /dev/null +++ b/test/unit/parsers/clearsilver_template_test.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::ClearsilverTemplateTest < Ohcount::Test + + def test_comment + html_lb = Ohcount::LanguageBreakdown.new("html", "", "", 0) + clearsilver_template_lb = Ohcount::LanguageBreakdown.new("clearsilver", "", "#comment\n", 0) + assert_equal [html_lb, clearsilver_template_lb], Ohcount::parse("", "clearsilver_template") + end + + def test_comprehensive + verify_parse("clearsilver_template1.cs") + end + + def test_comment_entities + assert_equal('', entities_array(" ", 'clearsilver_template', :comment).first) + assert_equal('#comment', entities_array("", 'clearsilver_template', :comment).first) + end + +end diff --git a/test/unit/parsers/clearsilver_test.rb b/test/unit/parsers/clearsilver_test.rb new file mode 100644 index 0000000..8cacf4b --- /dev/null +++ b/test/unit/parsers/clearsilver_test.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::ClearsilverTest < Ohcount::Test + + def test_comment + lb = [Ohcount::LanguageBreakdown.new("clearsilver", "", "#comment", 0)] + assert_equal lb, Ohcount::parse(" #comment", "clearsilver") + end + + def test_comment_entities + assert_equal('#comment', entities_array(" #comment", 'clearsilver', :comment).first) + end + +end diff --git a/test/unit/parsers/csharp_test.rb b/test/unit/parsers/csharp_test.rb new file mode 100644 index 0000000..1b25ffc --- /dev/null +++ b/test/unit/parsers/csharp_test.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::CSharpTest < Ohcount::Test + + def test_comment + lb = [Ohcount::LanguageBreakdown.new("csharp", "", "//comment", 0)] + assert_equal lb, Ohcount::parse(" //comment", "csharp") + end + + def test_comprehensive + verify_parse("cs1.cs") + end + + def test_comment_entities + assert_equal('//comment', entities_array(" //comment", 'csharp', :comment).first) + assert_equal('/*comment*/', entities_array(" /*comment*/", 'csharp', :comment).first) + end + +end diff --git a/test/unit/parsers/css_test.rb b/test/unit/parsers/css_test.rb new file mode 100644 index 0000000..a6bfd12 --- /dev/null +++ b/test/unit/parsers/css_test.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::CssTest < Ohcount::Test + def test_comment + lb = [Ohcount::LanguageBreakdown.new("css", "", "/*comment*/", 0)] + assert_equal lb, Ohcount::parse(" /*comment*/", "css") + end + + def test_comprehensive + verify_parse("css1.css") + end + + def test_comment_entities + assert_equal('/*comment*/', entities_array(" /*comment*/", 'css', :comment).first) + end +end diff --git a/test/unit/parsers/d_test.rb b/test/unit/parsers/d_test.rb new file mode 100644 index 0000000..14e1b3c --- /dev/null +++ b/test/unit/parsers/d_test.rb @@ -0,0 +1,43 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::DTest < Ohcount::Test + + def test_comments + lb = [Ohcount::LanguageBreakdown.new("dmd", "", "//comment", 0)] + assert_equal lb, Ohcount::parse(" //comment", "dmd") + end + + def test_empty_comments + lb = [Ohcount::LanguageBreakdown.new("dmd", "","//\n", 0)] + assert_equal lb, Ohcount::parse(" //\n", "dmd") + end + + def test_strings + lb = [Ohcount::LanguageBreakdown.new("dmd", "'/*' not a comment '*/'", "", 0)] + assert_equal lb, Ohcount::parse("'/*' not a comment '*/'", "dmd") + end + + def test_block_comment + lb = [Ohcount::LanguageBreakdown.new("dmd", "","/*d*/", 0)] + assert_equal lb, Ohcount::parse("/*d*/", "dmd") + + lb = [Ohcount::LanguageBreakdown.new("dmd", "","/+d+/", 0)] + assert_equal lb, Ohcount::parse("/+d+/", "dmd") + end + + def test_nested_block_comment + lb = [Ohcount::LanguageBreakdown.new("dmd", "","/+ /*d*/ not_code(); +/", 0)] + assert_equal lb, Ohcount::parse("/+ /*d*/ not_code(); +/", "dmd") + end + + def test_comprehensive + verify_parse("d1.d") + end + + def test_comment_entities + assert_equal('//comment', entities_array(" //comment", 'dmd', :comment).first) + assert_equal('/*comment*/', entities_array(" /*comment*/", 'dmd', :comment).first) + assert_equal('/+comment+/', entities_array(" /+comment+/", 'dmd', :comment).first) + end + +end diff --git a/test/unit/parsers/dcl_test.rb b/test/unit/parsers/dcl_test.rb new file mode 100644 index 0000000..c599c90 --- /dev/null +++ b/test/unit/parsers/dcl_test.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::DclTest < Ohcount::Test + def test_comment + lb = [Ohcount::LanguageBreakdown.new("dcl", "", "$!comment", 0)] + assert_equal lb, Ohcount::parse("$!comment", "dcl") + end + + def test_code + lb= [Ohcount::LanguageBreakdown.new("dcl", "$code", "", 0)] + assert_equal lb, Ohcount::parse("$code", "dcl") + end + + def test_blank + lb=[Ohcount::LanguageBreakdown.new("dcl", "", "", 1)] + assert_equal lb, Ohcount::parse("\n", "dcl") + end + + def test_input_line + lb=[Ohcount::LanguageBreakdown.new("dcl", "input", "", 0)] + assert_equal lb, Ohcount::parse("input", "dcl") + end + + + def test_comprehensive + verify_parse("dcl.com") + end + + def test_comment_entities + assert_equal('!comment', entities_array(" !comment", 'dcl', :comment).first) + end +end diff --git a/test/unit/parsers/dylan_test.rb b/test/unit/parsers/dylan_test.rb new file mode 100644 index 0000000..0f6ab5b --- /dev/null +++ b/test/unit/parsers/dylan_test.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::DylanTest < Ohcount::Test + + def test_comment + lb = [Ohcount::LanguageBreakdown.new("dylan", "", "//comment", 0)] + assert_equal lb, Ohcount::parse(" //comment", "dylan") + end + + def test_comprehensive + verify_parse("dylan1.dylan") + end + + def test_comment_entities + assert_equal('//comment', entities_array(" //comment", 'dylan', :comment).first) + assert_equal('/*comment*/', entities_array(" /*comment*/", 'dylan', :comment).first) + end +end diff --git a/test/unit/parsers/ebuild_test.rb b/test/unit/parsers/ebuild_test.rb new file mode 100644 index 0000000..b493154 --- /dev/null +++ b/test/unit/parsers/ebuild_test.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::EbuildTest < Ohcount::Test + def test_comprehensive + verify_parse("foo.ebuild") + end + + def test_comment_entities + assert_equal('#comment', entities_array(" #comment", 'ebuild', :comment).first) + end +end diff --git a/test/unit/parsers/eiffel_test.rb b/test/unit/parsers/eiffel_test.rb new file mode 100644 index 0000000..d037d57 --- /dev/null +++ b/test/unit/parsers/eiffel_test.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::EiffelTest < Ohcount::Test + def test_cb_comments + lb = [Ohcount::LanguageBreakdown.new("eiffel", "", "-- comment", 0)] + assert_equal lb, Ohcount::parse(" -- comment", "eiffel") + end + + def test_comprehensive + verify_parse("eiffel.e") + end + + def test_comment_entities + assert_equal('--comment', entities_array(" --comment", 'eiffel', :comment).first) + end + +end diff --git a/test/unit/parsers/emacs_lisp.rb b/test/unit/parsers/emacs_lisp.rb new file mode 100644 index 0000000..cb41b84 --- /dev/null +++ b/test/unit/parsers/emacs_lisp.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::EmacsLispTest < Ohcount::Test + + def test_comment + lb = [Ohcount::LanguageBreakdown.new("emacslisp", "", ";;comment", 0)] + assert_equal lb, Ohcount::parse(" ;;comment", "emacslisp") + end + + def test_comprehensive + verify_parse("el1.el") + end + + def test_comment_entities + assert_equal(';comment', entities_array(" ;comment", 'emacslisp', :comment).first) + end + +end + + diff --git a/test/unit/parsers/erlang_test.rb b/test/unit/parsers/erlang_test.rb new file mode 100644 index 0000000..52e5f0f --- /dev/null +++ b/test/unit/parsers/erlang_test.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::ErlangTest < Ohcount::Test + + def test_comment + lb = [Ohcount::LanguageBreakdown.new("erlang", "", "%%comment", 0)] + assert_equal lb, Ohcount::parse(" %%comment", "erlang") + end + + def test_comprehensive + verify_parse("erl1.erl") + end + + def test_comment_entities + assert_equal('%comment', entities_array(" %comment", 'erlang', :comment).first) + end + +end diff --git a/test/unit/parsers/exheres_test.rb b/test/unit/parsers/exheres_test.rb new file mode 100644 index 0000000..9bbe105 --- /dev/null +++ b/test/unit/parsers/exheres_test.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::ExheresTest < Ohcount::Test + def test_comprehensive + verify_parse("foo.exheres-0") + end + + def test_comment_entities + assert_equal('#comment', entities_array(" #comment", 'exheres', :comment).first) + end +end + diff --git a/test/unit/parsers/factor_test.rb b/test/unit/parsers/factor_test.rb new file mode 100644 index 0000000..086bc90 --- /dev/null +++ b/test/unit/parsers/factor_test.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::FactorTest < Ohcount::Test + + def test_comment + lb = [Ohcount::LanguageBreakdown.new("factor", "", "! comment", 0)] + assert_equal lb, Ohcount::parse(" ! comment", "factor") + end + + def test_strings + lb = [Ohcount::LanguageBreakdown.new("factor", "\"abc!not a 'comment\"", "", 0)] + assert_equal lb, Ohcount::parse("\"abc!not a 'comment\"", "factor") + end + + def test_comprehensive + verify_parse("factor1.factor") + end +end diff --git a/test/unit/parsers/fortran_test.rb b/test/unit/parsers/fortran_test.rb new file mode 100644 index 0000000..ef5f92e --- /dev/null +++ b/test/unit/parsers/fortran_test.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::FortranTest < Ohcount::Test + + def test_comprehensive + verify_parse("fortranfixed.f") + verify_parse("fortranfree.f") + end + + def test_comment_entities + assert_equal('!comment', entities_array(" !comment", 'fortranfree', :comment).first) + assert_equal('C comment', entities_array("C comment", 'fortranfixed', :comment).first) + end + +end diff --git a/test/unit/parsers/groovy_test.rb b/test/unit/parsers/groovy_test.rb new file mode 100644 index 0000000..f2e4386 --- /dev/null +++ b/test/unit/parsers/groovy_test.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::GroovyTest < Ohcount::Test + def test_comments + lb = [Ohcount::LanguageBreakdown.new("groovy", "", "//comment", 0)] + assert_equal lb, Ohcount::parse(" //comment", "groovy") + end + + def test_comprehensive + verify_parse("groovy1.groovy") + end + + def test_comment_entities + assert_equal('//comment', entities_array(" //comment", 'groovy', :comment).first) + assert_equal('/*comment*/', entities_array(" /*comment*/", 'groovy', :comment).first) + end + +end diff --git a/test/unit/parsers/haml_test.rb b/test/unit/parsers/haml_test.rb new file mode 100644 index 0000000..ae994cb --- /dev/null +++ b/test/unit/parsers/haml_test.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::HamlTest < Ohcount::Test + def test_line_comment + lb = [Ohcount::LanguageBreakdown.new("haml", "", "/ comment", 0)] + assert_equal lb, Ohcount::parse("/ comment", "haml") + end + + def test_element + lb2 = [Ohcount::LanguageBreakdown.new("haml", "%code", "", 0)] + assert_equal lb2, Ohcount::parse(" %code", "haml") + end + + def test_element_entities + assert_equal("%element", entities_array(" %element", 'haml', :element).first) + assert_equal(".class", entities_array(" .class", 'haml', :element_class).first) + assert_equal("#id", entities_array(" #id", 'haml', :element_id).first) + end + + def test_comprehensive + verify_parse("haml.haml") + end +end diff --git a/test/unit/parsers/haskell_test.rb b/test/unit/parsers/haskell_test.rb new file mode 100644 index 0000000..4e47904 --- /dev/null +++ b/test/unit/parsers/haskell_test.rb @@ -0,0 +1,25 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::HaskellTest < Ohcount::Test + def test_comments + lb = [Ohcount::LanguageBreakdown.new("haskell", "", "--comment", 0)] + assert_equal lb, Ohcount::parse(" --comment", "haskell") + end + + def test_comprehensive + verify_parse("haskell1.hs") + end + + def test_comprehensive_with_carriage_returns + verify_parse("haskell2.hs") + end + + def test_comprehensive_with_nested_comments + verify_parse("haskell3.hs") + end + + def test_comment_entities + assert_equal('--comment', entities_array(" --comment", 'haskell', :comment).first) + assert_equal('{-comment-}', entities_array(" {-comment-}", 'haskell', :comment).first) + end +end diff --git a/test/unit/parsers/haxe_test.rb b/test/unit/parsers/haxe_test.rb new file mode 100644 index 0000000..a5918c8 --- /dev/null +++ b/test/unit/parsers/haxe_test.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::HaxeTest < Ohcount::Test + def test_comments + lb = [Ohcount::LanguageBreakdown.new("haxe", "", "//comment", 0)] + assert_equal lb, Ohcount::parse(" //comment", "haxe") + end + + def test_comprehensive + verify_parse("haxe1.hx") + end + + def test_comment_entities + assert_equal('//comment', entities_array(' //comment', 'haxe', :comment).first) + assert_equal('/*comment*/', entities_array(' /*comment*/', 'haxe', :comment).first) + end +end diff --git a/test/unit/parsers/html_test.rb b/test/unit/parsers/html_test.rb new file mode 100644 index 0000000..cbadbd1 --- /dev/null +++ b/test/unit/parsers/html_test.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::HtmlTest < Ohcount::Test + def test_comprehensive + verify_parse("html1.html") + end + + def test_comment_entities + assert_equal('', entities_array(" ", 'html', :comment).first) + assert_equal('/*comment*/', entities_array("", 'html', :comment).first) + assert_equal('//comment', entities_array("", 'html', :comment).first) + assert_equal('/*comment*/', entities_array("", 'html', :comment).first) + end +end diff --git a/test/unit/parsers/java_test.rb b/test/unit/parsers/java_test.rb new file mode 100644 index 0000000..1951b51 --- /dev/null +++ b/test/unit/parsers/java_test.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::JavaTest < Ohcount::Test + def test_comments + lb = [Ohcount::LanguageBreakdown.new("java", "", "//comment", 0)] + assert_equal lb, Ohcount::parse(" //comment", "java") + end + + def test_comprehensive + verify_parse("java1.java") + end + + def test_comprehensive_with_carriage_returns + verify_parse("java2.java") + end + + def test_comment_entities + assert_equal('//comment', entities_array(" //comment", 'java', :comment).first) + assert_equal('/*comment*/', entities_array(" /*comment*/", 'java', :comment).first) + end +end diff --git a/test/unit/parsers/javascript_test.rb b/test/unit/parsers/javascript_test.rb new file mode 100644 index 0000000..e655179 --- /dev/null +++ b/test/unit/parsers/javascript_test.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::JavascriptTest < Ohcount::Test + def test_comments + lb = [Ohcount::LanguageBreakdown.new("javascript", "", "//comment", 0)] + assert_equal lb, Ohcount::parse(" //comment", "javascript") + end + + def test_comprehensive + verify_parse("js1.js") + end + + def test_comp2 + verify_parse("js2.js") + end + + def test_comment_entities + assert_equal('//comment', entities_array(" //comment", 'javascript', :comment).first) + assert_equal('/*comment*/', entities_array(" /*comment*/", 'javascript', :comment).first) + end + +end diff --git a/test/unit/parsers/jsp_test.rb b/test/unit/parsers/jsp_test.rb new file mode 100644 index 0000000..1d0e037 --- /dev/null +++ b/test/unit/parsers/jsp_test.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::JspTest < Ohcount::Test + def test_comment + html_lb = Ohcount::LanguageBreakdown.new("html", "%>", "", 0) + java_lb = Ohcount::LanguageBreakdown.new("java", "", "<% //comment\n", 0) + assert_equal [java_lb, html_lb], Ohcount::parse(" <% //comment\n%>", "jsp") + end + + def test_comprehensive + verify_parse("jsp1.jsp") + end + + def test_comment_entities + assert_equal('', entities_array(" ", 'jsp', :comment).first) + assert_equal('/*comment*/', entities_array("", 'jsp', :comment).first) + assert_equal('//comment', entities_array("<%\n//comment\n%>", 'jsp', :comment).first) + assert_equal('/*comment*/', entities_array("<%\n/*comment*/\n%>", 'jsp', :comment).first) + end +end diff --git a/test/unit/parsers/lisp_test.rb b/test/unit/parsers/lisp_test.rb new file mode 100644 index 0000000..fb7b8e2 --- /dev/null +++ b/test/unit/parsers/lisp_test.rb @@ -0,0 +1,38 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::LispTest < Ohcount::Test + + def test_comment + lb = [Ohcount::LanguageBreakdown.new("lisp", "", ";;; comment", 0)] + assert_equal lb, Ohcount::parse(" ;;; comment", "lisp") + end + + def test_doc_string + lb = [Ohcount::LanguageBreakdown.new("lisp", "", '""" comment """', 0)] + assert_equal lb, Ohcount::parse(' """ comment """', "lisp") + end + + def test_doc_string_blank + lb = [Ohcount::LanguageBreakdown.new("lisp", "", '""""""', 0)] + assert_equal lb, Ohcount::parse(' """"""', "lisp") + end + + def test_empty_string + lb = [Ohcount::LanguageBreakdown.new("lisp", '""', "", 0)] + assert_equal lb, Ohcount::parse(' ""', "lisp") + end + + def test_char_string + lb = [Ohcount::LanguageBreakdown.new("lisp", '"a"', "", 0)] + assert_equal lb, Ohcount::parse(' "a"', "lisp") + end + + def test_comprehensive + verify_parse("lsp1.lsp") + end + + def test_comment_entities + assert_equal(';comment', entities_array(" ;comment", 'lisp', :comment).first) + end + +end diff --git a/test/unit/parsers/lua_test.rb b/test/unit/parsers/lua_test.rb new file mode 100644 index 0000000..786f0c9 --- /dev/null +++ b/test/unit/parsers/lua_test.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::LuaTest < Ohcount::Test + + def test_comment + lb = [Ohcount::LanguageBreakdown.new("lua", "", "-- comment", 0)] + assert_equal lb, Ohcount::parse(" -- comment", "lua") + end + + def test_comprehensive + verify_parse("lua1.lua") + end + + def test_comment_entities + assert_equal('--comment', entities_array(" --comment", 'lua', :comment).first) + assert_equal("--[[comment\ncomment]]", entities_array(" --[[comment\ncomment]]", 'lua', :comment).first) + end + +end diff --git a/test/unit/parsers/make_test.rb b/test/unit/parsers/make_test.rb new file mode 100644 index 0000000..fc705fe --- /dev/null +++ b/test/unit/parsers/make_test.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::MakefileTest < Ohcount::Test + def test_comprehensive + verify_parse("Makefile") + end + + def test_comment_entities + assert_equal('#comment', entities_array(" #comment", 'make', :comment).first) + end + +end + diff --git a/test/unit/parsers/matlab_test.rb b/test/unit/parsers/matlab_test.rb new file mode 100644 index 0000000..dbbe9a0 --- /dev/null +++ b/test/unit/parsers/matlab_test.rb @@ -0,0 +1,30 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::MatlabTest < Ohcount::Test + + def test_line_comment_1 + lb = [Ohcount::LanguageBreakdown.new("matlab", "", "%comment", 0)] + assert_equal lb, Ohcount::parse(" %comment", "matlab") + end + + def test_octave_syntax_comment + lb = [Ohcount::LanguageBreakdown.new("matlab", "", "#comment", 0)] + assert_equal lb, Ohcount::parse(" #comment", "matlab") + end + + def test_false_line_comment + lb = [Ohcount::LanguageBreakdown.new("matlab", "%{block%} code", "", 0)] + assert_equal lb, Ohcount::parse(" %{block%} code", "matlab") + end + + def test_comprehensive + verify_parse("matlab1.m", 'matlab') + end + + def test_comment_entities + assert_equal('%comment', entities_array(" %comment", 'matlab', :comment).first) + assert_equal('#comment', entities_array(" #comment", 'matlab', :comment).first) + assert_equal('%{comment%}', entities_array(" %{comment%}", 'matlab', :comment).first) + end + +end diff --git a/test/unit/parsers/metafont_test.rb b/test/unit/parsers/metafont_test.rb new file mode 100644 index 0000000..d316c89 --- /dev/null +++ b/test/unit/parsers/metafont_test.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::MetaFontTest < Ohcount::Test + def test_comment + lb = [Ohcount::LanguageBreakdown.new("metafont", "", "% comment", 0)] + assert_equal lb, Ohcount::parse(" % comment", "metafont") + end + + def test_comprehensive + verify_parse("metafont.mf") + end + + def test_comment_entities + assert_equal('%comment', entities_array(" %comment", 'metafont', :comment).first) + end +end diff --git a/test/unit/parsers/metapost_test.rb b/test/unit/parsers/metapost_test.rb new file mode 100644 index 0000000..45a6c04 --- /dev/null +++ b/test/unit/parsers/metapost_test.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::MetaPostTest < Ohcount::Test + def test_comment + lb = [Ohcount::LanguageBreakdown.new("metapost", "", "% comment", 0)] + assert_equal lb, Ohcount::parse(" % comment", "metapost") + end + + def test_comprehensive + verify_parse("metapost.mp") + end + + def test_comment_entities + assert_equal('%comment', entities_array(" %comment", 'metapost', :comment).first) + assert_equal('%comment', entities_array("verbatim\n%comment\netex", 'metapost', :comment).first) + end +end diff --git a/test/unit/parsers/mxml_test.rb b/test/unit/parsers/mxml_test.rb new file mode 100644 index 0000000..09411c8 --- /dev/null +++ b/test/unit/parsers/mxml_test.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::MxmlTest < Ohcount::Test + def test_comprehensive + verify_parse("mxml1.mxml") + end + + def test_comment_entities + assert_equal('', entities_array(" ", 'mxml', :comment).first) + assert_equal('/*comment*/', entities_array("\n/*comment*/\n", 'mxml', :comment).first) + assert_equal('//comment', entities_array("\n//comment\n", 'mxml', :comment).first) + assert_equal('/*comment*/', entities_array("\n/*comment*/\n", 'mxml', :comment).first) + end +end diff --git a/test/unit/parsers/ocaml_test.rb b/test/unit/parsers/ocaml_test.rb new file mode 100644 index 0000000..29a0c5b --- /dev/null +++ b/test/unit/parsers/ocaml_test.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::OcamlTest < Ohcount::Test + def test_regular_comments + lb = [Ohcount::LanguageBreakdown.new("ocaml", "", "(* comment *)", 0)] + assert_equal lb, Ohcount::parse(" (* comment *)", "ocaml") + end + + def test_comprehensive + verify_parse("ocaml.ml") + end + + def test_comment_entities + assert_equal('(*comment*)', entities_array(" (*comment*)", 'ocaml', :comment).first) + end + +end diff --git a/test/unit/parsers/pascal_test.rb b/test/unit/parsers/pascal_test.rb new file mode 100644 index 0000000..1326282 --- /dev/null +++ b/test/unit/parsers/pascal_test.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::PascalTest < Ohcount::Test + def test_comment + lb = [Ohcount::LanguageBreakdown.new("pascal", "", "//comment", 0)] + assert_equal lb, Ohcount::parse(" //comment", "pascal") + end + + def test_comprehensive + verify_parse("pascal1.pas") + verify_parse("pascal2.pp") + end + + def test_comment_entities + assert_equal('//comment', entities_array(" //comment", 'pascal', :comment).first) + assert_equal('(*comment*)', entities_array(" (*comment*)", 'pascal', :comment).first) + assert_equal('{comment}', entities_array(" {comment}", 'pascal', :comment).first) + end +end diff --git a/test/unit/parsers/perl_test.rb b/test/unit/parsers/perl_test.rb new file mode 100644 index 0000000..ababb19 --- /dev/null +++ b/test/unit/parsers/perl_test.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::PerlTest < Ohcount::Test + def test_comments + lb = [Ohcount::LanguageBreakdown.new("perl", "", "#comment", 0)] + assert_equal lb, Ohcount::parse(" #comment", "perl") + end + + def test_perl_in_cgi + verify_parse("perl.cgi") + end + + def test_comprehensive + verify_parse("perl1.pl") + verify_parse("perl_module.pm") + verify_parse("perl_pod_to_eof.pl") # Verifies ticket #267 + end + + def test_comment_entities + assert_equal('#comment', entities_array(" #comment", 'perl', :comment).first) + assert_equal("=head1\ncomment\n=cut", entities_array("=head1\ncomment\n=cut", 'perl', :comment).first) + end +end diff --git a/test/unit/parsers/php_test.rb b/test/unit/parsers/php_test.rb new file mode 100644 index 0000000..78895ce --- /dev/null +++ b/test/unit/parsers/php_test.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::PhpTest < Ohcount::Test + def test_comment + lbhtml = Ohcount::LanguageBreakdown.new("html", "", "", 0) + lbphp = Ohcount::LanguageBreakdown.new("php", "", "//comment\n", 0) + assert_equal [lbhtml, lbphp], Ohcount::parse("", "php") + end + + def test_comprehensive + verify_parse("php1.php") + end + + def test_comment_entities + assert_equal('// comment', entities_array("\n", 'php', :comment).first) + assert_equal('/* comment */', entities_array("\n", 'php', :comment).first) + end +end diff --git a/test/unit/parsers/pike_test.rb b/test/unit/parsers/pike_test.rb new file mode 100644 index 0000000..c9714c7 --- /dev/null +++ b/test/unit/parsers/pike_test.rb @@ -0,0 +1,26 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::PikeTest < Ohcount::Test + def test_comments + lb = [Ohcount::LanguageBreakdown.new("pike", "", "//comment", 0)] + assert_equal lb, Ohcount::parse(" //comment", "pike") + end + + def test_comments2 + lb = [Ohcount::LanguageBreakdown.new("pike", "", "/*comment*/", 0)] + assert_equal lb, Ohcount::parse(" /*comment*/", "pike") + end + + def test_comprehensive + verify_parse("pike1.pike") + end + + def test_comprehensive_pmod + verify_parse("pike2.pmod") + end + + def test_comment_entities + assert_equal('//comment', entities_array(" //comment", 'pike', :comment).first) + assert_equal('/*comment*/', entities_array(" /*comment*/", 'pike', :comment).first) + end +end diff --git a/test/unit/parsers/python_test.rb b/test/unit/parsers/python_test.rb new file mode 100644 index 0000000..12a04d0 --- /dev/null +++ b/test/unit/parsers/python_test.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::PythonTest < Ohcount::Test + def test_comment + lb = [Ohcount::LanguageBreakdown.new("python", "", "#comment", 0)] + assert_equal lb, Ohcount::parse(" #comment", "python") + end + + def test_doc_comment + lb = [Ohcount::LanguageBreakdown.new("python", "", "'''\ndoc comment\n'''", 0)] + assert_equal lb, Ohcount::parse(" '''\n doc comment\n '''", "python") + end + + def test_strings + lb = [Ohcount::LanguageBreakdown.new("python", "\"abc#not a 'comment\"", "", 0)] + assert_equal lb, Ohcount::parse("\"abc#not a 'comment\"", "python") + end + + def test_comprehensive + verify_parse("py1.py") + end + + def test_comment_entities + assert_equal('#comment', entities_array(" #comment", 'python', :comment).first) + assert_equal('"""comment"""', entities_array(" \"\"\"comment\"\"\"", 'python', :comment).first) + end +end diff --git a/test/unit/parsers/r_test.rb b/test/unit/parsers/r_test.rb new file mode 100644 index 0000000..f86f75c --- /dev/null +++ b/test/unit/parsers/r_test.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::RTest < Ohcount::Test + + def test_line_comment_1 + lb = [Ohcount::LanguageBreakdown.new("r", "", "#comment", 0)] + assert_equal lb, Ohcount::parse(" #comment", "r") + end + + def test_comprehensive + verify_parse("example.R", 'r') + end + + def test_comment_entities + assert_equal('#comment', entities_array(" #comment", 'r', :comment).first) + end + +end diff --git a/test/unit/parsers/rexx_test.rb b/test/unit/parsers/rexx_test.rb new file mode 100644 index 0000000..3c7f7f4 --- /dev/null +++ b/test/unit/parsers/rexx_test.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::RexxTest < Ohcount::Test + + def test_comment + lb = [Ohcount::LanguageBreakdown.new("rexx", "", "/*comment*/", 0)] + assert_equal lb, Ohcount::parse(" /*comment*/", "rexx") + end + + def test_comprehensive + verify_parse("rexx1.rex") + end + + def test_comment_entities + assert_equal('/*comment*/', entities_array(" /*comment*/", 'rexx', :comment).first) + end + +end diff --git a/test/unit/parsers/rhtml_test.rb b/test/unit/parsers/rhtml_test.rb new file mode 100644 index 0000000..737e8fc --- /dev/null +++ b/test/unit/parsers/rhtml_test.rb @@ -0,0 +1,24 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::RhtmlTest < Ohcount::Test + + def test_comment + html_lb = Ohcount::LanguageBreakdown.new("html", "<%\n%>", "", 0) + ruby_lb = Ohcount::LanguageBreakdown.new("ruby", "", "#comment\n", 0) + assert_equal [html_lb, ruby_lb], Ohcount::parse("<%\n #comment\n%>", "rhtml") + end + + def test_comprehensive + verify_parse("rhtml1.rhtml") + end + + def test_comment_entities + assert_equal('', entities_array(" ", 'rhtml', :comment).first) + assert_equal('/*comment*/', entities_array("", 'rhtml', :comment).first) + assert_equal('//comment', entities_array("", 'rhtml', :comment).first) + assert_equal('/*comment*/', entities_array("", 'rhtml', :comment).first) + assert_equal('#comment', entities_array("<%\n#comment\n%>", 'rhtml', :comment).first) + assert_equal("=begin\ncomment\n=end", entities_array("<%\n=begin\ncomment\n=end\n%>", 'rhtml', :comment).first) + end + +end diff --git a/test/unit/parsers/ruby_test.rb b/test/unit/parsers/ruby_test.rb new file mode 100644 index 0000000..4d5768f --- /dev/null +++ b/test/unit/parsers/ruby_test.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::RubyTest < Ohcount::Test + + def test_comment + lb = [Ohcount::LanguageBreakdown.new("ruby", "", "#comment", 0)] + assert_equal lb, Ohcount::parse(" #comment", "ruby") + end + + def test_comprehensive + verify_parse("ruby1.rb") + end + + def test_comment_entities + assert_equal('#comment', entities_array(" #comment", 'ruby', :comment).first) + assert_equal("=begin\ncomment\n=end", entities_array("=begin\ncomment\n=end", 'ruby', :comment).first) + end + +end diff --git a/test/unit/parsers/scala_test.rb b/test/unit/parsers/scala_test.rb new file mode 100644 index 0000000..4d5521e --- /dev/null +++ b/test/unit/parsers/scala_test.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::ScalaTest < Ohcount::Test + + def test_comprehensive + verify_parse("scala1.scala") + end + + def test_comment_entities + assert_equal('//comment', entities_array(" //comment", 'scala', :comment).first) + assert_equal('/*comment*/', entities_array(" /*comment*/", 'scala', :comment).first) + end + +end diff --git a/test/unit/parsers/scheme_test.rb b/test/unit/parsers/scheme_test.rb new file mode 100644 index 0000000..51ae671 --- /dev/null +++ b/test/unit/parsers/scheme_test.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::SchemeTest < Ohcount::Test + + def test_comment + lb = [Ohcount::LanguageBreakdown.new("scheme", "", ";;; comment", 0)] + assert_equal lb, Ohcount::parse(" ;;; comment", "scheme") + end + + def test_comprehensive + verify_parse("scheme.scm") + end + + def test_comment_entities + assert_equal(';comment', entities_array(" ;comment", 'scheme', :comment).first) + end + +end diff --git a/test/unit/parsers/shell_test.rb b/test/unit/parsers/shell_test.rb new file mode 100644 index 0000000..666be08 --- /dev/null +++ b/test/unit/parsers/shell_test.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::ShellTest < Ohcount::Test + def test_comment + lb = [Ohcount::LanguageBreakdown.new("shell", "", "#comment", 0)] + assert_equal lb, Ohcount::parse(" #comment", "shell") + end + + def test_comprehensive + verify_parse("sh1.sh") + end + + def test_comment_entities + assert_equal('#comment', entities_array(" #comment", 'shell', :comment).first) + end +end diff --git a/test/unit/parsers/smalltalk_test.rb b/test/unit/parsers/smalltalk_test.rb new file mode 100644 index 0000000..13e624a --- /dev/null +++ b/test/unit/parsers/smalltalk_test.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::SmalltalkTest < Ohcount::Test + + def test_comment + lb = [Ohcount::LanguageBreakdown.new("smalltalk", "", '"comment\\"', 0)] + assert_equal lb, Ohcount::parse(' "comment\\"', "smalltalk") + end + + def test_comprehensive + verify_parse("smalltalk1.st") + end + + def test_comment_entities + assert_equal('"comment"', entities_array(" \"comment\"", 'smalltalk', :comment).first) + end + +end diff --git a/test/unit/parsers/sql_test.rb b/test/unit/parsers/sql_test.rb new file mode 100644 index 0000000..59e13c5 --- /dev/null +++ b/test/unit/parsers/sql_test.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::SqlTest < Ohcount::Test + + def test_comments + lb = [Ohcount::LanguageBreakdown.new("sql", "", "--comment", 0)] + assert_equal lb, Ohcount::parse(" --comment", "sql") + end + + def test_empty_comments + lb = [Ohcount::LanguageBreakdown.new("sql", "","--\n", 0)] + assert_equal lb, Ohcount::parse(" --\n", "sql") + end + + def test_block_comment + lb = [Ohcount::LanguageBreakdown.new("sql", "","{sql}", 0)] + assert_equal lb, Ohcount::parse(" {sql}", "sql") + end + + def test_comprehensive + verify_parse("sql1.sql") + end + + def test_comment_entities + assert_equal('--comment', entities_array(" --comment", 'sql', :comment).first) + assert_equal('#comment', entities_array(" #comment", 'sql', :comment).first) + assert_equal('//comment', entities_array(" //comment", 'sql', :comment).first) + assert_equal('/*comment*/', entities_array(" /*comment*/", 'sql', :comment).first) + assert_equal('{comment}', entities_array(" {comment}", 'sql', :comment).first) + end + +end diff --git a/test/unit/parsers/stratego_test.rb b/test/unit/parsers/stratego_test.rb new file mode 100644 index 0000000..2d33e67 --- /dev/null +++ b/test/unit/parsers/stratego_test.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::StrategoTest < Ohcount::Test + def test_line_comments + lb = [Ohcount::LanguageBreakdown.new("stratego", "", "// comment", 0)] + assert_equal lb, Ohcount::parse("// comment", "stratego") + end + + def test_comprehensive + verify_parse("stratego.str") + end + + def test_char_string_entities + assert_equal("'c'", entities_array(" 'c'", 'stratego', :string).first) + # single quote can be used in identiiers + # weak case + assert_not_equal(" c'", entities_array(" c'", 'stratego', :string).first) + # strong case + assert_not_equal("' = e'", entities_array(" c' = e'", 'stratego', :string).first) + end + +end diff --git a/test/unit/parsers/tcl_test.rb b/test/unit/parsers/tcl_test.rb new file mode 100644 index 0000000..17c0f1c --- /dev/null +++ b/test/unit/parsers/tcl_test.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::TclTest < Ohcount::Test + def test_comment + lb = [Ohcount::LanguageBreakdown.new("tcl", "", "#comment", 0)] + assert_equal lb, Ohcount::parse(" #comment", "tcl") + end + + def test_comprehensive + verify_parse("tcl1.tcl") + end + + def test_comment_entities + assert_equal('#comment', entities_array(" #comment", 'tcl', :comment).first) + end +end diff --git a/test/unit/parsers/tex_test.rb b/test/unit/parsers/tex_test.rb new file mode 100644 index 0000000..0d4d436 --- /dev/null +++ b/test/unit/parsers/tex_test.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::TeXTest < Ohcount::Test + + def test_comment + lb = [Ohcount::LanguageBreakdown.new("tex", "", "%comment", 0)] + assert_equal lb, Ohcount::parse(" %comment", "tex") + end + + def test_comprehensive + verify_parse("foo.tex") + end + + def test_comment_entities + assert_equal('%comment', entities_array(" %comment", 'tex', :comment).first) + end +end diff --git a/test/unit/parsers/vala_test.rb b/test/unit/parsers/vala_test.rb new file mode 100644 index 0000000..a80b3fd --- /dev/null +++ b/test/unit/parsers/vala_test.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::ValaTest < Ohcount::Test + + def test_comment + lb = [Ohcount::LanguageBreakdown.new("vala", "", "//comment", 0)] + assert_equal lb, Ohcount::parse(" //comment", "vala") + end + + def test_comprehensive + verify_parse("vala1.vala") + end + + def test_comment_entities + assert_equal('//comment', entities_array(" //comment", 'vala', :comment).first) + assert_equal('/*comment*/', entities_array(" /*comment*/", 'vala', :comment).first) + end +end diff --git a/test/unit/parsers/vhdl_test.rb b/test/unit/parsers/vhdl_test.rb new file mode 100644 index 0000000..69d7da2 --- /dev/null +++ b/test/unit/parsers/vhdl_test.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::VHDLTest < Ohcount::Test + def test_comment + lb = [Ohcount::LanguageBreakdown.new("vhdl", "", "-- comment", 0)] + assert_equal lb, Ohcount::parse(" -- comment", "vhdl") + end + + def test_comprehensive + verify_parse("vhdl1.vhd") + end + + def test_comment_entities + assert_equal('--comment', entities_array(" --comment", 'vhdl', :comment).first) + end +end diff --git a/test/unit/parsers/vim_test.rb b/test/unit/parsers/vim_test.rb new file mode 100644 index 0000000..40dd080 --- /dev/null +++ b/test/unit/parsers/vim_test.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::VimTest < Ohcount::Test + def test_comprehensive + verify_parse("foo.vim") + end +end diff --git a/test/unit/parsers/visual_basic_test.rb b/test/unit/parsers/visual_basic_test.rb new file mode 100644 index 0000000..5d99ea0 --- /dev/null +++ b/test/unit/parsers/visual_basic_test.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::VisualBasicTest < Ohcount::Test + def test_comments + lb = [Ohcount::LanguageBreakdown.new("visualbasic", "", "'comment", 0)] + assert_equal lb, Ohcount::parse(" 'comment", "visualbasic") + end + + def test_comprehensive + verify_parse("frx1.frx") + end + + def test_comment_entities + assert_equal('\'comment', entities_array(" 'comment", 'visualbasic', :comment).first) + assert_equal('Rem comment', entities_array(" Rem comment", 'visualbasic', :comment).first) + end +end diff --git a/test/unit/parsers/xml_test.rb b/test/unit/parsers/xml_test.rb new file mode 100644 index 0000000..280b782 --- /dev/null +++ b/test/unit/parsers/xml_test.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::XmlTest < Ohcount::Test + def test_comment + lb = [Ohcount::LanguageBreakdown.new("xml", "", "", 0)] + assert_equal lb, Ohcount::parse(" ", "xml") + end + + def test_comprehensive + verify_parse("xml1.xml") + end + + def test_comment_entities + assert_equal('', entities_array(" ", 'xml', :comment).first) + end +end diff --git a/test/unit/parsers/xmlschema_test.rb b/test/unit/parsers/xmlschema_test.rb new file mode 100644 index 0000000..5ff20ca --- /dev/null +++ b/test/unit/parsers/xmlschema_test.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::XMLSchemaTest < Ohcount::Test + def test_comment + lb = [Ohcount::LanguageBreakdown.new("xmlschema", "", "", 0)] + assert_equal lb, Ohcount::parse(" ", "xmlschema") + end + + def test_comprehensive + verify_parse("schema.xsd") + end + + def test_comment_entities + assert_equal('', entities_array(" ", 'xmlschema', :comment).first) + end +end diff --git a/test/unit/parsers/xslt_test.rb b/test/unit/parsers/xslt_test.rb new file mode 100644 index 0000000..b519252 --- /dev/null +++ b/test/unit/parsers/xslt_test.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::XsltTest < Ohcount::Test + def test_comment + lb = [Ohcount::LanguageBreakdown.new("xslt", "", "", 0)] + assert_equal lb, Ohcount::parse(" ", "xslt") + end + + def test_comprehensive + verify_parse("example.xsl") + end + + def test_comment_entities + assert_equal('', entities_array(" ", 'xslt', :comment).first) + end +end diff --git a/test/unit/source_file_test.rb b/test/unit/source_file_test.rb new file mode 100644 index 0000000..31059d4 --- /dev/null +++ b/test/unit/source_file_test.rb @@ -0,0 +1,34 @@ +require File.dirname(__FILE__) + '/../test_helper' +include Ohcount + +class SourceFileTest < Ohcount::Test + + def test_initialize + assert SourceFile.new("foo.rb") + end + + def test_contents + contents = "foobar" + f = SourceFile.new("foo.rb", :contents => contents) + assert_equal contents, f.contents + end + + def test_languages + contents = "x = 5" + f = SourceFile.new("foo.rb", :contents => contents) + assert_equal [:ruby], f.languages + assert_equal({:code => contents}, f.ruby) + assert_equal contents, f.ruby.code + end + + def test_parse + ruby_code = '' + contents = "x = 5" + f = SourceFile.new("foo.rb", :contents => contents) + f.parse do |l, s, line| + ruby_code << line if l == :ruby && s == :code + end + assert_equal contents, ruby_code + end +end + From 227761df5e9faab13ee34d526e837d4c00088e2d Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Thu, 6 Nov 2008 12:17:20 -0800 Subject: [PATCH 018/387] [INTERIM] More gestalt and cleanup --- bin/ohcount | 123 ++++--- ext/ohcount_native/language_breakdown.c | 24 +- ext/ohcount_native/language_breakdown.h | 6 +- ext/ohcount_native/ragel_parser.c | 4 +- ext/ohcount_native/ruby_binding.c | 122 +++++-- lib/detector/base.rb | 578 -------------------------------- lib/gestalt/base.rb | 4 +- lib/gestalt/library.rb | 4 + lib/gestalt/library_rule.rb | 25 +- lib/gestalt/platform.rb | 68 +++- lib/ohcount.rb | 11 +- lib/ohcount/detector.rb | 576 +++++++++++++++++++++++++++++++ lib/ohcount/gestalt_facts.rb | 58 ++++ lib/ohcount/helpers.rb | 12 + lib/ohcount/language_breakdown.rb | 21 +- lib/ohcount/language_facts.rb | 46 +++ lib/ohcount/source_file.rb | 40 +-- lib/ohcount/source_file_list.rb | 83 +++++ rules/libraries.rb | 8 + rules/platforms.rb | 7 + test/gestalt_files/test_cakephp/foo.php | 5 + test/unit/gestalt/platform_test.rb | 66 ++-- test/unit/language_breakdown_test.rb | 12 + test/unit/source_file_list_test.rb | 37 ++ test/unit/source_file_test.rb | 7 +- 25 files changed, 1157 insertions(+), 790 deletions(-) delete mode 100644 lib/detector/base.rb create mode 100644 lib/ohcount/detector.rb create mode 100644 lib/ohcount/gestalt_facts.rb create mode 100644 lib/ohcount/helpers.rb create mode 100644 lib/ohcount/language_facts.rb create mode 100644 lib/ohcount/source_file_list.rb create mode 100644 test/gestalt_files/test_cakephp/foo.php create mode 100644 test/unit/language_breakdown_test.rb create mode 100644 test/unit/source_file_list_test.rb diff --git a/bin/ohcount b/bin/ohcount index 847d8bd..965f4eb 100755 --- a/bin/ohcount +++ b/bin/ohcount @@ -18,15 +18,23 @@ class OhcountCommandLine self.paths = args end + def source_file_list + @source_file_list ||= Ohcount::SourceFileList.new(:paths => paths) + end + def paths - @paths || [] + @paths.empty? ? ['.'] : @paths end def paths=(p) @paths=p - @files = nil # If we change the search paths, clear the cache filenames + # If we change the search paths, clear the cached filenames + @files = @source_file_list = nil end + # + # TO DEPRECATE BEGIN + # def files return @files if @files @@ -48,10 +56,12 @@ class OhcountCommandLine array << path end end + # + # TO DEPRECATE END + # def annotate - files.each do |file| - s = Ohcount::SourceFile.new(file, :filenames => files) + source_file_list.each_source_file do |s| s.parse do |language, semantic, line| puts "#{language}\t#{semantic}\t#{line}" end @@ -60,34 +70,47 @@ class OhcountCommandLine # Find all source code files def detect - files.each do |file| - s = Ohcount::SourceFile.new(file, :filenames => files) - puts "#{s.polyglot}\t#{file}" if s.polyglot + source_file_list.each_source_file do |s| + puts "#{s.polyglot}\t#{s.filename}" if s.polyglot end end # Licenses def licenses - files.each do |file| - s = Ohcount::SourceFile.new(file, :filenames => files) + source_file_list.each_source_file do |s| next unless s.licenses.any? - symbols = licenses.collect { |l| LicenseSniffer::LicenseMap.instance.map[l].symbol }.join(",") - puts "#{symbols}\t#{file}" - end + symbols = s.licenses.collect { |l| LicenseSniffer::LicenseMap.instance.map[l].symbol }.join(",") + puts "#{symbols}\t#{s.filename}" + end end + def analyze_with_progress(what) + count = 0 + source_file_list.analyze(what) do |s| + if count % 100 == 0 + STDOUT.write('.') + STDOUT.flush + end + count+=1 + end + puts "\n" + end + + def write_platforms + platforms = source_file_list.gestalt_facts.platforms + platforms = platforms.any? ? platforms.collect { |p| p.to_s }.join(", ") : 'None' + puts "Platforms detected: #{ platforms }" + end + # Gestalt def gestalt - g = Ohcount::Gestalt::Base.new(:files => files) - puts "processing #{files.size} files... (this could take a while)" - g.process! - platforms = g.platforms.any? ? g.platforms.collect { |p| p.to_s }.join(", ") : 'None' - puts "Platforms detected: #{ platforms }" + analyze_with_progress(:gestalt) + write_platforms end def raw_entities - files.each do |file| - Ohcount::SourceFile.new(file, :filenames => files).raw_entities do |language, entity, s, e| + source_file_list.each_source_file do |s| + s.raw_entities do |language, entity, s, e| puts "#{language}\t#{entity}\t#{s}\t#{e}" end end @@ -163,20 +186,9 @@ HELP puts "Language Code Comment Comment % Blank Total File" puts "-------------- --------- --------- --------- --------- --------- -----------------------------------------------" - files.each do |file| - counts = {} - languages_found=[] - s = Ohcount::SourceFile.new(file, :filenames => files) - if s.source_code? - s.parse do |language_name, semantic, line| - counts[language_name] ||={:code => 0, :comment => 0, :blank => 0} - counts[language_name][semantic] += 1 - languages_found << language_name unless languages_found.include?(language_name) - end - end - - counts.keys.sort{ |a,b| counts[b][:code] <=> counts[a][:code] }.each do |key| - write_individual_row(file, key, counts[key][:code],counts[key][:comment],counts[key][:blank]) + source_file_list.analyze(:language) do |s| + s.language_breakdowns.sort {|l1,l2| l2.name <=> l1.name}.each do |lb| + write_individual_row(s.filename, lb.name, lb.code_count, lb.comment_count, lb.blanks) end end end @@ -203,34 +215,10 @@ HELP end end - def summary - STDOUT.write "Examining #{files.size} file(s)" - - counts = {} - any_language_file_count = 0 - progress = 0 - - files.each do |file| - languages_found = [] - Ohcount::SourceFile.new(file, :filenames => files).parse do |language_name, semantic, line| - counts[language_name] ||= {:code => 0, :comment => 0, :blank => 0} - counts[language_name][semantic] += 1 - languages_found << language_name unless languages_found.include?(language_name) - end - - # Keep a running total of the number of files that include a specific language - languages_found.each { |l| counts[l][:files] = (counts[l][:files] || 0) + 1 } - - # Keep a running total of the number of files that include any language - any_language_file_count += 1 if languages_found.any? + STDOUT.write "Examining #{source_file_list.size} file(s)" - progress += 1 - if (progress % 100 == 0) - STDOUT.write('.') - STDOUT.flush - end - end + analyze_with_progress(:*) puts puts "Ohloh Line Count Summary".center(76) @@ -239,15 +227,20 @@ HELP puts "Language Files Code Comment Comment % Blank Total" puts "-------------- ----- --------- --------- --------- --------- ---------" - counts.keys.sort{ |a,b| counts[b][:code] <=> counts[a][:code] }.each do |key| - write_summary_row(key, counts[key][:files], counts[key][:code], counts[key][:comment], counts[key][:blank]) + language_facts = source_file_list.language_facts + language_facts.fact_map.values.sort { |a,b| b.code <=> a.code}.each do |lf| + write_summary_row(lf.language, lf.filecount, lf.code, lf.comments, lf.blanks) end puts "-------------- ----- --------- --------- --------- --------- ---------" - write_summary_row('Total', any_language_file_count, - counts.values.inject(0) { |sum, v| sum + v[:code] }, - counts.values.inject(0) { |sum, v| sum + v[:comment] }, - counts.values.inject(0) { |sum, v| sum + v[:blank] }) + write_summary_row('Total', language_facts.filecount, + language_facts.code, + language_facts.comments, + language_facts.blanks) + + + puts + write_platforms end def write_summary_row(name, file_count, code, comment, blank) diff --git a/ext/ohcount_native/language_breakdown.c b/ext/ohcount_native/language_breakdown.c index 2a5ffc3..39b0977 100644 --- a/ext/ohcount_native/language_breakdown.c +++ b/ext/ohcount_native/language_breakdown.c @@ -1,12 +1,6 @@ /* * language_breakdown.c - * Ohcount - * - * Created by Jason Allen on 6/26/06. - * Copyright 2006 Ohloh. All rights reserved. - * */ - #include "common.h" /* @@ -21,6 +15,8 @@ void language_breakdown_initialize(LanguageBreakdown *lb, char *name, int buffer lb->code[0] = 0; lb->comment = lb->comment_cur = malloc(buffer_size); lb->comment[0] = 0; + lb->code_count = 0; + lb->comment_count = 0; lb->blank_count = 0; lb->buffer_size = buffer_size; } @@ -44,6 +40,10 @@ void language_breakdown_free(LanguageBreakdown *lb) { } +/* when storing code, we strip leading white spaces, + * which tends to normalize code better (indentation + * changes are ignored). + */ char * first_non_blank(char *from, char *to) { while (from < to && (*from == ' ' || *from == '\t')) { from++; @@ -52,7 +52,7 @@ char * first_non_blank(char *from, char *to) { } /* - * language_breakdown_copy_code + * language_breakdown_append_code_line * * copies the passed in string (via delimiters) to the code buffer * @@ -60,31 +60,33 @@ char * first_non_blank(char *from, char *to) { * for language syntax errors (e.g. unclosed strings or block comments) or * parser errors. */ -int language_breakdown_copy_code(LanguageBreakdown *lb, char *from, char *to) { +int language_breakdown_append_code_line(LanguageBreakdown *lb, char *from, char *to) { from = first_non_blank(from, to); if (lb->code_cur + (to - from) >= lb->code + lb->buffer_size) return 0; // overflow error strncpy(lb->code_cur, from, to - from); lb->code_cur += to - from; *lb->code_cur = 0; + lb->code_count++; return 1; } /* - * language_breakdown_copy_comment + * language_breakdown_append_comment_line * - * copies the passed in string (via delimiters) to the comment buffer + * copies the passed in line (via delimiters) to the comment buffer * * Returns 1 on success, 0 on buffer overflow. Buffer overflows typically occur * for language syntax errors (e.g. unclosed strings or block comments) or * parser errors. */ -int language_breakdown_copy_comment(LanguageBreakdown *lb, char *from, char *to) { +int language_breakdown_append_comment_line(LanguageBreakdown *lb, char *from, char *to) { from = first_non_blank(from, to); if (lb->comment_cur + (to - from) >= lb->comment + lb->buffer_size) return 0; // overflow error strncpy(lb->comment_cur, from, to - from); lb->comment_cur += to - from; *lb->comment_cur = 0; + lb->comment_count++; return 1; } diff --git a/ext/ohcount_native/language_breakdown.h b/ext/ohcount_native/language_breakdown.h index 4dde862..b337a4e 100644 --- a/ext/ohcount_native/language_breakdown.h +++ b/ext/ohcount_native/language_breakdown.h @@ -14,11 +14,13 @@ typedef struct { char *comment; char *comment_cur; int blank_count; + int code_count; + int comment_count; int buffer_size; } LanguageBreakdown; void language_breakdown_initialize(LanguageBreakdown *lb, char *name, int buffer_size); -int language_breakdown_copy_code(LanguageBreakdown *lb, char *from, char *to); -int language_breakdown_copy_comment(LanguageBreakdown *lb, char *from, char *to); +int language_breakdown_append_code_line(LanguageBreakdown *lb, char *from, char *to); +int language_breakdown_append_comment_line(LanguageBreakdown *lb, char *from, char *to); void language_breakdown_free(LanguageBreakdown *lb); diff --git a/ext/ohcount_native/ragel_parser.c b/ext/ohcount_native/ragel_parser.c index 9aa02dc..744f905 100644 --- a/ext/ohcount_native/ragel_parser.c +++ b/ext/ohcount_native/ragel_parser.c @@ -219,10 +219,10 @@ void ragel_parse_yield_entity(const char *lang, const char *entity, int s, int e void ragel_parser_callback(const char *lang, const char *entity, int s, int e) { LanguageBreakdown *lb = get_language_breakdown((char *) lang); if (strcmp(entity, "lcode") == 0) { - if (language_breakdown_copy_code(lb, parse_buffer + s, parse_buffer + e)) + if (language_breakdown_append_code_line(lb, parse_buffer + s, parse_buffer + e)) ragel_parse_yield_line(lang, entity, s, e); } else if (strcmp(entity, "lcomment") == 0) { - if (language_breakdown_copy_comment(lb, parse_buffer + s, parse_buffer + e)) + if (language_breakdown_append_comment_line(lb, parse_buffer + s, parse_buffer + e)) ragel_parse_yield_line(lang, entity, s, e); } else if (strcmp(entity, "lblank") == 0) { lb->blank_count++; diff --git a/ext/ohcount_native/ruby_binding.c b/ext/ohcount_native/ruby_binding.c index fffa1fe..2eca9a4 100644 --- a/ext/ohcount_native/ruby_binding.c +++ b/ext/ohcount_native/ruby_binding.c @@ -21,20 +21,29 @@ static VALUE _language_breakdown_allocate(VALUE klass) { _my_buffer_size = 100; LanguageBreakdown *language_breakdown = (LanguageBreakdown *) malloc(sizeof(LanguageBreakdown)); language_breakdown_initialize(language_breakdown, "", _my_buffer_size); - - /* bs initializers */ - strcpy(language_breakdown->name, ""); - strcpy(language_breakdown->code, ""); - strcpy(language_breakdown->comment, ""); return Data_Wrap_Struct(klass, 0, _language_breakdown_free, language_breakdown); } -static VALUE _language_breakdown_initialize(VALUE self, VALUE name, VALUE code, VALUE comment, VALUE blanks) { +/* + * Initializes a LanguageBreakdown. + * + * call-seq: + * new(language_name, code_string, comment_string, blank_counts) + * + */ +static VALUE _language_breakdown_initialize(int argc, VALUE* argv, VALUE self) { + VALUE name; + VALUE code; + VALUE comment; + VALUE blanks; + + rb_scan_args(argc, argv, "13", &name, &code, &comment, &blanks); + /* validation */ - Check_Type(name, T_STRING); - Check_Type(code, T_STRING); - Check_Type(comment, T_STRING); - Check_Type(blanks, T_FIXNUM); + Check_Type(name, T_STRING); + if (!NIL_P(code)) { Check_Type(code, T_STRING); } + if (!NIL_P(comment)) { Check_Type(comment, T_STRING); } + if (!NIL_P(blanks)) { Check_Type(blanks, T_FIXNUM); } LanguageBreakdown *lb; Data_Get_Struct (self, LanguageBreakdown, lb); @@ -43,52 +52,102 @@ static VALUE _language_breakdown_initialize(VALUE self, VALUE name, VALUE code, strncpy(lb->name, rb_string_value_ptr(&name), MAX_LANGUAGE_NAME); /* code */ - if (lb->code != NULL) { - free(lb->code); + if (!NIL_P(code)) { + if (lb->code != NULL) { + free(lb->code); + } + lb->code = (char*)malloc(RSTRING(code)->len + 1); + strcpy(lb->code, rb_string_value_ptr(&code)); } - lb->code = (char*)malloc(RSTRING(code)->len + 1); - strcpy(lb->code, rb_string_value_ptr(&code)); /* comment */ - if (lb->comment != NULL) { - free(lb->comment); + if (!NIL_P(comment)) { + if (lb->comment != NULL) { + free(lb->comment); + } + lb->comment = (char*)malloc(RSTRING(comment)->len + 1); + strcpy(lb->comment, rb_string_value_ptr(&comment)); } - lb->comment = (char*)malloc(RSTRING(comment)->len + 1); - strcpy(lb->comment, rb_string_value_ptr(&comment)); /* blanks */ - lb->blank_count = NUM2INT(blanks); - + if (!NIL_P(blanks)) { + lb->blank_count = NUM2INT(blanks); + } return self; } +/* + * Returns the language name of this LanguageBreakdown. + * + * Example: + * puts lb.name + * + * # would output + * Ruby # assuming the lb language was Ruby + */ static VALUE _language_breakdown_name(VALUE self) { LanguageBreakdown *lb; Data_Get_Struct (self, LanguageBreakdown, lb); return rb_str_new2(lb->name); } +/* + * Returns a string containing only the code portion + * of the file. For example, if the file contained the + * following Ruby code: + * + * # a comment + * i = 5 + * + * After parsing, the code portion would contain: + * + * i = 5 + */ static VALUE _language_breakdown_code(VALUE self) { LanguageBreakdown *lb; Data_Get_Struct (self, LanguageBreakdown, lb); return rb_str_new2(lb->code); } +/* + * Returns a string containing only the commented lines. + */ static VALUE _language_breakdown_comment(VALUE self) { LanguageBreakdown *lb; Data_Get_Struct (self, LanguageBreakdown, lb); return rb_str_new2(lb->comment); } +/* + * Returns the count of blanks + */ static VALUE _language_breakdown_blanks(VALUE self) { LanguageBreakdown *lb; Data_Get_Struct (self, LanguageBreakdown, lb); - return INT2NUM(lb->blank_count); + return INT2FIX(lb->blank_count); +} + +/* + * Returns the count of lines of code + */ +static VALUE _language_breakdown_code_count(VALUE self) { + LanguageBreakdown *lb; + Data_Get_Struct (self, LanguageBreakdown, lb); + return INT2FIX(lb->code_count); } +/* + * Returns the count of lines of comment + */ +static VALUE _language_breakdown_comment_count(VALUE self) { + LanguageBreakdown *lb; + Data_Get_Struct (self, LanguageBreakdown, lb); + return INT2FIX(lb->comment_count); +} /* - * Ohcount::parse is the main entry point to Ohcount. + * Ohcount::parse is the Ohcount's workhorse function. It's wrapped by the + * SourceFile object - which provides a cleaner and easier API. * * It takes two parameters: a string buffer, and a string Monoglot or Polyglot name. * The buffer will be parsed using the specified glot. @@ -139,6 +198,8 @@ static VALUE _ohcount_parse(VALUE self, VALUE buffer, VALUE polyglot_name_value) strcpy(lb->name,src_lb->name); lb->code = src_lb->code; lb->comment = src_lb->comment; + lb->code_count = src_lb->code_count; + lb->comment_count = src_lb->comment_count; lb->blank_count = src_lb->blank_count; rb_ary_store(ary, i_pr, Data_Wrap_Struct(rb_class_language_breakdown, 0, _language_breakdown_free, lb)); } @@ -150,7 +211,10 @@ static VALUE _ohcount_parse(VALUE self, VALUE buffer, VALUE polyglot_name_value) } -/** +/* + * Document-class: Ohcount + * Document-method: parse_entities + * * Parses a source file's entities (if available). * An entity is each comment, string, number, keyword, etc. that occurs in a * source file. @@ -192,13 +256,21 @@ void Init_ohcount_native () { rb_define_module_function(rb_module_ohcount, "parse", _ohcount_parse, 2); rb_define_module_function(rb_module_ohcount, "parse_entities", _ohcount_parse_entities, 2); - // define language_breakdown + /* + * When a file containing source code is parsed, it stores the results in a + * collection of LanguageBreakdowns - one per coding language found in the + * file. For example, a parsed html file might contain three + * LanguageBreakdowns: one for html, one for javascript and another for css. + * + */ rb_class_language_breakdown = rb_define_class_under( rb_module_ohcount, "LanguageBreakdown", rb_cObject); rb_define_alloc_func (rb_class_language_breakdown, _language_breakdown_allocate); - rb_define_method (rb_class_language_breakdown, "initialize", _language_breakdown_initialize, 4); + rb_define_method (rb_class_language_breakdown, "initialize", _language_breakdown_initialize, -1); rb_define_method (rb_class_language_breakdown, "name", _language_breakdown_name, 0); rb_define_method (rb_class_language_breakdown, "code", _language_breakdown_code, 0); rb_define_method (rb_class_language_breakdown, "comment", _language_breakdown_comment, 0); rb_define_method (rb_class_language_breakdown, "blanks", _language_breakdown_blanks, 0); + rb_define_method (rb_class_language_breakdown, "code_count", _language_breakdown_code_count, 0); + rb_define_method (rb_class_language_breakdown, "comment_count", _language_breakdown_comment_count, 0); } diff --git a/lib/detector/base.rb b/lib/detector/base.rb deleted file mode 100644 index 2b7614e..0000000 --- a/lib/detector/base.rb +++ /dev/null @@ -1,578 +0,0 @@ -# The Detector determines which Monoglot or Polyglot should be -# used to parse a source file. -# -# The Detector primarily uses filename extensions to identify languages. -# -# The hash EXTENSION_MAP maps a filename extension to the name of a parser. -# -# If a filename extension is not enough to determine the correct parser (for -# instance, the *.m extension can indicate either a Matlab or Objective-C file), -# then the EXTENSION_MAP hash will contain a symbol identifying a Ruby method -# which will be invoked. This Ruby method can examine the file -# contents and return the name of the correct parser. -# -# Many source files do not have an extension. The method +disambiguate_nil+ -# is called in these cases. The +file+ command line tool is used to determine -# the type of file and select a parser. -# -# The Detector is covered by DetectorTest. -# -module Ohcount - module Detector - class Base - - # A performance hack -- once we've checked for the presence of *.m files, the result - # is stored here to avoid checking twice. - module ContainsM - attr_accessor :contains_m - # A performance hack -- once we've checked for the presence of *.pike and *.pmod files, the result - # is stored here to avoid checking twice. - attr_accessor :contains_pike_or_pmod - end - - # A performance hack -- once we've checked for the presence of *.frx, *.frm and *.vbp files, the result - # is stored here to avoid checking twice. - module ContainsVB - attr_accessor :contains_vb - end - - # The primary entry point for the detector. - # Given a file context containing the file name, content, and an array of - # other filenames in the source tree, attempts to detect which - # language family (Monoglot or Polyglot) is in use for this file. - # - # Returns nil if the language is not recognized or if the file does not - # contain any code. - # - # Example: - # - # # List all C files in the 'src' directory - # Dir.entries("src").each do |file| - # context = Ohcount::SimpleFileContext.new(file) - # polyglot = Ohcount::Detector.detect(context) - # puts "#{file}" if polyglot == 'c' - # end - # - def self.detect(source_file) - # start with filename and extension - polyglot = [ - lambda { | f | FILENAME_MAP[File.basename(source_file.filename)] }, - lambda { | f | EXTENSION_MAP[File.extname(source_file.filename)] }, - lambda { | f | EXTENSION_MAP[File.extname(source_file.filename).downcase] } - ].inject(nil) { | a, f | a and break a or f.call(source_file) } - case polyglot - when String - # simplest case - return polyglot if polyglot.is_a?(String) - when Symbol - # extension is ambiguous - requires custom disambiguation - self.send(polyglot, source_file) - when NilClass - return disambiguate_nil(source_file) - else - raise RuntimeError.new("Unknown file detection type") - end - end - - # Based solely on the filename, makes a judgment whether a file is a binary format. - def self.binary_filename?(filename) - ignore = [ - ".svn", - ".jar", - ".tar", - ".gz", - ".tgz", - ".zip", - ".gif", - ".jpg", - ".jpeg", - ".bmp", - ".png", - ".tif", - ".tiff", - ".ogg", - ".aiff", - ".wav", - ".mp3", - ".au", - ".ra", - ".m4a", - ".pdf", - ".mpg", - ".mov", - ".qt", - ".avi", - ".swf" - ] - ignore.include?(File.extname(filename)) - end - - # If an extension maps to a string, that string must be the name of a glot. - # If an extension maps to a Ruby symbol, that symbol must be the name of a - # Ruby method which will return the name of a glot. - EXTENSION_MAP = { - '.ada' => "ada", - '.adb' => "ada", - '.ads' => "ada", - '.as' => "actionscript", - '.asm' => "assembler", - '.awk' => "awk", - '.b' => :disambiguate_non_visual_basic, - '.bas' => :disambiguate_basic, - '.bat' => "bat", - '.bi' => :disambiguate_non_visual_basic, - '.boo' => "boo", - '.c' => "c", - '.C' => "cpp", - '.cc' => "cpp", - '.cpp' => "cpp", - '.css' => "css", - '.c++' => "cpp", - '.cxx' => "cpp", - '.com' => "dcl", - '.el' => "emacslisp", - '.cs' => :disambiguate_cs, - '.dylan' => "dylan", - '.e' => "eiffel", - '.ebuild' => "ebuild", - '.eclass' => "ebuild", - '.kdebuild-1' => "ebuild", - '.erl' => "erlang", - '.exheres-0' => "exheres", - '.exlib' => "exheres", - '.f' => :disambiguate_fortran, - '.factor' => "factor", - '.ftn' => :disambiguate_fortran, - '.f77' => :disambiguate_fortran, - '.f90' => :disambiguate_fortran, - '.f95' => :disambiguate_fortran, - '.f03' => :disambiguate_fortran, - '.frx' => "visualbasic", - '.groovy' => "groovy", - '.h' => :disambiguate_h_header, - '.haml' => 'haml', - '.H' => "cpp", - '.hpp' => "cpp", - '.h++' => "cpp", - '.hs' => "haskell", - '.hx' => "haxe", - '.hxx' => "cpp", - '.hh' => "cpp", - '.hrl' => "erlang", - '.htm' => "html", - '.html' => "html", - '.in' => :disambiguate_in, - '.inc' => :disambiguate_inc, - '.java' => "java", - '.js' => "javascript", - '.jsp' => "jsp", - '.lua' => "lua", - '.lsp' => "lisp", - '.lisp' => "lisp", - '.m' => :matlab_or_objective_c, - '.mf' => 'metafont', - '.mk' => 'make', - '.ml' => "ocaml", - '.mli' => "ocaml", - '.mm' => "objective_c", - '.mp' => 'metapost_with_tex', - '.mxml' => 'mxml', - '.nse' => 'lua', - '.pas' => "pascal", - '.pp' => "pascal", - '.php' => "php", - '.php3' => "php", - '.php4' => "php", - '.php5' => "php", - '.p6' => "perl", - '.pl' => "perl", - '.pm' => "perl", - '.perl' => "perl", - '.ph' => "perl", - '.pod' => "perl", - '.t' => "perl", - '.pike' => "pike", - '.pmc' => "c", - '.pmod' => "pike", - '.py' => "python", - '.r' => "r", - '.rhtml' => "rhtml", - '.rb' => "ruby", - '.rex' => "rexx", - '.rexx' => "rexx", - '.s' => "assembler", - '.sc' => "scheme", - '.scala' => "scala", - '.scm' => "scheme", - '.sh' => "shell", - '.sql' => "sql", - '.st' => "smalltalk", - '.str' => "stratego", - '.tcl' => "tcl", - '.tpl' => "html", - '.vala' => "vala", - '.vb' => "visualbasic", - '.vba' => "visualbasic", - '.vbs' => "visualbasic", - '.vhd' => "vhdl", - '.vhdl' => "vhdl", - '.vim' => "vim", - '.xml' => "xml", - '.xs' => "c", - '.xsd' => "xmlschema", - '.xsl' => "xslt", - '.d' => 'dmd', - '.di' => 'dmd', - '.tex' => 'tex', - '.ltx' => 'tex', - '.latex' => 'tex' - } - - # Map full filenames to glots. The right hand side is a string or symbol as - # for EXTENSION_MAP. - FILENAME_MAP = { - 'Makefile' => 'make', - 'GNUmakefile' => 'make', - 'makefile' => 'make', - 'Makefile.am' => 'automake', - 'configure.in' => 'autoconf', - 'configure.ac' => 'autoconf', - 'configure' => 'autoconf' - } - - protected - - # Returns a count of lines in the buffer matching the given regular expression. - def self.lines_matching(buffer, re) - buffer.inject(0) { |total, line| line =~ re ? total+1 : total } - end - - # For *.m files, differentiates Matlab from Objective-C. - # - # This is done with a weighted heuristic that - # scans the *.m file contents for keywords, - # and also checks for the presence of matching *.h files. - def self.matlab_or_objective_c(file_context) - buffer = file_context.contents - - # if there are .h files in same directory, this probably isn't matlab - h_headers = 0.0 - h_headers = -0.5 if file_context.filenames.select { |a| a =~ /\.h$/ }.any? - - # if the contents contain 'function (' on a single line - very likely to be matlab - # if the contents contain lines starting with '%', its probably matlab comments - matlab_signatures = /(^\s*function\s*)|(^\s*%)/ - matlab_sig_score = 0.1 * lines_matching(buffer, matlab_signatures) - - # if the contents contains '//' or '/*', likely objective_c - objective_c_signatures = /(^\s*\/\/\s*)|(^\s*\/\*)|(^[+-])/ - obj_c_sig_score = -0.1 * lines_matching(buffer, objective_c_signatures) - - matlab = h_headers + matlab_sig_score + obj_c_sig_score - - matlab > 0 ? 'matlab' : 'objective_c' - end - - # For *.h files, differentiates C, C++ and Objective-C. - # - # This is done with a weighted heuristic that - # scans the *.h file contents for Objective-C keywords, - # C++ keywords and C++ headers, and also checks for the - # presence of matching *.m files. - def self.disambiguate_h_header(file_context) - buffer = file_context.contents - - # could it be realistically be objective_c ? are there any .m files at all? - # Speed hack - remember our findings in case we get the same filenames over and over - unless defined?(file_context.filenames.contains_m) - file_context.filenames.extend(ContainsM) - file_context.filenames.contains_m = file_context.filenames.select { |a| a =~ /\.m$/ }.any? - file_context.filenames.contains_pike_or_pmod = file_context.filenames.select { |a| a =~ /\.p(ike|mod)$/ }.any? - end - - if file_context.filenames.contains_m - # if the dir contains a matching *.m file, likely objective_c - if file_context.filename =~ /\.h$/ - m_counterpart = file_context.filename.gsub(/\.h$/, ".m") - return 'objective_c' if file_context.filenames.include?(m_counterpart) - end - - # ok - it just might be objective_c, let's check contents for objective_c signatures - objective_c_signatures = /(^\s*@interface)|(^\s*@end)/ - objective_c = lines_matching(buffer, objective_c_signatures) - return 'objective_c' if objective_c > 1 - end - - if file_context.filenames.contains_pike_or_pmod - # The string "pike" and a selection of common Pike keywords. - pike_signatures = /([Pp][Ii][Kk][Ee])|(string )|(mapping)|(multiset)|(import )|(inherit )|(predef)/ - pike = lines_matching(buffer, pike_signatures) - return 'pike' if pike > 0 - end - - disambiguate_c_cpp(buffer) - end - - # A map of headers that indicate C++, but that do not have C++-specific file - # extensions. This list is made from the Standard, plus Technical Report 1. - CPP_HEADERS_MAP = %w[ - algorithm - array - bitset - cassert - ccomplex - cctype - cerrno - cfenv - cfloat - cinttypes - ciso646 - climits - clocale - cmath - csetjmp - csignal - cstdarg - cstdbool - cstddef - cstdint - cstdio - cstdlib - cstring - ctgmath - ctime - cwchar - cwctype - deque - exception - fstream - functional - iomanip - ios - iosfwd - iostream - istream - iterator - limits - list - locale - map - memory - new - numeric - ostream - queue - random - regex - set - sstream - stack - stdexcept - streambuf - string - system_error - tuple - type_traits - typeinfo - unordered_map - unordered_set - utility - valarray - vector - tr1/array - tr1/ccomplex - tr1/cctype - tr1/cfenv - tr1/cfloat - tr1/cinttypes - tr1/climits - tr1/cmath - tr1/complex - tr1/cstdarg - tr1/cstdbool - tr1/cstdint - tr1/cstdio - tr1/cstdlib - tr1/ctgmath - tr1/ctime - tr1/cwchar - tr1/cwctype - tr1/memory - tr1/random - tr1/regex - tr1/tuple - tr1/type_traits - tr1/unordered_map - tr1/unordered_set - tr1/utility - ].inject({}) { | h, k | h[k] = true ; h } - - # A map of keywords that indicate C++. - CPP_KEYWORDS_MAP = %w[ - template - typename - class - namespace - ].inject({}) { | h, k | h[k] = true ; h } - - # For *.h files that we know aren't Objective-C, differentiates C and C++. - # - # This is done with a weighted heuristic that - # scans the *.h file contents for C++ keywords and C++ headers. - def self.disambiguate_c_cpp(buffer) - # Look for C++ headers - return 'cpp' if extract_c_cpp_headers(buffer).detect do | header | - EXTENSION_MAP[File.extname(header)] == 'cpp' or CPP_HEADERS_MAP.include? header - end - - # Look for C++ keywords. This could check for comments, but doesn't. - return 'cpp' if buffer.find do | line | - line.split(/\W/).find do | word | - CPP_KEYWORDS_MAP.include? word - end - end - - # Nothing to suggest C++ - 'c' - end - - # Return a list of files included in a C or C++ source file. - def self.extract_c_cpp_headers(buffer) - buffer.map do | line | - m = line.match(/^#\s*include\s+[<"](.*)[>"]/) and m[1] - end.find_all { | a | a } - end - - # Tests whether the provided buffer contains binary or text content. - # This is not fool-proof -- we basically just check for zero values - # in the early bytes of the buffer. If we find a zero, we know it - # is not (ascii) text. - def self.binary_buffer?(buffer) - 100.times do |i| - return true if buffer[i] == 0 - end - false - end - - # True if the provided buffer includes a '?php' directive - def self.php_instruction?(buffer) - buffer =~ /\?php/ - end - - # For *.in files, checks the prior extension. - # Typically used for template files (eg Makefile.in, auto.c.in, etc). - def self.disambiguate_in(source_file) - # if the filename has an extension prior to the .in - if source_file.filename =~ /\..*\.in$/ - undecorated_filename = source_file.filename.gsub(/\.in$/, "") - undecorated_source = Ohcount::SourceFile.new(undecorated_filename, - :filenames => source_file.filenames, - :contents => source_file.contents, - :file_location => source_file.file_location) - return detect(undecorated_source) - end - nil - end - - # For *.inc files, checks for a PHP class. - def self.disambiguate_inc(file_context) - buffer = file_context.contents - return nil if binary_buffer?(buffer) - return 'php' if php_instruction?(buffer) - nil - end - - # For files with extention *.cs, differentiates C# from Clearsilver. - def self.disambiguate_cs(file_context) - buffer = file_context.contents - return 'clearsilver_template' if lines_matching(file_context.contents, /\<\?cs/) > 0 - return 'csharp' - end - - def self.disambiguate_fortran(file_context) - buffer = file_context.contents - - definitely_not_f77 = /^ [^0-9 ]{5}/ - return 'fortranfixed' if lines_matching(buffer, definitely_not_f77) > 0 - - free_form_continuation = /&\s*\n\s*&/m - return 'fortranfree' if buffer.match(free_form_continuation) - - possibly_fixed = /^ [0-9 ]{5}/ - contig_number = /^\s*\d+\s*$/ - buffer.scan(possibly_fixed) {|leader| - return 'fortranfixed' if !(leader =~ contig_number) } - # Might as well be free-form. - return 'fortranfree' - end - - # Attempts to tell apart VB, classic BASIC and structured BASIC. - # First, checks if it is classic BASIC based on syntax. - # If not checks for .vb, .vbp, .frx and .frm files (associated with VB) - # in file context - # - # If these files are absent, assumes structured BASIC - # - def self.disambiguate_basic(file_context) - classic_basic_line = /^\d+\s+\w+.*$/ - vb_filename = /\.fr[mx]$|\.vb([aps]?)$/ - buffer = file_context.contents - if lines_matching(buffer,classic_basic_line) > 0 - return 'classic_basic' - else - unless defined?(file_context.filenames.contains_vb) - file_context.filenames.extend(ContainsVB) - file_context.filenames.contains_vb = file_context.filenames.select { |a| a =~ vb_filename }.any? - end - if file_context.filenames.contains_vb - return 'visualbasic' - else - return 'structured_basic' - end - end - end - - def self.disambiguate_non_visual_basic(file_context) - classic_basic_line = /^\d+\s+\w+.*$/ - buffer = file_context.contents - - if lines_matching(buffer,classic_basic_line) > 0 - return 'classic_basic' - else - return 'structured_basic' - end - end - - # Attempts to determine the Polyglot for files that do not have a - # filename extension. - # - # Relies on the bash +file+ command line tool as its primary method. - # - # There must be a file at file_context.file_location for +file+ - # to operate on. - # - def self.disambiguate_nil(file_context) - file_location = file_context.file_location - output = `file -b '#{ file_location }'` - case output - when /([\w\/]+)(?: -[\w_]+)* script text/, /script text executable for ([\w\/]+)/ - script = $1 - if script =~ /\/(\w*)$/ - script = $1 - end - known_languages = EXTENSION_MAP.values - return script.downcase if known_languages.include?(script.downcase) - when /([\w\-]*) shell script text/ - case $1 - when "Bourne-Again" - return "shell" - end - end - - # dang... no dice - nil - end - - end - end -end diff --git a/lib/gestalt/base.rb b/lib/gestalt/base.rb index 1f17ddb..f952a71 100644 --- a/lib/gestalt/base.rb +++ b/lib/gestalt/base.rb @@ -27,8 +27,8 @@ def process! @lib_counts[l] ||= 0 @lib_counts[l] += 1 end - s.languages.each do |l| - @language_counts[l] = s.send(l).code.to_s.split.size + s.language_breakdowns.each do |lb| + @language_counts[lb.name.intern] = lb.code_count end end diff --git a/lib/gestalt/library.rb b/lib/gestalt/library.rb index f1faedc..2296215 100644 --- a/lib/gestalt/library.rb +++ b/lib/gestalt/library.rb @@ -28,6 +28,10 @@ def self.c_keywords(*keywords) rules << CKeywordRule.new(keywords) end + def self.php_keywords(*keywords) + rules << PHPKeywordRule.new(keywords) + end + def to_sym self.class.to_sym end diff --git a/lib/gestalt/library_rule.rb b/lib/gestalt/library_rule.rb index 53a9abf..4602dfd 100644 --- a/lib/gestalt/library_rule.rb +++ b/lib/gestalt/library_rule.rb @@ -21,7 +21,8 @@ def initialize(*headers) def trigger?(source_file) return false unless ['c','cpp'].include?(source_file.polyglot) - regexp.match(source_file.c.code) || regexp.match(source_file.cpp.code) + regexp.match(source_file.language_breakdowns('c').code) || + regexp.match(source_file.language_breakdowns('cpp').code) end def regexp @@ -44,23 +45,33 @@ def trigger?(source_file) end end - class CKeywordRule < LibraryRule + class KeywordLibraryRule attr_reader :keywords def initialize(*keywords) @keywords = keywords end - def trigger?(source_file) - return false unless ['c','cpp'].include?(source_file.polyglot) - regexp.match(source_file.c.code) || regexp.match(source_file.cpp.code) - end - def regexp @regexp ||= begin Regexp.new("(" + keywords.join("|") + ")") end end end + + class CKeywordRule < KeywordLibraryRule + def trigger?(source_file) + return false unless ['c','cpp'].include?(source_file.polyglot) + regexp.match(source_file.language_breakdowns('c').code) || + regexp.match(source_file.language_breakdowns('cpp').code) + end + end + + class PHPKeywordRule < KeywordLibraryRule + def trigger?(source_file) + regexp.match(source_file.language_breakdowns('php').code) + end + end + end end diff --git a/lib/gestalt/platform.rb b/lib/gestalt/platform.rb index 96637e8..9e6a1b9 100644 --- a/lib/gestalt/platform.rb +++ b/lib/gestalt/platform.rb @@ -23,40 +23,76 @@ def children() @children ||= [] end def inherited(other) children << other and super end def descendants() children.inject([]){|d,c| d.push(c, *c.descendants)} end end + end - # Will trigger if any sub-trigger does - class OrTrigger + class PTrigger + end + + class LogicalTrigger < PTrigger attr_reader :triggers def initialize(*triggers) @triggers = triggers end - def triggered?(g_attr) - triggers.each do |t| - return t if t.triggered?(g_attr) + def new_trigger(t_class, *args) + # since we might be nesting logical triggers, we must do remove + # any 'grandchildren triggers' from our list, since we are giving + args.each do |a| + next unless a.is_a?(PTrigger) + @triggers.delete(a) end - nil + t = t_class.new(*args) + triggers << t + t + end + + def t_or(*args) + new_trigger OrTrigger, *args + end + + def t_and(*args) + new_trigger AndTrigger, *args end def trigger_libs(*args) - triggers << LibsTrigger.new(*args) + new_trigger LibsTrigger, *args + end + + def trigger_platform(*args) + new_trigger PlatformTrigger, *args end - def trigger_platform(platform) - triggers << PlatformTrigger.new(platform) + def trigger_language(*args) + new_trigger LanguageTrigger, *args end + end + + # Will trigger if any sub-trigger does + class OrTrigger < LogicalTrigger + def triggered?(g_attr) + triggers.each do |t| + return t if t.triggered?(g_attr) + end + nil + end + end - def trigger_language(language, options = {}) - triggers << LanguageTrigger.new(language, options) + # Will trigger if all sub-triggers do + class AndTrigger < LogicalTrigger + def triggered?(g) + triggers.each do |t| + return nil unless t.triggered?(g) + end + self end end # will trigger if any libs were detected # options: # :count => minimum number of detections (default 1) - class LibsTrigger + class LibsTrigger < PTrigger attr_reader :lib_symbols attr_reader :count @@ -77,7 +113,7 @@ def triggered?(g) end end - class PlatformTrigger + class PlatformTrigger < PTrigger attr_reader :platform def initialize(platform) @@ -89,7 +125,7 @@ def triggered?(g) end end - class LanguageTrigger + class LanguageTrigger < PTrigger attr_reader :language attr_reader :min_percent @@ -107,7 +143,3 @@ def triggered?(g) end end -# require the dynamic rules -require OHCOUNT_ROOT + '/rules/libraries' -require OHCOUNT_ROOT + '/rules/platforms' - diff --git a/lib/ohcount.rb b/lib/ohcount.rb index 8b29937..3ea01ac 100644 --- a/lib/ohcount.rb +++ b/lib/ohcount.rb @@ -12,11 +12,20 @@ module Ohcount require "lib/#{Config::CONFIG['arch']}/ohcount_native" end -require "lib/detector/base" +require "lib/ohcount/helpers" +require "lib/ohcount/detector" require "lib/ohcount/language_breakdown" require "lib/ohcount/sloc_info" require "lib/ohcount/scratch_dir" require "lib/ohcount/source_file" +require "lib/ohcount/language_facts" +require "lib/ohcount/gestalt_facts" +require "lib/ohcount/source_file_list" require "lib/licenses/license_sniffer" require "lib/gestalt/base" + +# require the dynamic rules +require 'rules/libraries' +require 'rules/platforms' + diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb new file mode 100644 index 0000000..ddf828d --- /dev/null +++ b/lib/ohcount/detector.rb @@ -0,0 +1,576 @@ +module Ohcount #:nodoc: + # The Detector determines which Monoglot or Polyglot should be + # used to parse a source file. + # + # The Detector primarily uses filename extensions to identify languages. + # + # The hash EXTENSION_MAP maps a filename extension to the name of a parser. + # + # If a filename extension is not enough to determine the correct parser (for + # instance, the *.m extension can indicate either a Matlab or Objective-C file), + # then the EXTENSION_MAP hash will contain a symbol identifying a Ruby method + # which will be invoked. This Ruby method can examine the file + # contents and return the name of the correct parser. + # + # Many source files do not have an extension. The method +disambiguate_nil+ + # is called in these cases. The +file+ command line tool is used to determine + # the type of file and select a parser. + # + # The Detector is covered by DetectorTest. + # + class Detector + + # A performance hack -- once we've checked for the presence of *.m files, the result + # is stored here to avoid checking twice. + module ContainsM + attr_accessor :contains_m + # A performance hack -- once we've checked for the presence of *.pike and *.pmod files, the result + # is stored here to avoid checking twice. + attr_accessor :contains_pike_or_pmod + end + + # A performance hack -- once we've checked for the presence of *.frx, *.frm and *.vbp files, the result + # is stored here to avoid checking twice. + module ContainsVB + attr_accessor :contains_vb + end + + # The primary entry point for the detector. + # Given a file context containing the file name, content, and an array of + # other filenames in the source tree, attempts to detect which + # language family (Monoglot or Polyglot) is in use for this file. + # + # Returns nil if the language is not recognized or if the file does not + # contain any code. + # + # Example: + # + # # List all C files in the 'src' directory + # Dir.entries("src").each do |file| + # context = Ohcount::SimpleFileContext.new(file) + # polyglot = Ohcount::Detector.detect(context) + # puts "#{file}" if polyglot == 'c' + # end + # + def self.detect(source_file) + # start with filename and extension + polyglot = [ + lambda { | f | FILENAME_MAP[File.basename(source_file.filename)] }, + lambda { | f | EXTENSION_MAP[File.extname(source_file.filename)] }, + lambda { | f | EXTENSION_MAP[File.extname(source_file.filename).downcase] } + ].inject(nil) { | a, f | a and break a or f.call(source_file) } + case polyglot + when String + # simplest case + return polyglot if polyglot.is_a?(String) + when Symbol + # extension is ambiguous - requires custom disambiguation + self.send(polyglot, source_file) + when NilClass + return disambiguate_nil(source_file) + else + raise RuntimeError.new("Unknown file detection type") + end + end + + # Based solely on the filename, makes a judgment whether a file is a binary format. + def self.binary_filename?(filename) + ignore = [ + ".svn", + ".jar", + ".tar", + ".gz", + ".tgz", + ".zip", + ".gif", + ".jpg", + ".jpeg", + ".bmp", + ".png", + ".tif", + ".tiff", + ".ogg", + ".aiff", + ".wav", + ".mp3", + ".au", + ".ra", + ".m4a", + ".pdf", + ".mpg", + ".mov", + ".qt", + ".avi", + ".swf" + ] + ignore.include?(File.extname(filename)) + end + + # If an extension maps to a string, that string must be the name of a glot. + # If an extension maps to a Ruby symbol, that symbol must be the name of a + # Ruby method which will return the name of a glot. + EXTENSION_MAP = { + '.ada' => "ada", + '.adb' => "ada", + '.ads' => "ada", + '.as' => "actionscript", + '.asm' => "assembler", + '.awk' => "awk", + '.b' => :disambiguate_non_visual_basic, + '.bas' => :disambiguate_basic, + '.bat' => "bat", + '.bi' => :disambiguate_non_visual_basic, + '.boo' => "boo", + '.c' => "c", + '.C' => "cpp", + '.cc' => "cpp", + '.cpp' => "cpp", + '.css' => "css", + '.c++' => "cpp", + '.cxx' => "cpp", + '.com' => "dcl", + '.el' => "emacslisp", + '.cs' => :disambiguate_cs, + '.dylan' => "dylan", + '.e' => "eiffel", + '.ebuild' => "ebuild", + '.eclass' => "ebuild", + '.kdebuild-1' => "ebuild", + '.erl' => "erlang", + '.exheres-0' => "exheres", + '.exlib' => "exheres", + '.f' => :disambiguate_fortran, + '.factor' => "factor", + '.ftn' => :disambiguate_fortran, + '.f77' => :disambiguate_fortran, + '.f90' => :disambiguate_fortran, + '.f95' => :disambiguate_fortran, + '.f03' => :disambiguate_fortran, + '.frx' => "visualbasic", + '.groovy' => "groovy", + '.h' => :disambiguate_h_header, + '.haml' => 'haml', + '.H' => "cpp", + '.hpp' => "cpp", + '.h++' => "cpp", + '.hs' => "haskell", + '.hx' => "haxe", + '.hxx' => "cpp", + '.hh' => "cpp", + '.hrl' => "erlang", + '.htm' => "html", + '.html' => "html", + '.in' => :disambiguate_in, + '.inc' => :disambiguate_inc, + '.java' => "java", + '.js' => "javascript", + '.jsp' => "jsp", + '.lua' => "lua", + '.lsp' => "lisp", + '.lisp' => "lisp", + '.m' => :matlab_or_objective_c, + '.mf' => 'metafont', + '.mk' => 'make', + '.ml' => "ocaml", + '.mli' => "ocaml", + '.mm' => "objective_c", + '.mp' => 'metapost_with_tex', + '.mxml' => 'mxml', + '.nse' => 'lua', + '.pas' => "pascal", + '.pp' => "pascal", + '.php' => "php", + '.php3' => "php", + '.php4' => "php", + '.php5' => "php", + '.p6' => "perl", + '.pl' => "perl", + '.pm' => "perl", + '.perl' => "perl", + '.ph' => "perl", + '.pod' => "perl", + '.t' => "perl", + '.pike' => "pike", + '.pmc' => "c", + '.pmod' => "pike", + '.py' => "python", + '.r' => "r", + '.rhtml' => "rhtml", + '.rb' => "ruby", + '.rex' => "rexx", + '.rexx' => "rexx", + '.s' => "assembler", + '.sc' => "scheme", + '.scala' => "scala", + '.scm' => "scheme", + '.sh' => "shell", + '.sql' => "sql", + '.st' => "smalltalk", + '.str' => "stratego", + '.tcl' => "tcl", + '.tpl' => "html", + '.vala' => "vala", + '.vb' => "visualbasic", + '.vba' => "visualbasic", + '.vbs' => "visualbasic", + '.vhd' => "vhdl", + '.vhdl' => "vhdl", + '.vim' => "vim", + '.xml' => "xml", + '.xs' => "c", + '.xsd' => "xmlschema", + '.xsl' => "xslt", + '.d' => 'dmd', + '.di' => 'dmd', + '.tex' => 'tex', + '.ltx' => 'tex', + '.latex' => 'tex' + } + + # Map full filenames to glots. The right hand side is a string or symbol as + # for EXTENSION_MAP. + FILENAME_MAP = { + 'Makefile' => 'make', + 'GNUmakefile' => 'make', + 'makefile' => 'make', + 'Makefile.am' => 'automake', + 'configure.in' => 'autoconf', + 'configure.ac' => 'autoconf', + 'configure' => 'autoconf' + } + + protected + + # Returns a count of lines in the buffer matching the given regular expression. + def self.lines_matching(buffer, re) + buffer.inject(0) { |total, line| line =~ re ? total+1 : total } + end + + # For *.m files, differentiates Matlab from Objective-C. + # + # This is done with a weighted heuristic that + # scans the *.m file contents for keywords, + # and also checks for the presence of matching *.h files. + def self.matlab_or_objective_c(file_context) + buffer = file_context.contents + + # if there are .h files in same directory, this probably isn't matlab + h_headers = 0.0 + h_headers = -0.5 if file_context.filenames.select { |a| a =~ /\.h$/ }.any? + + # if the contents contain 'function (' on a single line - very likely to be matlab + # if the contents contain lines starting with '%', its probably matlab comments + matlab_signatures = /(^\s*function\s*)|(^\s*%)/ + matlab_sig_score = 0.1 * lines_matching(buffer, matlab_signatures) + + # if the contents contains '//' or '/*', likely objective_c + objective_c_signatures = /(^\s*\/\/\s*)|(^\s*\/\*)|(^[+-])/ + obj_c_sig_score = -0.1 * lines_matching(buffer, objective_c_signatures) + + matlab = h_headers + matlab_sig_score + obj_c_sig_score + + matlab > 0 ? 'matlab' : 'objective_c' + end + + # For *.h files, differentiates C, C++ and Objective-C. + # + # This is done with a weighted heuristic that + # scans the *.h file contents for Objective-C keywords, + # C++ keywords and C++ headers, and also checks for the + # presence of matching *.m files. + def self.disambiguate_h_header(file_context) + buffer = file_context.contents + + # could it be realistically be objective_c ? are there any .m files at all? + # Speed hack - remember our findings in case we get the same filenames over and over + unless defined?(file_context.filenames.contains_m) + file_context.filenames.extend(ContainsM) + file_context.filenames.contains_m = file_context.filenames.select { |a| a =~ /\.m$/ }.any? + file_context.filenames.contains_pike_or_pmod = file_context.filenames.select { |a| a =~ /\.p(ike|mod)$/ }.any? + end + + if file_context.filenames.contains_m + # if the dir contains a matching *.m file, likely objective_c + if file_context.filename =~ /\.h$/ + m_counterpart = file_context.filename.gsub(/\.h$/, ".m") + return 'objective_c' if file_context.filenames.include?(m_counterpart) + end + + # ok - it just might be objective_c, let's check contents for objective_c signatures + objective_c_signatures = /(^\s*@interface)|(^\s*@end)/ + objective_c = lines_matching(buffer, objective_c_signatures) + return 'objective_c' if objective_c > 1 + end + + if file_context.filenames.contains_pike_or_pmod + # The string "pike" and a selection of common Pike keywords. + pike_signatures = /([Pp][Ii][Kk][Ee])|(string )|(mapping)|(multiset)|(import )|(inherit )|(predef)/ + pike = lines_matching(buffer, pike_signatures) + return 'pike' if pike > 0 + end + + disambiguate_c_cpp(buffer) + end + + # A map of headers that indicate C++, but that do not have C++-specific file + # extensions. This list is made from the Standard, plus Technical Report 1. + CPP_HEADERS_MAP = %w[ + algorithm + array + bitset + cassert + ccomplex + cctype + cerrno + cfenv + cfloat + cinttypes + ciso646 + climits + clocale + cmath + csetjmp + csignal + cstdarg + cstdbool + cstddef + cstdint + cstdio + cstdlib + cstring + ctgmath + ctime + cwchar + cwctype + deque + exception + fstream + functional + iomanip + ios + iosfwd + iostream + istream + iterator + limits + list + locale + map + memory + new + numeric + ostream + queue + random + regex + set + sstream + stack + stdexcept + streambuf + string + system_error + tuple + type_traits + typeinfo + unordered_map + unordered_set + utility + valarray + vector + tr1/array + tr1/ccomplex + tr1/cctype + tr1/cfenv + tr1/cfloat + tr1/cinttypes + tr1/climits + tr1/cmath + tr1/complex + tr1/cstdarg + tr1/cstdbool + tr1/cstdint + tr1/cstdio + tr1/cstdlib + tr1/ctgmath + tr1/ctime + tr1/cwchar + tr1/cwctype + tr1/memory + tr1/random + tr1/regex + tr1/tuple + tr1/type_traits + tr1/unordered_map + tr1/unordered_set + tr1/utility + ].inject({}) { | h, k | h[k] = true ; h } + + # A map of keywords that indicate C++. + CPP_KEYWORDS_MAP = %w[ + template + typename + class + namespace + ].inject({}) { | h, k | h[k] = true ; h } + + # For *.h files that we know aren't Objective-C, differentiates C and C++. + # + # This is done with a weighted heuristic that + # scans the *.h file contents for C++ keywords and C++ headers. + def self.disambiguate_c_cpp(buffer) + # Look for C++ headers + return 'cpp' if extract_c_cpp_headers(buffer).detect do | header | + EXTENSION_MAP[File.extname(header)] == 'cpp' or CPP_HEADERS_MAP.include? header + end + + # Look for C++ keywords. This could check for comments, but doesn't. + return 'cpp' if buffer.find do | line | + line.split(/\W/).find do | word | + CPP_KEYWORDS_MAP.include? word + end + end + + # Nothing to suggest C++ + 'c' + end + + # Return a list of files included in a C or C++ source file. + def self.extract_c_cpp_headers(buffer) + buffer.map do | line | + m = line.match(/^#\s*include\s+[<"](.*)[>"]/) and m[1] + end.find_all { | a | a } + end + + # Tests whether the provided buffer contains binary or text content. + # This is not fool-proof -- we basically just check for zero values + # in the early bytes of the buffer. If we find a zero, we know it + # is not (ascii) text. + def self.binary_buffer?(buffer) + 100.times do |i| + return true if buffer[i] == 0 + end + false + end + + # True if the provided buffer includes a '?php' directive + def self.php_instruction?(buffer) + buffer =~ /\?php/ + end + + # For *.in files, checks the prior extension. + # Typically used for template files (eg Makefile.in, auto.c.in, etc). + def self.disambiguate_in(source_file) + # if the filename has an extension prior to the .in + if source_file.filename =~ /\..*\.in$/ + undecorated_filename = source_file.filename.gsub(/\.in$/, "") + undecorated_source = Ohcount::SourceFile.new(undecorated_filename, + :filenames => source_file.filenames, + :contents => source_file.contents, + :file_location => source_file.file_location) + return detect(undecorated_source) + end + nil + end + + # For *.inc files, checks for a PHP class. + def self.disambiguate_inc(file_context) + buffer = file_context.contents + return nil if binary_buffer?(buffer) + return 'php' if php_instruction?(buffer) + nil + end + + # For files with extention *.cs, differentiates C# from Clearsilver. + def self.disambiguate_cs(file_context) + buffer = file_context.contents + return 'clearsilver_template' if lines_matching(file_context.contents, /\<\?cs/) > 0 + return 'csharp' + end + + def self.disambiguate_fortran(file_context) + buffer = file_context.contents + + definitely_not_f77 = /^ [^0-9 ]{5}/ + return 'fortranfixed' if lines_matching(buffer, definitely_not_f77) > 0 + + free_form_continuation = /&\s*\n\s*&/m + return 'fortranfree' if buffer.match(free_form_continuation) + + possibly_fixed = /^ [0-9 ]{5}/ + contig_number = /^\s*\d+\s*$/ + buffer.scan(possibly_fixed) {|leader| + return 'fortranfixed' if !(leader =~ contig_number) } + # Might as well be free-form. + return 'fortranfree' + end + + # Attempts to tell apart VB, classic BASIC and structured BASIC. + # First, checks if it is classic BASIC based on syntax. + # If not checks for .vb, .vbp, .frx and .frm files (associated with VB) + # in file context + # + # If these files are absent, assumes structured BASIC + # + def self.disambiguate_basic(file_context) + classic_basic_line = /^\d+\s+\w+.*$/ + vb_filename = /\.fr[mx]$|\.vb([aps]?)$/ + buffer = file_context.contents + if lines_matching(buffer,classic_basic_line) > 0 + return 'classic_basic' + else + unless defined?(file_context.filenames.contains_vb) + file_context.filenames.extend(ContainsVB) + file_context.filenames.contains_vb = file_context.filenames.select { |a| a =~ vb_filename }.any? + end + if file_context.filenames.contains_vb + return 'visualbasic' + else + return 'structured_basic' + end + end + end + + def self.disambiguate_non_visual_basic(file_context) + classic_basic_line = /^\d+\s+\w+.*$/ + buffer = file_context.contents + + if lines_matching(buffer,classic_basic_line) > 0 + return 'classic_basic' + else + return 'structured_basic' + end + end + + # Attempts to determine the Polyglot for files that do not have a + # filename extension. + # + # Relies on the bash +file+ command line tool as its primary method. + # + # There must be a file at file_context.file_location for +file+ + # to operate on. + # + def self.disambiguate_nil(file_context) + file_location = file_context.file_location + output = `file -b '#{ file_location }'` + case output + when /([\w\/]+)(?: -[\w_]+)* script text/, /script text executable for ([\w\/]+)/ + script = $1 + if script =~ /\/(\w*)$/ + script = $1 + end + known_languages = EXTENSION_MAP.values + return script.downcase if known_languages.include?(script.downcase) + when /([\w\-]*) shell script text/ + case $1 + when "Bourne-Again" + return "shell" + end + end + + # dang... no dice + nil + end + + end +end diff --git a/lib/ohcount/gestalt_facts.rb b/lib/ohcount/gestalt_facts.rb new file mode 100644 index 0000000..f2fa8e2 --- /dev/null +++ b/lib/ohcount/gestalt_facts.rb @@ -0,0 +1,58 @@ +module Ohcount + + # Represents language statistics for a collection of files + class GestaltFacts + attr_accessor :platforms, :lib_counts, :language_counts + + def initialize + @platforms = [] + @lib_counts = {} + @language_counts = {} + end + + def process(source_file) + Library.detect_libraries(source_file).collect { |library| library.to_sym }.each do |l| + @lib_counts[l] ||= 0 + @lib_counts[l] += 1 + end + source_file.language_breakdowns.each do |lb| + @language_counts[lb.name.intern] ||= 0 + @language_counts[lb.name.intern] += lb.code_count + end + end + + def post_process + # since platforms can depend on other platforms, + # we perform an iterative process and break when + # no new platforms have been detected. + while true do + prev_platforms = self.platforms.clone + uninfered_platforms.each do |p| + platforms << p if p.triggered?(self) + end + break if prev_platforms == self.platforms + end + end + + def uninfered_platforms #:nodoc: + Platform.descendants - @platforms + end + + def includes_language?(language, min_percent = 0) + return false unless language_counts[language] + language_percents[language] >= min_percent + end + + def language_percents + @language_percents ||= begin + total = language_counts.values.inject(0) { |s,c| s+c } + l = {} + language_counts.each do |k,v| + l[k] = 100.0 * v.to_i / total + end + l + end + end + + end +end diff --git a/lib/ohcount/helpers.rb b/lib/ohcount/helpers.rb new file mode 100644 index 0000000..97bcb92 --- /dev/null +++ b/lib/ohcount/helpers.rb @@ -0,0 +1,12 @@ +class String + + # Generic string abbreviation function. + # + # Example: + # "foobar".abbr(5) => "fo..." + # + def abbr(len=80) + size > len ? self[0..(len-3)] + "..." : self + end +end + diff --git a/lib/ohcount/language_breakdown.rb b/lib/ohcount/language_breakdown.rb index f07ffab..55e133c 100644 --- a/lib/ohcount/language_breakdown.rb +++ b/lib/ohcount/language_breakdown.rb @@ -1,26 +1,11 @@ -# LanguageBreakdown is a helper struct. Most of its methods are defined in the C code. -# It has the following properties: -# -# name: The name of the language found -# -# code: A string containing all lines from the parsed buffer that contained code in language . -# -# comment: A string containing all lines from the parsed buffer that contained only comments (no code) in language . -# -# blanks: The number of blank lines found while parsing language . -# class Ohcount::LanguageBreakdown - def ==(other) + def ==(other) #:nodoc: return self.name == other.name && self.code == other.code && self.comment == other.comment && self.blanks == other.blanks end - def abbr(s, len=80) - s.size > len ? s[0..(len-3)] + "..." : s - end - - def inspect - return "<[#{ self.name }]-code(#{ abbr(self.code).gsub("\n", "\\n") })/comment(#{ abbr(self.comment) })/blanks:#{ self.blanks }>" + def inspect # :nodoc: + return "<'#{ self.name }'-code(|#{ self.code_count } lines| \"#{ self.code.abbr.gsub("\n", "\\n") }\")/comments(|#{ self.comment_count } lines| \"#{ self.comment.abbr }\")/blanks:#{ self.blanks }>" end end diff --git a/lib/ohcount/language_facts.rb b/lib/ohcount/language_facts.rb new file mode 100644 index 0000000..ae2c77e --- /dev/null +++ b/lib/ohcount/language_facts.rb @@ -0,0 +1,46 @@ +module Ohcount + + # Represents language statistics for a collection of files + class LanguageFacts + attr_accessor :fact_map + attr_accessor :filecount + attr_accessor :code, :blanks, :comments + + def initialize + @fact_map = {} + @filecount = @code = @blanks = @comments = 0 + end + + def process(source_file) + source_file.language_breakdowns.each do |lb| + lang = lb.name + lang_fact = @fact_map[lang] ||= LanguageFact.new(lang) + + @code += lb.code_count + @comments += lb.comment_count + @blanks += lb.blanks + + lang_fact.code += lb.code_count + lang_fact.comments += lb.comment_count + lang_fact.blanks += lb.blanks + lang_fact.filecount += 1 + end + @filecount += 1 + end + + def method_missing(m, *args) + @fact_map[m] || @fact_map[m.to_s] || LanguageFact.new(m.to_s) + end + end + + # holds stats for an individual language + class LanguageFact + attr_reader :language + attr_accessor :filecount, :blanks, :code, :comments + + def initialize(lang) + @language = lang + @filecount = @blanks = @code = @comments = 0 + end + end +end diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb index 08b87b7..8911db5 100644 --- a/lib/ohcount/source_file.rb +++ b/lib/ohcount/source_file.rb @@ -56,7 +56,7 @@ def contents end def polyglot - @polyglot ||= Ohcount::Detector::Base.detect(self) + @polyglot ||= Ohcount::Detector.detect(self) end def basename @@ -69,27 +69,21 @@ def source_code? !!polyglot end - def parse - # dont reparse for nothing - return if parsed? && !block_given? - - @languages = {} - return unless polyglot - Ohcount::parse(contents, polyglot) do |language, semantic, line| - @languages[language] ||= HashWithDotAccess.new - @languages[language][semantic] ||= '' - @languages[language][semantic] << line - yield(language, semantic, line) if block_given? - end + def parse(&block) + @language_breakdowns = Ohcount::parse(contents, polyglot, &block) end def parsed? - !(@languages.nil?) + !(@language_breakdowns.nil?) end - def languages - parse unless @languages - @languages.keys + def language_breakdowns(language = nil) + parse unless parsed? + if language + return @language_breakdowns.find { |lb| lb.name == language.to_s } || + LanguageBreakdown.new(language.to_s) + end + @language_breakdowns end def licenses @@ -109,17 +103,5 @@ def raw_entities(&block) Ohcount::parse_entities(contents, polyglot, &block) end - # we support sourcefile.ruby - def method_missing(method, *args) - parse - return @languages[method] || HashWithDotAccess.new - end - - end -end - -class HashWithDotAccess < Hash - def method_missing(method, *args) - self[method] if args.empty? end end diff --git a/lib/ohcount/source_file_list.rb b/lib/ohcount/source_file_list.rb new file mode 100644 index 0000000..971fc1d --- /dev/null +++ b/lib/ohcount/source_file_list.rb @@ -0,0 +1,83 @@ +module Ohcount + + # Use a SourceFileList to collect information about multiple files. Example: + # + # # find out the number of Ruby lines of code in project 'foo' + # sfl = SourceFileList.new(:dir => '/foo') + # sfl.language_stats(:ruby).code + # + class SourceFileList < Array + attr_reader :language_facts, :gestalt_facts + + # pass an array of filenames you want to process. + # + # Options: + # + # :paths directory name from which to populate all files from (deep). + # :files exact files to analyze + # + def initialize(options = {}) + files = options.inject([]) do |memo,(k,v)| + memo + case k + when :path then files_from_paths([v]) + when :paths then files_from_paths(v) + when :files then v + else raise(ArgumentError, "Unrecognized option: #{ k }") + end + end + super(files) + end + + def files_from_paths(paths) + paths.inject([]) do |files, path| + glob_path = File.join(path,"**","*") + files + Dir.glob(glob_path) + end + end + + # + # call analyze to generate facts from a collection of files (typically a + # project directory). Because deducing different facts often requires doing + # similar work, this function allows multiple facts to be extracted in one + # single pass + # + # *Fact* *Types* + # + # :gestalt:: platform dependencies and tools usage + # :languages:: detailed programming languages facts + # + # Examples + # + # sfl = SourceFileList.new(:dir => '/foo/bar') + # sfl.analyze(:languages) + # puts sfl.ruby.code.count + # + # + def analyze(what = []) + what = [what] unless what.is_a?(Array) + + do_gestalt = what.include?(:gestalt) || what.include?(:*) + do_languages = what.include?(:language) || what.include?(:*) + + @language_facts = LanguageFacts.new if do_languages + @gestalt_facts = GestaltFacts.new if do_gestalt + + each_source_file do |source_file| + @language_facts.process(source_file) if do_languages + @gestalt_facts.process(source_file) if do_gestalt + yield source_file if block_given? + end + + @gestalt_facts.post_process if do_gestalt + end + + def each_source_file + self.each do |file| + sf = SourceFile.new(file, :filename => self) + next unless sf.polyglot + yield sf + end + end + + end +end diff --git a/rules/libraries.rb b/rules/libraries.rb index 5af4722..fa42c17 100644 --- a/rules/libraries.rb +++ b/rules/libraries.rb @@ -12,5 +12,13 @@ class WindowsConstants < Library c_keywords 'WM_PAINT', 'ReleaseDC', 'WndProc' end + class CakePhpCore < Library + php_keywords "CAKE_CORE_INCLUDE_PATH" + end + + class BSDLib < Library + c_keywords 'FTS_PHYSICAL' + end + end end diff --git a/rules/platforms.rb b/rules/platforms.rb index 87c0707..25d56bc 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -18,3 +18,10 @@ class Linux < Platform class Ruby < Platform trigger_language :ruby, :min_percent => 15 end + +class CakePHP < Platform + t_and( + trigger_language(:php, :min_percent => 15), + trigger_libs(:cake_php_core) + ) +end diff --git a/test/gestalt_files/test_cakephp/foo.php b/test/gestalt_files/test_cakephp/foo.php new file mode 100644 index 0000000..62a3a9d --- /dev/null +++ b/test/gestalt_files/test_cakephp/foo.php @@ -0,0 +1,5 @@ + diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index 361c3d2..22df2d1 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -5,22 +5,22 @@ class PlatformTest < Test::Unit::TestCase -# def test_initialize -# b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_win32')) -# assert_equal [gestalt_file_dir('test_win32/foo.c')], b.filenames -# end - -# def test_win32_not_enough -# b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_win32_not_enough')) -# b.process! -# assert_equal [], b.platforms -# end -# -# def test_win32_enough -# b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_win32_enough')) -# b.process! -# assert_equal [Win32], b.platforms -# end + def test_initialize + b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_cakephp')) + assert_equal [gestalt_file_dir('test_cakephp/foo.php')], b.filenames + end + + def test_win32_not_enough + b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_win32_not_enough')) + b.process! + assert_equal [], b.platforms + end + + def test_win32_enough + b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_win32_enough')) + b.process! + assert_equal [Win32], b.platforms + end def test_linux_1 b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_linux_1')) @@ -28,18 +28,28 @@ def test_linux_1 assert_equal [POSIX, Linux], b.platforms end -# def test_ruby_just_enough -# b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_ruby_just_enough')) -# b.process! -# assert_equal [Ruby], b.platforms -# end -# -# def test_ruby_not_enough -# b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_ruby_not_enough')) -# b.process! -# assert_equal [], b.platforms -# end -# + def test_ruby_just_enough + b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_ruby_just_enough')) + b.process! + assert_equal [Ruby], b.platforms + end + + def test_ruby_not_enough + assert_platform('test_ruby_not_enough') + end + + def test_cakephp + assert_platform('test_cakephp', CakePHP) + end + + protected + + def assert_platform(path, *platforms) + b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir(path)) + b.process! + assert_equal platforms, b.platforms + end + def gestalt_file_dir(path = '') File.expand_path(File.dirname(__FILE__) + "/../../gestalt_files/" + path) end diff --git a/test/unit/language_breakdown_test.rb b/test/unit/language_breakdown_test.rb new file mode 100644 index 0000000..cc6d832 --- /dev/null +++ b/test/unit/language_breakdown_test.rb @@ -0,0 +1,12 @@ +require File.dirname(__FILE__) + '/../test_helper' +include Ohcount + +class LanguageBreakdownTest < Ohcount::Test + + def test_initialize + lb = LanguageBreakdown.new('c') + assert 'c', lb.name + end + +end + diff --git a/test/unit/source_file_list_test.rb b/test/unit/source_file_list_test.rb new file mode 100644 index 0000000..f277944 --- /dev/null +++ b/test/unit/source_file_list_test.rb @@ -0,0 +1,37 @@ +require File.dirname(__FILE__) + '/../test_helper' +include Ohcount + +class SourceFileListTest < Ohcount::Test + +# def test_init_with_dir +# sfl = SourceFileList.new(:dir => test_dir('test_win32_enough')) +# assert_equal 2, sfl.size +# end + + def test_language_facts + sfl = SourceFileList.new(:path => test_dir('test_win32_enough')) + sfl.analyze(:language) + assert_equal 2, sfl.language_facts.filecount + assert_equal 2, sfl.language_facts.c.code + assert_equal 2, sfl.language_facts.c.comments + assert_equal 2, sfl.language_facts.c.blanks + end + + def test_gestalt_facts + sfl = SourceFileList.new(:path => test_dir('test_win32_enough')) + sfl.analyze(:gestalt) + assert_equal [Win32], sfl.gestalt_facts.platforms + end + + protected + + def license_file(f) + File.expand_path(File.dirname(__FILE__) + "/../src_licenses/#{ f }") + end + + def test_dir(d) + File.expand_path(File.dirname(__FILE__) + "/../gestalt_files/#{ d }") + end + +end + diff --git a/test/unit/source_file_test.rb b/test/unit/source_file_test.rb index 31059d4..bfd5ffd 100644 --- a/test/unit/source_file_test.rb +++ b/test/unit/source_file_test.rb @@ -13,12 +13,11 @@ def test_contents assert_equal contents, f.contents end - def test_languages + def test_language_breakdowns contents = "x = 5" f = SourceFile.new("foo.rb", :contents => contents) - assert_equal [:ruby], f.languages - assert_equal({:code => contents}, f.ruby) - assert_equal contents, f.ruby.code + assert_equal 'ruby', f.language_breakdowns[0].name + assert_equal contents, f.language_breakdowns('ruby').code end def test_parse From 2111dc1710d271b80b77312971af5e14c5455dae Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Thu, 6 Nov 2008 12:28:09 -0800 Subject: [PATCH 019/387] [CLEANUP] yanked gestalt/base -- superceded by source_file_list --- lib/gestalt/base.rb | 70 -------------------------------------- lib/ohcount.rb | 4 ++- test/unit/gestalt/platform_test.rb | 31 +++++------------ 3 files changed, 12 insertions(+), 93 deletions(-) delete mode 100644 lib/gestalt/base.rb diff --git a/lib/gestalt/base.rb b/lib/gestalt/base.rb deleted file mode 100644 index f952a71..0000000 --- a/lib/gestalt/base.rb +++ /dev/null @@ -1,70 +0,0 @@ -require "lib/gestalt/library" -require "lib/gestalt/platform" - -module Ohcount - module Gestalt - class Base - attr_reader :lib_counts - attr_reader :language_counts - attr_reader :platforms - attr_reader :filenames - - def initialize(args = {}) - if args[:dir] - @filenames = Dir.glob(File.join(args[:dir] + "/","**", "*")) - end - @filenames ||= args[:files] - @lib_counts = {} - @platforms = [] - @language_counts = {} - end - - def process! - # process files - filenames.each do |filename| - s = SourceFile.new(filename) - Library.detect_libraries(s).collect { |library| library.to_sym }.each do |l| - @lib_counts[l] ||= 0 - @lib_counts[l] += 1 - end - s.language_breakdowns.each do |lb| - @language_counts[lb.name.intern] = lb.code_count - end - end - - # since platforms can depend on other platforms, - # we perform an iterative process and break when - # no new platforms have been detected. - while true do - prev_platforms = self.platforms.clone - uninfered_platforms.each do |p| - platforms << p if p.triggered?(self) - end - break if prev_platforms == self.platforms - end - end - - def uninfered_platforms - Platform.descendants - @platforms - end - - def includes_language?(language, min_percent = 0) - return false unless language_counts[language] - language_percents[language] >= min_percent - end - - def language_percents - @language_percents ||= begin - total = language_counts.values.inject(0) { |s,c| s+c } - l = {} - language_counts.each do |k,v| - l[k] = 100.0 * v.to_i / total - end - l - end - end - - end - end -end - diff --git a/lib/ohcount.rb b/lib/ohcount.rb index 3ea01ac..cd21de4 100644 --- a/lib/ohcount.rb +++ b/lib/ohcount.rb @@ -23,7 +23,9 @@ module Ohcount require "lib/ohcount/source_file_list" require "lib/licenses/license_sniffer" -require "lib/gestalt/base" + +require "lib/gestalt/library" +require "lib/gestalt/platform" # require the dynamic rules require 'rules/libraries' diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index 22df2d1..dd53e7a 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -5,33 +5,20 @@ class PlatformTest < Test::Unit::TestCase - def test_initialize - b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_cakephp')) - assert_equal [gestalt_file_dir('test_cakephp/foo.php')], b.filenames - end - def test_win32_not_enough - b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_win32_not_enough')) - b.process! - assert_equal [], b.platforms + assert_platform('test_win32_not_enough') end def test_win32_enough - b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_win32_enough')) - b.process! - assert_equal [Win32], b.platforms + assert_platform('test_win32_enough', Win32) end def test_linux_1 - b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_linux_1')) - b.process! - assert_equal [POSIX, Linux], b.platforms + assert_platform('test_linux_1', POSIX, Linux) end def test_ruby_just_enough - b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir('test_ruby_just_enough')) - b.process! - assert_equal [Ruby], b.platforms + assert_platform('test_ruby_just_enough', Ruby) end def test_ruby_not_enough @@ -45,12 +32,12 @@ def test_cakephp protected def assert_platform(path, *platforms) - b = Ohcount::Gestalt::Base.new(:dir => gestalt_file_dir(path)) - b.process! - assert_equal platforms, b.platforms + sfl = SourceFileList.new(:path => test_dir(path)) + sfl.analyze(:gestalt) + assert_equal platforms, sfl.gestalt_facts.platforms end - def gestalt_file_dir(path = '') - File.expand_path(File.dirname(__FILE__) + "/../../gestalt_files/" + path) + def test_dir(d) + File.expand_path(File.dirname(__FILE__) + "/../../gestalt_files/#{ d }") end end From 480fd943f1234c06135b9b2b3f53cb47e5e2871b Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Thu, 6 Nov 2008 14:17:46 -0800 Subject: [PATCH 020/387] [NEW] Rails a recognized platform --- lib/gestalt/library.rb | 12 ++++++++---- lib/gestalt/library_rule.rb | 21 +++++++++++++-------- rules/libraries.rb | 4 ++++ rules/platforms.rb | 7 +++++++ .../gestalt_files/{test_cakephp => cakephp}/foo.php | 0 .../{test_linux_1 => linux_1}/configure.in | 0 test/gestalt_files/{test_linux_1 => linux_1}/foo.c | 0 test/gestalt_files/{test_linux_1 => linux_1}/foo.rb | 0 test/gestalt_files/rails/foo.rb | 3 +++ .../foo.c | 0 .../foo.rb | 0 .../{test_ruby_not_enough => ruby_not_enough}/foo.c | 0 .../foo.rb | 0 .../{test_win32_enough => win32_enough}/bar.c | 0 .../{test_win32_enough => win32_enough}/foo.c | 0 .../foo.c | 0 test/unit/gestalt/platform_test.rb | 16 ++++++++++------ test/unit/source_file_list_test.rb | 4 ++-- 18 files changed, 47 insertions(+), 20 deletions(-) rename test/gestalt_files/{test_cakephp => cakephp}/foo.php (100%) rename test/gestalt_files/{test_linux_1 => linux_1}/configure.in (100%) rename test/gestalt_files/{test_linux_1 => linux_1}/foo.c (100%) rename test/gestalt_files/{test_linux_1 => linux_1}/foo.rb (100%) create mode 100644 test/gestalt_files/rails/foo.rb rename test/gestalt_files/{test_ruby_just_enough => ruby_just_enough}/foo.c (100%) rename test/gestalt_files/{test_ruby_just_enough => ruby_just_enough}/foo.rb (100%) rename test/gestalt_files/{test_ruby_not_enough => ruby_not_enough}/foo.c (100%) rename test/gestalt_files/{test_ruby_not_enough => ruby_not_enough}/foo.rb (100%) rename test/gestalt_files/{test_win32_enough => win32_enough}/bar.c (100%) rename test/gestalt_files/{test_win32_enough => win32_enough}/foo.c (100%) rename test/gestalt_files/{test_win32_not_enough => win32_not_enough}/foo.c (100%) diff --git a/lib/gestalt/library.rb b/lib/gestalt/library.rb index 2296215..fef8361 100644 --- a/lib/gestalt/library.rb +++ b/lib/gestalt/library.rb @@ -28,14 +28,18 @@ def self.c_keywords(*keywords) rules << CKeywordRule.new(keywords) end - def self.php_keywords(*keywords) - rules << PHPKeywordRule.new(keywords) - end - def to_sym self.class.to_sym end + def self.method_missing(m,*args) + if /(.*)_keywords$/ =~ m.to_s + language = $1 + return rules << KeywordLibraryRule.new(language,args) + end + super + end + # when tallying up libraries, its easier to # use symbol names instead of class names # to_sym maps FooLib to :foo_lib diff --git a/lib/gestalt/library_rule.rb b/lib/gestalt/library_rule.rb index 4602dfd..fa69c78 100644 --- a/lib/gestalt/library_rule.rb +++ b/lib/gestalt/library_rule.rb @@ -46,12 +46,18 @@ def trigger?(source_file) end class KeywordLibraryRule - attr_reader :keywords + attr_reader :keywords, :language - def initialize(*keywords) + def initialize(language, *keywords) + @language = language @keywords = keywords end + def trigger?(source_file) + return unless source_file.language_breakdowns(language) + regexp.match(source_file.language_breakdowns(language).code) + end + def regexp @regexp ||= begin Regexp.new("(" + keywords.join("|") + ")") @@ -60,6 +66,11 @@ def regexp end class CKeywordRule < KeywordLibraryRule + + def initialize(*keywords) + super('c',*keywords) + end + def trigger?(source_file) return false unless ['c','cpp'].include?(source_file.polyglot) regexp.match(source_file.language_breakdowns('c').code) || @@ -67,11 +78,5 @@ def trigger?(source_file) end end - class PHPKeywordRule < KeywordLibraryRule - def trigger?(source_file) - regexp.match(source_file.language_breakdowns('php').code) - end - end - end end diff --git a/rules/libraries.rb b/rules/libraries.rb index fa42c17..553b2a7 100644 --- a/rules/libraries.rb +++ b/rules/libraries.rb @@ -16,6 +16,10 @@ class CakePhpCore < Library php_keywords "CAKE_CORE_INCLUDE_PATH" end + class RailsCore < Library + ruby_keywords "RAILS_ROOT" + end + class BSDLib < Library c_keywords 'FTS_PHYSICAL' end diff --git a/rules/platforms.rb b/rules/platforms.rb index 25d56bc..3f81dfb 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -19,6 +19,13 @@ class Ruby < Platform trigger_language :ruby, :min_percent => 15 end +class Rails < Platform + t_and( + trigger_libs(:rails_core), + trigger_platform(Ruby) + ) +end + class CakePHP < Platform t_and( trigger_language(:php, :min_percent => 15), diff --git a/test/gestalt_files/test_cakephp/foo.php b/test/gestalt_files/cakephp/foo.php similarity index 100% rename from test/gestalt_files/test_cakephp/foo.php rename to test/gestalt_files/cakephp/foo.php diff --git a/test/gestalt_files/test_linux_1/configure.in b/test/gestalt_files/linux_1/configure.in similarity index 100% rename from test/gestalt_files/test_linux_1/configure.in rename to test/gestalt_files/linux_1/configure.in diff --git a/test/gestalt_files/test_linux_1/foo.c b/test/gestalt_files/linux_1/foo.c similarity index 100% rename from test/gestalt_files/test_linux_1/foo.c rename to test/gestalt_files/linux_1/foo.c diff --git a/test/gestalt_files/test_linux_1/foo.rb b/test/gestalt_files/linux_1/foo.rb similarity index 100% rename from test/gestalt_files/test_linux_1/foo.rb rename to test/gestalt_files/linux_1/foo.rb diff --git a/test/gestalt_files/rails/foo.rb b/test/gestalt_files/rails/foo.rb new file mode 100644 index 0000000..7f10e75 --- /dev/null +++ b/test/gestalt_files/rails/foo.rb @@ -0,0 +1,3 @@ +# we're impersonating a rails app +RAILS_ROOT = '/' +some_rails_code = "true" diff --git a/test/gestalt_files/test_ruby_just_enough/foo.c b/test/gestalt_files/ruby_just_enough/foo.c similarity index 100% rename from test/gestalt_files/test_ruby_just_enough/foo.c rename to test/gestalt_files/ruby_just_enough/foo.c diff --git a/test/gestalt_files/test_ruby_just_enough/foo.rb b/test/gestalt_files/ruby_just_enough/foo.rb similarity index 100% rename from test/gestalt_files/test_ruby_just_enough/foo.rb rename to test/gestalt_files/ruby_just_enough/foo.rb diff --git a/test/gestalt_files/test_ruby_not_enough/foo.c b/test/gestalt_files/ruby_not_enough/foo.c similarity index 100% rename from test/gestalt_files/test_ruby_not_enough/foo.c rename to test/gestalt_files/ruby_not_enough/foo.c diff --git a/test/gestalt_files/test_ruby_not_enough/foo.rb b/test/gestalt_files/ruby_not_enough/foo.rb similarity index 100% rename from test/gestalt_files/test_ruby_not_enough/foo.rb rename to test/gestalt_files/ruby_not_enough/foo.rb diff --git a/test/gestalt_files/test_win32_enough/bar.c b/test/gestalt_files/win32_enough/bar.c similarity index 100% rename from test/gestalt_files/test_win32_enough/bar.c rename to test/gestalt_files/win32_enough/bar.c diff --git a/test/gestalt_files/test_win32_enough/foo.c b/test/gestalt_files/win32_enough/foo.c similarity index 100% rename from test/gestalt_files/test_win32_enough/foo.c rename to test/gestalt_files/win32_enough/foo.c diff --git a/test/gestalt_files/test_win32_not_enough/foo.c b/test/gestalt_files/win32_not_enough/foo.c similarity index 100% rename from test/gestalt_files/test_win32_not_enough/foo.c rename to test/gestalt_files/win32_not_enough/foo.c diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index dd53e7a..b71f534 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -6,27 +6,31 @@ class PlatformTest < Test::Unit::TestCase def test_win32_not_enough - assert_platform('test_win32_not_enough') + assert_platform('win32_not_enough') end def test_win32_enough - assert_platform('test_win32_enough', Win32) + assert_platform('win32_enough', Win32) end def test_linux_1 - assert_platform('test_linux_1', POSIX, Linux) + assert_platform('linux_1', POSIX, Linux) end def test_ruby_just_enough - assert_platform('test_ruby_just_enough', Ruby) + assert_platform('ruby_just_enough', Ruby) end def test_ruby_not_enough - assert_platform('test_ruby_not_enough') + assert_platform('ruby_not_enough') end def test_cakephp - assert_platform('test_cakephp', CakePHP) + assert_platform('cakephp', CakePHP) + end + + def test_rails + assert_platform('rails', Ruby, Rails) end protected diff --git a/test/unit/source_file_list_test.rb b/test/unit/source_file_list_test.rb index f277944..7c5bda2 100644 --- a/test/unit/source_file_list_test.rb +++ b/test/unit/source_file_list_test.rb @@ -9,7 +9,7 @@ class SourceFileListTest < Ohcount::Test # end def test_language_facts - sfl = SourceFileList.new(:path => test_dir('test_win32_enough')) + sfl = SourceFileList.new(:path => test_dir('win32_enough')) sfl.analyze(:language) assert_equal 2, sfl.language_facts.filecount assert_equal 2, sfl.language_facts.c.code @@ -18,7 +18,7 @@ def test_language_facts end def test_gestalt_facts - sfl = SourceFileList.new(:path => test_dir('test_win32_enough')) + sfl = SourceFileList.new(:path => test_dir('win32_enough')) sfl.analyze(:gestalt) assert_equal [Win32], sfl.gestalt_facts.platforms end From f251850f9b3fd4276db7b56246024d32ec3ccace Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Thu, 6 Nov 2008 15:36:06 -0800 Subject: [PATCH 021/387] [NEW] Added java as a platform --- bin/ohcount | 2 +- lib/gestalt/library_rule.rb | 8 ++++++++ rules/libraries.rb | 4 ++++ rules/platforms.rb | 16 +++++++++++++++- test/gestalt_files/spring_framework/main.java | 7 +++++++ test/gestalt_files/spring_framework/spring.jar | 0 test/unit/gestalt/platform_test.rb | 4 ++++ 7 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 test/gestalt_files/spring_framework/main.java create mode 100644 test/gestalt_files/spring_framework/spring.jar diff --git a/bin/ohcount b/bin/ohcount index 965f4eb..2b1cd5d 100755 --- a/bin/ohcount +++ b/bin/ohcount @@ -71,7 +71,7 @@ class OhcountCommandLine # Find all source code files def detect source_file_list.each_source_file do |s| - puts "#{s.polyglot}\t#{s.filename}" if s.polyglot + puts "#{s.polyglot}\t#{s.filename}" end end diff --git a/lib/gestalt/library_rule.rb b/lib/gestalt/library_rule.rb index fa69c78..c404f3c 100644 --- a/lib/gestalt/library_rule.rb +++ b/lib/gestalt/library_rule.rb @@ -41,8 +41,16 @@ def initialize(filenames) end def trigger?(source_file) + # string_matches filenames.include?(source_file.basename) end + + def regex + #@regexp ||= begin + # filenames.collect + # Regexp.new("(" + keywords.join("|") + ")") + #end + end end class KeywordLibraryRule diff --git a/rules/libraries.rb b/rules/libraries.rb index 553b2a7..082d9d3 100644 --- a/rules/libraries.rb +++ b/rules/libraries.rb @@ -24,5 +24,9 @@ class BSDLib < Library c_keywords 'FTS_PHYSICAL' end + class SpringLibrary < Library + files 'spring.jar' + end + end end diff --git a/rules/platforms.rb b/rules/platforms.rb index 3f81dfb..faed1ff 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -1,5 +1,4 @@ # platforms - include Ohcount::Gestalt class POSIX < Platform @@ -26,9 +25,24 @@ class Rails < Platform ) end +class Java < Platform + trigger_language :java, :min_percent => 20 +end + class CakePHP < Platform t_and( trigger_language(:php, :min_percent => 15), trigger_libs(:cake_php_core) ) end + +class Java < Platform + trigger_language :java, :min_percent => 15 +end + +class SpringFramework < Platform + t_and( + trigger_platform(Java), + trigger_libs(:spring_library) + ) +end diff --git a/test/gestalt_files/spring_framework/main.java b/test/gestalt_files/spring_framework/main.java new file mode 100644 index 0000000..d762779 --- /dev/null +++ b/test/gestalt_files/spring_framework/main.java @@ -0,0 +1,7 @@ +class JavaClass +{ + int i = 1; + int i = 2; + int i = 3; +} + diff --git a/test/gestalt_files/spring_framework/spring.jar b/test/gestalt_files/spring_framework/spring.jar new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index b71f534..47a2228 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -29,6 +29,10 @@ def test_cakephp assert_platform('cakephp', CakePHP) end + def test_spring_framework + assert_platform('spring_framework', Java) + end + def test_rails assert_platform('rails', Ruby, Rails) end From 80807c1593034e37e586d5b167052db9d7484fd1 Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Thu, 6 Nov 2008 15:53:58 -0800 Subject: [PATCH 022/387] [NEW] FileTest now works with multiple args, and assumes they are all Regular Expressions [NEW] SpringFramework now recognized --- lib/gestalt/library_rule.rb | 11 ++++---- lib/ohcount/language_facts.rb | 1 + lib/ohcount/source_file.rb | 2 ++ lib/ohcount/source_file_list.rb | 5 +++- test/unit/gestalt/library_rule_test.rb | 8 ++++++ test/unit/gestalt/platform_test.rb | 48 +++++++++++++++++----------------- 6 files changed, 44 insertions(+), 31 deletions(-) diff --git a/lib/gestalt/library_rule.rb b/lib/gestalt/library_rule.rb index c404f3c..ccb4471 100644 --- a/lib/gestalt/library_rule.rb +++ b/lib/gestalt/library_rule.rb @@ -41,15 +41,14 @@ def initialize(filenames) end def trigger?(source_file) - # string_matches - filenames.include?(source_file.basename) + regex.match(source_file.filename) end def regex - #@regexp ||= begin - # filenames.collect - # Regexp.new("(" + keywords.join("|") + ")") - #end + @regex ||= begin + r = filenames.collect { |f| "(" + f + ")"}.join("|") + Regexp.new(r) + end end end diff --git a/lib/ohcount/language_facts.rb b/lib/ohcount/language_facts.rb index ae2c77e..3373588 100644 --- a/lib/ohcount/language_facts.rb +++ b/lib/ohcount/language_facts.rb @@ -12,6 +12,7 @@ def initialize end def process(source_file) + return unless source_file.source_code? source_file.language_breakdowns.each do |lb| lang = lb.name lang_fact = @fact_map[lang] ||= LanguageFact.new(lang) diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb index 8911db5..a8dd75b 100644 --- a/lib/ohcount/source_file.rb +++ b/lib/ohcount/source_file.rb @@ -70,6 +70,8 @@ def source_code? end def parse(&block) + @language_breakdowns = [] + return unless polyglot @language_breakdowns = Ohcount::parse(contents, polyglot, &block) end diff --git a/lib/ohcount/source_file_list.rb b/lib/ohcount/source_file_list.rb index 971fc1d..6a5faf3 100644 --- a/lib/ohcount/source_file_list.rb +++ b/lib/ohcount/source_file_list.rb @@ -62,7 +62,10 @@ def analyze(what = []) @language_facts = LanguageFacts.new if do_languages @gestalt_facts = GestaltFacts.new if do_gestalt - each_source_file do |source_file| + self.each do |file| + # we process each file - even if its not a source_code - for + # library rules sake - they sometimes want 'jar' files or something + source_file = SourceFile.new(file, :filename => self) @language_facts.process(source_file) if do_languages @gestalt_facts.process(source_file) if do_gestalt yield source_file if block_given? diff --git a/test/unit/gestalt/library_rule_test.rb b/test/unit/gestalt/library_rule_test.rb index a4fe234..c20fec7 100644 --- a/test/unit/gestalt/library_rule_test.rb +++ b/test/unit/gestalt/library_rule_test.rb @@ -27,6 +27,14 @@ def test_file_rule s = Ohcount::SourceFile.new('header.h') assert r.trigger?(s) end + + def test_file_rule_advanced + r = Ohcount::Gestalt::FileRule.new(['f[ab]o', 'foo']) + assert r.trigger?(Ohcount::SourceFile.new('fao')) + assert r.trigger?(Ohcount::SourceFile.new('fbo')) + assert r.trigger?(Ohcount::SourceFile.new('foo')) + assert !r.trigger?(Ohcount::SourceFile.new('fco')) + end end diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index 47a2228..86311c2 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -5,32 +5,32 @@ class PlatformTest < Test::Unit::TestCase - def test_win32_not_enough - assert_platform('win32_not_enough') - end - - def test_win32_enough - assert_platform('win32_enough', Win32) - end - - def test_linux_1 - assert_platform('linux_1', POSIX, Linux) - end - - def test_ruby_just_enough - assert_platform('ruby_just_enough', Ruby) - end - - def test_ruby_not_enough - assert_platform('ruby_not_enough') - end - - def test_cakephp - assert_platform('cakephp', CakePHP) - end +# def test_win32_not_enough +# assert_platform('win32_not_enough') +# end +# +# def test_win32_enough +# assert_platform('win32_enough', Win32) +# end +# +# def test_linux_1 +# assert_platform('linux_1', POSIX, Linux) +# end +# +# def test_ruby_just_enough +# assert_platform('ruby_just_enough', Ruby) +# end +# +# def test_ruby_not_enough +# assert_platform('ruby_not_enough') +# end +# +# def test_cakephp +# assert_platform('cakephp', CakePHP) +# end def test_spring_framework - assert_platform('spring_framework', Java) + assert_platform('spring_framework', Java, SpringFramework) end def test_rails From 193724fa096ee323f15e570d834502c8e2444644 Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Thu, 6 Nov 2008 15:56:25 -0800 Subject: [PATCH 023/387] [FIX] Default bin/ohcount now runs 'summary' - as expected (was running gestalt, by mistake) --- bin/ohcount | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/ohcount b/bin/ohcount index 2b1cd5d..5c78852 100755 --- a/bin/ohcount +++ b/bin/ohcount @@ -303,7 +303,7 @@ HELP end def run! - self.subcommand ||= :gestalt + self.subcommand ||= :summary if self.respond_to?(self.subcommand) self.send(self.subcommand) else From 933ac5d77602bb7fc14002c1df9333af32a41976 Mon Sep 17 00:00:00 2001 From: "andy@ohloh.net" Date: Thu, 6 Nov 2008 16:04:01 -0800 Subject: [PATCH 024/387] [NEW] Add simple AppleEvents, Mac platform --- rules/libraries.rb | 3 +++ rules/platforms.rb | 4 ++++ test/unit/gestalt/library_test.rb | 9 +++++++++ test/unit/gestalt/platform_test.rb | 4 ++++ 4 files changed, 20 insertions(+) diff --git a/rules/libraries.rb b/rules/libraries.rb index 082d9d3..d8710dc 100644 --- a/rules/libraries.rb +++ b/rules/libraries.rb @@ -28,5 +28,8 @@ class SpringLibrary < Library files 'spring.jar' end + class AppleEvents < Library + c_keywords 'AppleEvent', 'AEBuildAppleEvent' + end end end diff --git a/rules/platforms.rb b/rules/platforms.rb index faed1ff..06ecedb 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -46,3 +46,7 @@ class SpringFramework < Platform trigger_libs(:spring_library) ) end + +class Mac < Platform + trigger_libs(:apple_events) +end diff --git a/test/unit/gestalt/library_test.rb b/test/unit/gestalt/library_test.rb index 99c39c9..db9568a 100644 --- a/test/unit/gestalt/library_test.rb +++ b/test/unit/gestalt/library_test.rb @@ -34,6 +34,15 @@ def test_windows_constants assert_detected_lib(s, WindowsConstants, CKeywordRule) end + def test_apple_events + s = SourceFile.new("foo.c", :filenames => [], :contents => <<-INLINE_C + // fake apple event file + AppleEvent tAppleEvent; + INLINE_C + ) + assert_detected_lib(s, AppleEvents, CKeywordRule) + end + protected def assert_detected_lib(source_file, lib, triggered_rule) diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index 47a2228..7065513 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -37,6 +37,10 @@ def test_rails assert_platform('rails', Ruby, Rails) end + def test_mac + assert_platform('mac', Mac) + end + protected def assert_platform(path, *platforms) From e1563d19bd87991d61c4db33396428cc48a9df8b Mon Sep 17 00:00:00 2001 From: "andy@ohloh.net" Date: Thu, 6 Nov 2008 16:09:13 -0800 Subject: [PATCH 025/387] [FIX] missing directory --- test/gestalt_files/mac/foo.c | 1 + 1 file changed, 1 insertion(+) create mode 100644 test/gestalt_files/mac/foo.c diff --git a/test/gestalt_files/mac/foo.c b/test/gestalt_files/mac/foo.c new file mode 100644 index 0000000..c1e580d --- /dev/null +++ b/test/gestalt_files/mac/foo.c @@ -0,0 +1 @@ +AppleEvent tAppleEvent; From 3f03b0efd60327ec798979acd5bd82aeb33d2dc9 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 6 Nov 2008 16:11:32 -0800 Subject: [PATCH 026/387] [CHANGE] Remove the 'empty' Linux platform; leave only POSIX --- rules/platforms.rb | 4 ---- test/gestalt_files/{linux_1 => posix}/configure.in | 0 test/gestalt_files/{linux_1 => posix}/foo.c | 0 test/gestalt_files/{linux_1 => posix}/foo.rb | 0 test/unit/gestalt/platform_test.rb | 8 ++++---- 5 files changed, 4 insertions(+), 8 deletions(-) rename test/gestalt_files/{linux_1 => posix}/configure.in (100%) rename test/gestalt_files/{linux_1 => posix}/foo.c (100%) rename test/gestalt_files/{linux_1 => posix}/foo.rb (100%) diff --git a/rules/platforms.rb b/rules/platforms.rb index 06ecedb..923cbf5 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -10,10 +10,6 @@ class Win32 < Platform trigger_libs :windows_constants, :count => 2 end -class Linux < Platform - trigger_platform POSIX -end - class Ruby < Platform trigger_language :ruby, :min_percent => 15 end diff --git a/test/gestalt_files/linux_1/configure.in b/test/gestalt_files/posix/configure.in similarity index 100% rename from test/gestalt_files/linux_1/configure.in rename to test/gestalt_files/posix/configure.in diff --git a/test/gestalt_files/linux_1/foo.c b/test/gestalt_files/posix/foo.c similarity index 100% rename from test/gestalt_files/linux_1/foo.c rename to test/gestalt_files/posix/foo.c diff --git a/test/gestalt_files/linux_1/foo.rb b/test/gestalt_files/posix/foo.rb similarity index 100% rename from test/gestalt_files/linux_1/foo.rb rename to test/gestalt_files/posix/foo.rb diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index e1b3e06..c0fdd1d 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -13,10 +13,6 @@ class PlatformTest < Test::Unit::TestCase # assert_platform('win32_enough', Win32) # end # -# def test_linux_1 -# assert_platform('linux_1', POSIX, Linux) -# end -# # def test_ruby_just_enough # assert_platform('ruby_just_enough', Ruby) # end @@ -41,6 +37,10 @@ def test_mac assert_platform('mac', Mac) end + def test_posix + assert_platform('posix', POSIX) + end + protected def assert_platform(path, *platforms) From 940a83049a19d4e251b0711523e13233a4a26ec6 Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Thu, 6 Nov 2008 16:34:18 -0800 Subject: [PATCH 027/387] [NEW] File trigger for library rules now allows files that aren't strictly source code files (like jars) [FIX] We dont crash when parsing a directory [NEW] JQuery platform added --- lib/ohcount/source_file.rb | 13 ++++++- rules/libraries.rb | 5 ++- rules/platforms.rb | 9 +++++ test/detect_files/example.st | 0 test/detect_files/example.xsl | 0 test/detect_files/foo.exlib | 0 test/gestalt_files/jquery/jquery-1.2.6.min.js | 1 + test/unit/detector_test.rb | 4 +++ test/unit/gestalt/platform_test.rb | 50 +++++++++++++++------------ 9 files changed, 57 insertions(+), 25 deletions(-) create mode 100644 test/detect_files/example.st create mode 100644 test/detect_files/example.xsl create mode 100644 test/detect_files/foo.exlib create mode 100644 test/gestalt_files/jquery/jquery-1.2.6.min.js diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb index a8dd75b..ded72cf 100644 --- a/lib/ohcount/source_file.rb +++ b/lib/ohcount/source_file.rb @@ -56,7 +56,18 @@ def contents end def polyglot - @polyglot ||= Ohcount::Detector.detect(self) + @polyglot ||= begin + if file? + Ohcount::Detector.detect(self) + else + nil + end + end + end + + # returns true iff we represent a file (could be a dir) + def file? + File.file?(@file_location) || @contents end def basename diff --git a/rules/libraries.rb b/rules/libraries.rb index 082d9d3..522251e 100644 --- a/rules/libraries.rb +++ b/rules/libraries.rb @@ -25,8 +25,11 @@ class BSDLib < Library end class SpringLibrary < Library - files 'spring.jar' + files 'spring\.jar' end + class JQueryLibrary < Library + files 'jquery-\d.\d.\d.min.js' + end end end diff --git a/rules/platforms.rb b/rules/platforms.rb index faed1ff..8bbc17f 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -40,9 +40,18 @@ class Java < Platform trigger_language :java, :min_percent => 15 end +class Javascript < Platform + trigger_language :javascript, :min_percent => 20 +end + +class JQuery < Platform + trigger_libs :j_query_library +end + class SpringFramework < Platform t_and( trigger_platform(Java), trigger_libs(:spring_library) ) end + diff --git a/test/detect_files/example.st b/test/detect_files/example.st new file mode 100644 index 0000000..e69de29 diff --git a/test/detect_files/example.xsl b/test/detect_files/example.xsl new file mode 100644 index 0000000..e69de29 diff --git a/test/detect_files/foo.exlib b/test/detect_files/foo.exlib new file mode 100644 index 0000000..e69de29 diff --git a/test/gestalt_files/jquery/jquery-1.2.6.min.js b/test/gestalt_files/jquery/jquery-1.2.6.min.js new file mode 100644 index 0000000..0b035d7 --- /dev/null +++ b/test/gestalt_files/jquery/jquery-1.2.6.min.js @@ -0,0 +1 @@ +i = 1; diff --git a/test/unit/detector_test.rb b/test/unit/detector_test.rb index 72ba698..59e18dc 100644 --- a/test/unit/detector_test.rb +++ b/test/unit/detector_test.rb @@ -32,6 +32,10 @@ def do_detect_with_siblings(filename) SourceFile.new(filepath, {:filenames => filename}).detect end + def test_smalltalk + assert_equal "smalltalk", do_detect("example.st") + end + def test_matlab_or_objective_c assert_equal 'objective_c', do_detect("t1.m") assert_equal 'objective_c', do_detect("t2.m") diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index 86311c2..2461b98 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -5,29 +5,29 @@ class PlatformTest < Test::Unit::TestCase -# def test_win32_not_enough -# assert_platform('win32_not_enough') -# end -# -# def test_win32_enough -# assert_platform('win32_enough', Win32) -# end -# -# def test_linux_1 -# assert_platform('linux_1', POSIX, Linux) -# end -# -# def test_ruby_just_enough -# assert_platform('ruby_just_enough', Ruby) -# end -# -# def test_ruby_not_enough -# assert_platform('ruby_not_enough') -# end -# -# def test_cakephp -# assert_platform('cakephp', CakePHP) -# end + def test_win32_not_enough + assert_platform('win32_not_enough') + end + + def test_win32_enough + assert_platform('win32_enough', Win32) + end + + def test_linux_1 + assert_platform('linux_1', POSIX, Linux) + end + + def test_ruby_just_enough + assert_platform('ruby_just_enough', Ruby) + end + + def test_ruby_not_enough + assert_platform('ruby_not_enough') + end + + def test_cakephp + assert_platform('cakephp', CakePHP) + end def test_spring_framework assert_platform('spring_framework', Java, SpringFramework) @@ -37,6 +37,10 @@ def test_rails assert_platform('rails', Ruby, Rails) end + def test_jquery + assert_platform('jquery', Javascript, JQuery) + end + protected def assert_platform(path, *platforms) From 7df9a85b99c3c823cd7a9927a22de37aac14fa64 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 6 Nov 2008 16:52:34 -0800 Subject: [PATCH 028/387] [NEW] Plist files indicate mac platform --- rules/libraries.rb | 4 ++++ rules/platforms.rb | 2 +- test/gestalt_files/plist/Info.plist.in | 8 ++++++++ test/unit/gestalt/platform_test.rb | 4 ++++ 4 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 test/gestalt_files/plist/Info.plist.in diff --git a/rules/libraries.rb b/rules/libraries.rb index b92382f..41efa68 100644 --- a/rules/libraries.rb +++ b/rules/libraries.rb @@ -35,5 +35,9 @@ class JQueryLibrary < Library class AppleEvents < Library c_keywords 'AppleEvent', 'AEBuildAppleEvent' end + + class Plist < Library + files '\.plist' + end end end diff --git a/rules/platforms.rb b/rules/platforms.rb index 759299e..5b3e9ad 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -52,5 +52,5 @@ class SpringFramework < Platform end class Mac < Platform - trigger_libs(:apple_events) + trigger_libs(:apple_events, :plist) end diff --git a/test/gestalt_files/plist/Info.plist.in b/test/gestalt_files/plist/Info.plist.in new file mode 100644 index 0000000..eb7c10a --- /dev/null +++ b/test/gestalt_files/plist/Info.plist.in @@ -0,0 +1,8 @@ + + + + + CFBundleDevelopmentRegion + English + + diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index b64dd0f..7ece495 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -41,6 +41,10 @@ def test_mac assert_platform('mac', Mac) end + def test_plist + assert_platform('plist', Mac) + end + def test_posix assert_platform('posix', POSIX) end From 202381e1d47fb2842955627f360e4b2c445527f2 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 6 Nov 2008 17:15:16 -0800 Subject: [PATCH 029/387] [NEW] PHP platform --- rules/platforms.rb | 6 +++++- test/gestalt_files/php/main.php | 5 +++++ test/unit/gestalt/platform_test.rb | 6 +++++- 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 test/gestalt_files/php/main.php diff --git a/rules/platforms.rb b/rules/platforms.rb index 5b3e9ad..3f06843 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -25,9 +25,13 @@ class Java < Platform trigger_language :java, :min_percent => 20 end +class PHP < Platform + trigger_language :php, :min_percent => 15 +end + class CakePHP < Platform t_and( - trigger_language(:php, :min_percent => 15), + trigger_platform(PHP), trigger_libs(:cake_php_core) ) end diff --git a/test/gestalt_files/php/main.php b/test/gestalt_files/php/main.php new file mode 100644 index 0000000..2830618 --- /dev/null +++ b/test/gestalt_files/php/main.php @@ -0,0 +1,5 @@ + diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index 7ece495..a3beeff 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -22,7 +22,7 @@ def test_ruby_not_enough end def test_cakephp - assert_platform('cakephp', CakePHP) + assert_platform('cakephp', PHP, CakePHP) end def test_spring_framework @@ -37,6 +37,10 @@ def test_jquery assert_platform('jquery', Javascript, JQuery) end + def test_php + assert_platform('php', PHP) + end + def test_mac assert_platform('mac', Mac) end From a2cb987d921195431cbe7a457f48319e8a25b60f Mon Sep 17 00:00:00 2001 From: "andy@ohloh.net" Date: Thu, 6 Nov 2008 18:00:34 -0800 Subject: [PATCH 030/387] [NEW] find XWindows --- rules/libraries.rb | 5 +++++ rules/platforms.rb | 4 ++++ test/gestalt_files/xwindows/foo.c | 1 + test/unit/gestalt/library_test.rb | 9 +++++++++ test/unit/gestalt/platform_test.rb | 4 ++++ 5 files changed, 23 insertions(+) create mode 100644 test/gestalt_files/xwindows/foo.c diff --git a/rules/libraries.rb b/rules/libraries.rb index 41efa68..8eb8972 100644 --- a/rules/libraries.rb +++ b/rules/libraries.rb @@ -36,8 +36,13 @@ class AppleEvents < Library c_keywords 'AppleEvent', 'AEBuildAppleEvent' end + # Mac preference settings class Plist < Library files '\.plist' end + + class XWindowsLib < Library + c_headers 'Xlib.h', 'X11\/xpm.h' + end end end diff --git a/rules/platforms.rb b/rules/platforms.rb index 5b3e9ad..735c6a9 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -51,6 +51,10 @@ class SpringFramework < Platform ) end +class XWindows < Platform + trigger_libs :x_windows_lib +end + class Mac < Platform trigger_libs(:apple_events, :plist) end diff --git a/test/gestalt_files/xwindows/foo.c b/test/gestalt_files/xwindows/foo.c new file mode 100644 index 0000000..271aa6c --- /dev/null +++ b/test/gestalt_files/xwindows/foo.c @@ -0,0 +1 @@ +#include diff --git a/test/unit/gestalt/library_test.rb b/test/unit/gestalt/library_test.rb index db9568a..2abf9fb 100644 --- a/test/unit/gestalt/library_test.rb +++ b/test/unit/gestalt/library_test.rb @@ -43,6 +43,15 @@ def test_apple_events assert_detected_lib(s, AppleEvents, CKeywordRule) end + def test_xwindows + s = SourceFile.new("foo.c", :filenames => [], :contents => <<-INLINE_C + #include + INLINE_C + ) + assert_detected_lib(s, XWindowsLib, CHeaderRule) + end + + protected def assert_detected_lib(source_file, lib, triggered_rule) diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index 7ece495..980549c 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -49,6 +49,10 @@ def test_posix assert_platform('posix', POSIX) end + def test_x_windows + assert_platform('xwindows', XWindows) + end + protected def assert_platform(path, *platforms) From cfa76d79d9718e6202af89af1e62a09896db6e6c Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Thu, 6 Nov 2008 19:27:38 -0800 Subject: [PATCH 031/387] [INTERIM] Getting ready for tools and cleanup --- rules/libraries.rb | 4 ++++ rules/tools.rb | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/rules/libraries.rb b/rules/libraries.rb index b92382f..d60edba 100644 --- a/rules/libraries.rb +++ b/rules/libraries.rb @@ -3,6 +3,10 @@ module Ohcount module Gestalt + class VisualStudioFiles < Library + files '\.vcproj$', '\.vsproj$', '\.vbproj$', '\.vpb$', '\.sln$' + end + class GnuLib < Library c_headers 'pthread.h', 'xstrtol.h', 'xreadlink.h', 'fatal-signal.h', 'diacrit.h' end diff --git a/rules/tools.rb b/rules/tools.rb index c906753..2ad8d31 100644 --- a/rules/tools.rb +++ b/rules/tools.rb @@ -1,6 +1,8 @@ # Tools +include Ohcount::Gestalt + class VisualStudio < Tool - c_headers 'pthread.h', 'xstrtol.h', 'xreadlink.h', 'fatal-signal.h', 'diacrit.h' + trigger_libs :visual_studio_files end class Eclipse < Tool From f9dcce970372bd7274c7e6c307053aebccd212cf Mon Sep 17 00:00:00 2001 From: "andy@ohloh.net" Date: Fri, 7 Nov 2008 01:48:24 -0800 Subject: [PATCH 032/387] [NEW] add basic KDE support --- rules/libraries.rb | 4 ++++ rules/platforms.rb | 4 ++++ test/gestalt_files/kde/foo.c | 1 + test/unit/gestalt/library_test.rb | 8 ++++++++ test/unit/gestalt/platform_test.rb | 4 ++++ 5 files changed, 21 insertions(+) create mode 100644 test/gestalt_files/kde/foo.c diff --git a/rules/libraries.rb b/rules/libraries.rb index 8eb8972..e5d3d21 100644 --- a/rules/libraries.rb +++ b/rules/libraries.rb @@ -44,5 +44,9 @@ class Plist < Library class XWindowsLib < Library c_headers 'Xlib.h', 'X11\/xpm.h' end + + class KDEHeaders < Library + c_headers 'KDEInit.h', 'kdeversion.h' + end end end diff --git a/rules/platforms.rb b/rules/platforms.rb index 735c6a9..563393f 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -58,3 +58,7 @@ class XWindows < Platform class Mac < Platform trigger_libs(:apple_events, :plist) end + +class KDE < Platform + trigger_libs(:k_d_e_headers) +end diff --git a/test/gestalt_files/kde/foo.c b/test/gestalt_files/kde/foo.c new file mode 100644 index 0000000..ec50a2d --- /dev/null +++ b/test/gestalt_files/kde/foo.c @@ -0,0 +1 @@ +#include diff --git a/test/unit/gestalt/library_test.rb b/test/unit/gestalt/library_test.rb index 2abf9fb..55c0755 100644 --- a/test/unit/gestalt/library_test.rb +++ b/test/unit/gestalt/library_test.rb @@ -51,6 +51,14 @@ def test_xwindows assert_detected_lib(s, XWindowsLib, CHeaderRule) end + def test_kde + s = SourceFile.new("foo.c", :filenames => [], :contents => <<-INLINE_C + #include + INLINE_C + ) + assert_detected_lib(s, KDEHeaders, CHeaderRule) + end + protected diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index 980549c..b5e60e3 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -53,6 +53,10 @@ def test_x_windows assert_platform('xwindows', XWindows) end + def test_kde + assert_platform('kde', KDE) + end + protected def assert_platform(path, *platforms) From cccb0e935b7459524bf1954d816815f8eacf5e5c Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Fri, 7 Nov 2008 02:06:00 -0800 Subject: [PATCH 033/387] [NEW] Yanked libraries and merged their rules into Platform rules --- lib/gestalt/library.rb | 81 ------------------- lib/gestalt/library_rule.rb | 89 --------------------- lib/gestalt/platform.rb | 139 +++++---------------------------- lib/gestalt/rules/and_rule.rb | 15 ++++ lib/gestalt/rules/c_header_rule.rb | 27 +++++++ lib/gestalt/rules/c_keyword_rule.rb | 16 ++++ lib/gestalt/rules/file_rule.rb | 42 ++++++++++ lib/gestalt/rules/filename_rule.rb | 25 ++++++ lib/gestalt/rules/keyword_rule.rb | 26 ++++++ lib/gestalt/rules/language_rule.rb | 22 ++++++ lib/gestalt/rules/logical_rule.rb | 62 +++++++++++++++ lib/gestalt/rules/or_rule.rb | 13 +++ lib/gestalt/rules/platform_rule.rb | 18 +++++ lib/gestalt/rules/rule.rb | 43 ++++++++++ lib/ohcount.rb | 3 - lib/ohcount/gestalt_facts.rb | 10 +-- rules/platforms.rb | 72 +++++++++-------- test/unit/gestalt/file_rule_test.rb | 41 ++++++++++ test/unit/gestalt/library_rule_test.rb | 40 ---------- test/unit/gestalt/library_test.rb | 65 --------------- test/unit/gestalt/platform_test.rb | 8 +- test/unit/gestalt/rule_test.rb | 10 +++ 22 files changed, 426 insertions(+), 441 deletions(-) delete mode 100644 lib/gestalt/library.rb delete mode 100644 lib/gestalt/library_rule.rb create mode 100644 lib/gestalt/rules/and_rule.rb create mode 100644 lib/gestalt/rules/c_header_rule.rb create mode 100644 lib/gestalt/rules/c_keyword_rule.rb create mode 100644 lib/gestalt/rules/file_rule.rb create mode 100644 lib/gestalt/rules/filename_rule.rb create mode 100644 lib/gestalt/rules/keyword_rule.rb create mode 100644 lib/gestalt/rules/language_rule.rb create mode 100644 lib/gestalt/rules/logical_rule.rb create mode 100644 lib/gestalt/rules/or_rule.rb create mode 100644 lib/gestalt/rules/platform_rule.rb create mode 100644 lib/gestalt/rules/rule.rb create mode 100644 test/unit/gestalt/file_rule_test.rb delete mode 100644 test/unit/gestalt/library_rule_test.rb delete mode 100644 test/unit/gestalt/library_test.rb create mode 100644 test/unit/gestalt/rule_test.rb diff --git a/lib/gestalt/library.rb b/lib/gestalt/library.rb deleted file mode 100644 index fef8361..0000000 --- a/lib/gestalt/library.rb +++ /dev/null @@ -1,81 +0,0 @@ -require 'lib/gestalt/library_rule' - -module Ohcount - module Gestalt - - # A library represents the binding to a specific 'library'. The class methods - # allow the detection of the library. - class Library - attr_reader :triggered_rules - - def initialize(*rules) - @triggered_rules = rules - end - - def self.rules - @rules ||= [] - end - - def self.c_headers(*header_names) - rules << CHeaderRule.new(header_names) - end - - def self.files(*filenames) - rules << FileRule.new(filenames) - end - - def self.c_keywords(*keywords) - rules << CKeywordRule.new(keywords) - end - - def to_sym - self.class.to_sym - end - - def self.method_missing(m,*args) - if /(.*)_keywords$/ =~ m.to_s - language = $1 - return rules << KeywordLibraryRule.new(language,args) - end - super - end - - # when tallying up libraries, its easier to - # use symbol names instead of class names - # to_sym maps FooLib to :foo_lib - def self.to_sym - @symbol ||= begin - to_s =~ /([^:]*)$/ - naked_classname = $1 - chars = naked_classname.scan(/./) - chars[0] = chars[0].downcase - ruby_s = chars.collect do |char| - char.downcase == char ? char : "_" + char.downcase - end.to_s - ruby_s.intern - end - end - - def self.detect_libraries(source_file) - descendants.inject([]) do |a, l| - r = l.triggered_rule(source_file) - r ? ( a << l.new(r)) : a - end - end - - def self.triggered_rule(source_file) - rules.each do |r| - return r if r.trigger?(source_file) - end - nil - end - - # tricky code to let us track the descendants... - class << self - def children() @children ||= [] end - def inherited(other) children << other and super end - def descendants() children.inject([]){|d,c| d.push(c, *c.descendants)} end - end - end - end -end diff --git a/lib/gestalt/library_rule.rb b/lib/gestalt/library_rule.rb deleted file mode 100644 index ccb4471..0000000 --- a/lib/gestalt/library_rule.rb +++ /dev/null @@ -1,89 +0,0 @@ -module Ohcount - module Gestalt - - class LibraryRule - def ==(other) - return false unless self.class == other.class - return false unless self.instance_variables == other.instance_variables - self.instance_variables.each do |v| - return false unless self.send(v[1..-1]) == other.send(v[1..-1]) - end - true - end - end - - class CHeaderRule < LibraryRule - attr_reader :headers - - def initialize(*headers) - @headers = headers - end - - def trigger?(source_file) - return false unless ['c','cpp'].include?(source_file.polyglot) - regexp.match(source_file.language_breakdowns('c').code) || - regexp.match(source_file.language_breakdowns('cpp').code) - end - - def regexp - @regexp ||= begin - header_term = "(" + headers.join("|") + ")" - Regexp.new("include\s+['<\"]#{ header_term }[\">']", Regexp::IGNORECASE) - end - end - end - - class FileRule < LibraryRule - attr_reader :filenames - - def initialize(filenames) - @filenames = filenames - end - - def trigger?(source_file) - regex.match(source_file.filename) - end - - def regex - @regex ||= begin - r = filenames.collect { |f| "(" + f + ")"}.join("|") - Regexp.new(r) - end - end - end - - class KeywordLibraryRule - attr_reader :keywords, :language - - def initialize(language, *keywords) - @language = language - @keywords = keywords - end - - def trigger?(source_file) - return unless source_file.language_breakdowns(language) - regexp.match(source_file.language_breakdowns(language).code) - end - - def regexp - @regexp ||= begin - Regexp.new("(" + keywords.join("|") + ")") - end - end - end - - class CKeywordRule < KeywordLibraryRule - - def initialize(*keywords) - super('c',*keywords) - end - - def trigger?(source_file) - return false unless ['c','cpp'].include?(source_file.polyglot) - regexp.match(source_file.language_breakdowns('c').code) || - regexp.match(source_file.language_breakdowns('cpp').code) - end - end - - end -end diff --git a/lib/gestalt/platform.rb b/lib/gestalt/platform.rb index 9e6a1b9..1b15bb0 100644 --- a/lib/gestalt/platform.rb +++ b/lib/gestalt/platform.rb @@ -1,15 +1,24 @@ -require 'lib/gestalt/library' -#require 'lib/gestalt/platforms/platform' +require 'lib/gestalt/rules/rule' +require 'lib/gestalt/rules/logical_rule' +require 'lib/gestalt/rules/or_rule' +require 'lib/gestalt/rules/and_rule' +require 'lib/gestalt/rules/language_rule' +require 'lib/gestalt/rules/file_rule' +require 'lib/gestalt/rules/filename_rule' +require 'lib/gestalt/rules/c_header_rule' +require 'lib/gestalt/rules/keyword_rule' +require 'lib/gestalt/rules/c_keyword_rule' +require 'lib/gestalt/rules/platform_rule' module Ohcount module Gestalt class Platform - # platform triggers are assumed to be, at the top level, + # platform rules are assumed to be, at the top level, # OR-ed. In other words, any one rule will trigger that platform. - # That's why we keep a top-level OrTrigger around. + # That's why we keep a top-level OrRule around. def self.top_level_or - @top_level_or ||= OrTrigger.new + @top_level_or ||= OrRule.new end # we delegate to the top_level_or trigger @@ -17,6 +26,11 @@ def self.method_missing(method, *args) top_level_or.send(method, *args) end + def self.triggered?(g) + top_level_or.triggered?(g) + + end + # tricky code to let us track the descendants... class << self def children() @children ||= [] end @@ -25,121 +39,6 @@ def descendants() children.inject([]){|d,c| d.push(c, *c.descendants)} end end end - - class PTrigger - end - - class LogicalTrigger < PTrigger - attr_reader :triggers - - def initialize(*triggers) - @triggers = triggers - end - - def new_trigger(t_class, *args) - # since we might be nesting logical triggers, we must do remove - # any 'grandchildren triggers' from our list, since we are giving - args.each do |a| - next unless a.is_a?(PTrigger) - @triggers.delete(a) - end - t = t_class.new(*args) - triggers << t - t - end - - def t_or(*args) - new_trigger OrTrigger, *args - end - - def t_and(*args) - new_trigger AndTrigger, *args - end - - def trigger_libs(*args) - new_trigger LibsTrigger, *args - end - - def trigger_platform(*args) - new_trigger PlatformTrigger, *args - end - - def trigger_language(*args) - new_trigger LanguageTrigger, *args - end - end - - # Will trigger if any sub-trigger does - class OrTrigger < LogicalTrigger - def triggered?(g_attr) - triggers.each do |t| - return t if t.triggered?(g_attr) - end - nil - end - end - - # Will trigger if all sub-triggers do - class AndTrigger < LogicalTrigger - def triggered?(g) - triggers.each do |t| - return nil unless t.triggered?(g) - end - self - end - end - - # will trigger if any libs were detected - # options: - # :count => minimum number of detections (default 1) - class LibsTrigger < PTrigger - attr_reader :lib_symbols - attr_reader :count - - def initialize(*args) - options = args.last.is_a?(::Hash) ? args.pop : {} - @count = options.delete(:count) || 1 - raise "Unrecognized LibsTrigger options '#{ options.keys.inspect }'" if options.any? - @lib_symbols = args - end - - def triggered?(g) - c = count - lib_symbols.each do |ls| - c -= g.lib_counts[ls].to_i - return self if c <= 0 - end - nil - end - end - - class PlatformTrigger < PTrigger - attr_reader :platform - - def initialize(platform) - @platform = platform - end - - def triggered?(g) - g.platforms.include?(platform) - end - end - - class LanguageTrigger < PTrigger - attr_reader :language - attr_reader :min_percent - - def initialize(language, options= {}) - @min_percent = options.delete(:min_percent) || 0 - raise "Unrecognized LanguageTrigger options '#{ options.keys.inspect }'" if options.any? - @language = language - end - - def triggered?(g) - return self if g.includes_language?(language, min_percent) - end - - end end end diff --git a/lib/gestalt/rules/and_rule.rb b/lib/gestalt/rules/and_rule.rb new file mode 100644 index 0000000..9b3553b --- /dev/null +++ b/lib/gestalt/rules/and_rule.rb @@ -0,0 +1,15 @@ +module Ohcount + module Gestalt + # Will trigger if all sub-rules do + class AndRule < LogicalRule + def triggered?(g_facts) + rules.each do |r| + return nil unless r.triggered?(g_facts) + end + self + end + end + end +end + + diff --git a/lib/gestalt/rules/c_header_rule.rb b/lib/gestalt/rules/c_header_rule.rb new file mode 100644 index 0000000..bcc83ee --- /dev/null +++ b/lib/gestalt/rules/c_header_rule.rb @@ -0,0 +1,27 @@ +module Ohcount + module Gestalt + # Triggers if a c or cpp header is present + class CHeaderRule < FileRule + attr_reader :headers + + def initialize(*args) + options = args.pop if args.last.is_a?(Hash) + @headers = args + super(options) + end + + def trigger_file?(source_file) + return false unless ['c','cpp'].include?(source_file.polyglot) + regexp.match(source_file.language_breakdowns('c').code) || + regexp.match(source_file.language_breakdowns('cpp').code) + end + + def regexp + @regexp ||= begin + header_term = "(" + headers.join("|") + ")" + Regexp.new("include\s+['<\"]#{ header_term }[\">']", Regexp::IGNORECASE) + end + end + end + end +end diff --git a/lib/gestalt/rules/c_keyword_rule.rb b/lib/gestalt/rules/c_keyword_rule.rb new file mode 100644 index 0000000..2827cb4 --- /dev/null +++ b/lib/gestalt/rules/c_keyword_rule.rb @@ -0,0 +1,16 @@ +module Ohcount + module Gestalt + class CKeywordRule < KeywordRule + + def initialize(*keywords) + super('c',*keywords) + end + + def trigger_file?(source_file) + return false unless ['c','cpp'].include?(source_file.polyglot) + regexp.match(source_file.language_breakdowns('c').code) || + regexp.match(source_file.language_breakdowns('cpp').code) + end + end + end +end diff --git a/lib/gestalt/rules/file_rule.rb b/lib/gestalt/rules/file_rule.rb new file mode 100644 index 0000000..31abdf5 --- /dev/null +++ b/lib/gestalt/rules/file_rule.rb @@ -0,0 +1,42 @@ +module Ohcount + module Gestalt + # an abstract base class representing a rule based + # on an individual file's attribute (like + # code content, or filename, etc..) + class FileRule < Rule + attr_reader :min_count + + def initialize(args = {}) + args ||= {} + @min_count = 1 + args.each do |k,v| + case k + when :min then @min_count = v + else raise ArgumentError.new("Unrecognized option: #{ k.inspect }") + end + end + FileRule.add_instance(self) + end + + def triggered?(g) + g.file_rules[self].to_i >= min_count + end + + def self.rules_triggered_by(source_file) + rules = instances.find_all do |r| + r.trigger_file?(source_file) + end + rules + end + + def self.instances + @instances ||= [] + end + + def self.add_instance(r) + instances << r + end + + end + end +end diff --git a/lib/gestalt/rules/filename_rule.rb b/lib/gestalt/rules/filename_rule.rb new file mode 100644 index 0000000..ee6e619 --- /dev/null +++ b/lib/gestalt/rules/filename_rule.rb @@ -0,0 +1,25 @@ +module Ohcount + module Gestalt + # rule based a the name of the file + class FilenameRule < FileRule + attr_reader :filenames + + def initialize(*args) + options = args.pop if args.last.is_a?(Hash) + @filenames = args + super(options) + end + + def trigger_file?(source_file) + regex.match(source_file.filename) + end + + def regex + @regex ||= begin + r = filenames.collect { |f| "(" + f + ")"}.join("|") + Regexp.new(r) + end + end + end + end +end diff --git a/lib/gestalt/rules/keyword_rule.rb b/lib/gestalt/rules/keyword_rule.rb new file mode 100644 index 0000000..17891dc --- /dev/null +++ b/lib/gestalt/rules/keyword_rule.rb @@ -0,0 +1,26 @@ +module Ohcount + module Gestalt + class KeywordRule < FileRule + attr_reader :keywords, :language + + def initialize(language, *args) + options = args.pop if args.last.is_a?(Hash) + keywords = args + @language = language + @keywords = keywords + super(options) + end + + def trigger_file?(source_file) + return unless source_file.language_breakdowns(language) + regexp.match(source_file.language_breakdowns(language).code) + end + + def regexp + @regexp ||= begin + Regexp.new("(" + keywords.join("|") + ")") + end + end + end + end +end diff --git a/lib/gestalt/rules/language_rule.rb b/lib/gestalt/rules/language_rule.rb new file mode 100644 index 0000000..70c55d5 --- /dev/null +++ b/lib/gestalt/rules/language_rule.rb @@ -0,0 +1,22 @@ +module Ohcount + module Gestalt + + # states that a platform depends on a programming + # language being at least :min_percent + class LanguageRule < Rule + attr_reader :language + attr_reader :min_percent + + def initialize(language, options= {}) + @min_percent = options.delete(:min_percent) || 0 + raise "Unrecognized LanguageRule options '#{ options.keys.inspect }'" if options.any? + @language = language + end + + def triggered?(g) + return self if g.includes_language?(language, min_percent) + end + + end + end +end diff --git a/lib/gestalt/rules/logical_rule.rb b/lib/gestalt/rules/logical_rule.rb new file mode 100644 index 0000000..f363755 --- /dev/null +++ b/lib/gestalt/rules/logical_rule.rb @@ -0,0 +1,62 @@ +module Ohcount + module Gestalt + class LogicalRule < Rule + attr_reader :rules + + def initialize(*rules) + @rules = rules + end + + def new_rule(r_class, *args) + # since we might be nesting logical rules, we must remove + # any 'grandchildren rules' from our list, since we are giving + args.each do |a| + next unless a.is_a?(Rule) + @rules.delete(a) + end + r = r_class.new(*args) + @rules << r + r + end + + def _or(*args) + new_rule OrRule, *args + end + + def _and(*args) + new_rule AndRule, *args + end + + def platform(*args) + new_rule PlatformRule, *args + end + + def language(*args) + new_rule LanguageRule, *args + end + + # file rules + def c_headers(*args) + new_rule CHeaderRule, *args + end + + def filenames(*args) + new_rule FilenameRule, *args + end + + def c_keywords(*args) + new_rule CKeywordRule, *args + end + + def method_missing(m,*args) + if /(.*)_keywords$/ =~ m.to_s + language = $1 + new_args = [language] + args + return new_rule(KeywordRule, *new_args) + end + super + end + + end + end +end diff --git a/lib/gestalt/rules/or_rule.rb b/lib/gestalt/rules/or_rule.rb new file mode 100644 index 0000000..4fa35ea --- /dev/null +++ b/lib/gestalt/rules/or_rule.rb @@ -0,0 +1,13 @@ +module Ohcount + module Gestalt + # Will trigger if any sub-rule does + class OrRule < LogicalRule + def triggered?(g_facts) + rules.each do |r| + return r if r.triggered?(g_facts) + end + nil + end + end + end +end diff --git a/lib/gestalt/rules/platform_rule.rb b/lib/gestalt/rules/platform_rule.rb new file mode 100644 index 0000000..9ec5c2b --- /dev/null +++ b/lib/gestalt/rules/platform_rule.rb @@ -0,0 +1,18 @@ +module Ohcount + module Gestalt + + # states that a platform depends on another platform + # being true. + class PlatformRule < Rule + attr_reader :platform + + def initialize(platform) + @platform = platform + end + + def triggered?(g_facts) + g_facts.platforms.include?(platform) + end + end + end +end diff --git a/lib/gestalt/rules/rule.rb b/lib/gestalt/rules/rule.rb new file mode 100644 index 0000000..2274c7d --- /dev/null +++ b/lib/gestalt/rules/rule.rb @@ -0,0 +1,43 @@ +module Ohcount + module Gestalt + class Rule + def ==(other) + return false unless self.class == other.class + return false unless self.instance_variables == other.instance_variables + self.instance_variables.each do |v| + return false unless self.send(v[1..-1]) == other.send(v[1..-1]) + end + true + end + + def to_sym + self.class.to_sym + end + + # when tallying up libraries, its easier to + # use symbol names instead of class names + # to_sym maps FooLib to :foo_lib + def self.to_sym + @symbol ||= begin + to_s =~ /([^:]*)$/ + naked_classname = $1 + chars = naked_classname.scan(/./) + chars[0] = chars[0].downcase + ruby_s = chars.collect do |char| + char.downcase == char ? char : "_" + char.downcase + end.to_s + ruby_s.intern + end + end + + def self.method_missing(m,*args) + if /(.*)_keywords$/ =~ m.to_s + language = $1 + return rules << KeywordLibraryRule.new(language,args) + end + super + end + + end + end +end diff --git a/lib/ohcount.rb b/lib/ohcount.rb index cd21de4..ecac09b 100644 --- a/lib/ohcount.rb +++ b/lib/ohcount.rb @@ -23,11 +23,8 @@ module Ohcount require "lib/ohcount/source_file_list" require "lib/licenses/license_sniffer" - -require "lib/gestalt/library" require "lib/gestalt/platform" # require the dynamic rules -require 'rules/libraries' require 'rules/platforms' diff --git a/lib/ohcount/gestalt_facts.rb b/lib/ohcount/gestalt_facts.rb index f2fa8e2..5ec8a67 100644 --- a/lib/ohcount/gestalt_facts.rb +++ b/lib/ohcount/gestalt_facts.rb @@ -2,18 +2,18 @@ module Ohcount # Represents language statistics for a collection of files class GestaltFacts - attr_accessor :platforms, :lib_counts, :language_counts + attr_accessor :platforms, :file_rules, :language_counts def initialize @platforms = [] - @lib_counts = {} + @file_rules = {} @language_counts = {} end def process(source_file) - Library.detect_libraries(source_file).collect { |library| library.to_sym }.each do |l| - @lib_counts[l] ||= 0 - @lib_counts[l] += 1 + FileRule.rules_triggered_by(source_file).each do |r| + @file_rules[r] ||= 0 + @file_rules[r] += 1 end source_file.language_breakdowns.each do |lb| @language_counts[lb.name.intern] ||= 0 diff --git a/rules/platforms.rb b/rules/platforms.rb index 735c6a9..0879ff9 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -2,59 +2,63 @@ include Ohcount::Gestalt class POSIX < Platform - trigger_libs :gnu_lib - trigger_language :autoconf + # gnu_lib + c_headers 'pthread.h', 'xstrtol.h', 'xreadlink.h', 'fatal-signal.h', 'diacrit.h' + + # autoconf means m4 (unix macro processor) + language :autoconf end class Win32 < Platform - trigger_libs :windows_constants, :count => 2 + c_headers 'windows.h' + c_keywords 'WM_PAINT', 'ReleaseDC', 'WndProc', :min => 2 end - + class Ruby < Platform - trigger_language :ruby, :min_percent => 15 + language :ruby, :min_percent => 15 end class Rails < Platform - t_and( - trigger_libs(:rails_core), - trigger_platform(Ruby) - ) -end - -class Java < Platform - trigger_language :java, :min_percent => 20 + _and( + platform(Ruby), + ruby_keywords("RAILS_ROOT") + ) end - -class CakePHP < Platform - t_and( - trigger_language(:php, :min_percent => 15), - trigger_libs(:cake_php_core) - ) -end - + class Java < Platform - trigger_language :java, :min_percent => 15 + language :java, :min_percent => 15 end - + class Javascript < Platform - trigger_language :javascript, :min_percent => 20 + language :javascript, :min_percent => 20 end class JQuery < Platform - trigger_libs :j_query_library + filenames 'jquery-\d.\d.\d.min.js' end - + class SpringFramework < Platform - t_and( - trigger_platform(Java), - trigger_libs(:spring_library) - ) + _and( + platform(Java), + filenames('spring\.jar$') + ) end - + class XWindows < Platform - trigger_libs :x_windows_lib + c_headers 'Xlib.h', 'X11\/xpm.h' end - + class Mac < Platform - trigger_libs(:apple_events, :plist) + # apple events + c_keywords 'AppleEvent', 'AEBuildAppleEvent' + + # plist is a mac thing, right? + filenames '\.plist' +end + +class CakePHP < Platform + _and( + language(:php, :min_percent => 15), + php_keywords('CAKE_CORE_INCLUDE_PATH') + ) end diff --git a/test/unit/gestalt/file_rule_test.rb b/test/unit/gestalt/file_rule_test.rb new file mode 100644 index 0000000..09cc4b8 --- /dev/null +++ b/test/unit/gestalt/file_rule_test.rb @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class FileRuleTest < Test::Unit::TestCase + + def test_trigger_c_header + r = Ohcount::Gestalt::CHeaderRule.new('foo.h') + s = Ohcount::SourceFile.new('header.h', :contents => <<-H_FILE + // a comment + include 'foo.h' + H_FILE + ) + assert r.trigger_file?(s) + end + + def test_c_keyword_rule + r = Ohcount::Gestalt::CKeywordRule.new('WM_PAINT') + s = Ohcount::SourceFile.new('header.h', :contents => <<-H_FILE + // a comment + (WM_PAINT) + H_FILE + ) + assert r.trigger_file?(s) + end + + def test_filename_rule + r = Ohcount::Gestalt::FilenameRule.new('header.h') + s = Ohcount::SourceFile.new('header.h') + assert r.trigger_file?(s) + end + + def test_filename_rule_advanced + r = Ohcount::Gestalt::FilenameRule.new('f[ab]o', 'foo') + assert r.trigger_file?(Ohcount::SourceFile.new('fao')) + assert r.trigger_file?(Ohcount::SourceFile.new('fbo')) + assert r.trigger_file?(Ohcount::SourceFile.new('foo')) + assert !r.trigger_file?(Ohcount::SourceFile.new('fco')) + end +end + + + diff --git a/test/unit/gestalt/library_rule_test.rb b/test/unit/gestalt/library_rule_test.rb deleted file mode 100644 index c20fec7..0000000 --- a/test/unit/gestalt/library_rule_test.rb +++ /dev/null @@ -1,40 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class LibraryRuleTest < Test::Unit::TestCase - - def test_trigger_c_header - r = Ohcount::Gestalt::CHeaderRule.new('foo.h') - s = Ohcount::SourceFile.new('header.h', :contents => <<-H_FILE - // a comment - include 'foo.h' - H_FILE - ) - assert r.trigger?(s) - end - - def test_c_keyword_rule - r = Ohcount::Gestalt::CKeywordRule.new('WM_PAINT') - s = Ohcount::SourceFile.new('header.h', :contents => <<-H_FILE - // a comment - (WM_PAINT) - H_FILE - ) - assert r.trigger?(s) - end - - def test_file_rule - r = Ohcount::Gestalt::FileRule.new('header.h') - s = Ohcount::SourceFile.new('header.h') - assert r.trigger?(s) - end - - def test_file_rule_advanced - r = Ohcount::Gestalt::FileRule.new(['f[ab]o', 'foo']) - assert r.trigger?(Ohcount::SourceFile.new('fao')) - assert r.trigger?(Ohcount::SourceFile.new('fbo')) - assert r.trigger?(Ohcount::SourceFile.new('foo')) - assert !r.trigger?(Ohcount::SourceFile.new('fco')) - end -end - - diff --git a/test/unit/gestalt/library_test.rb b/test/unit/gestalt/library_test.rb deleted file mode 100644 index 2abf9fb..0000000 --- a/test/unit/gestalt/library_test.rb +++ /dev/null @@ -1,65 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -include Ohcount -include Ohcount::Gestalt - -class TestLibrary < Ohcount::Gestalt::Library - c_headers "foobar.h" -end - -class LibraryTest < Test::Unit::TestCase - def test_descendants - assert Library.descendants.include?(TestLibrary) - end - - def test_gnulib - s = SourceFile.new("foo.h", :filenames => [], :contents => <<-INLINE_C - include ; - INLINE_C - ) - assert_detected_lib(s, GnuLib, CHeaderRule) - - s = SourceFile.new("foo.h", :filenames => [], :contents => <<-INLINE_C - include 'diacrit.h'; - INLINE_C - ) - assert_detected_lib(s, GnuLib, CHeaderRule) - end - - def test_windows_constants - s = SourceFile.new("foo.c", :filenames => [], :contents => <<-INLINE_C - wc.lpfnWndProc = (WNDPROC) WndProc; - INLINE_C - ) - assert_detected_lib(s, WindowsConstants, CKeywordRule) - end - - def test_apple_events - s = SourceFile.new("foo.c", :filenames => [], :contents => <<-INLINE_C - // fake apple event file - AppleEvent tAppleEvent; - INLINE_C - ) - assert_detected_lib(s, AppleEvents, CKeywordRule) - end - - def test_xwindows - s = SourceFile.new("foo.c", :filenames => [], :contents => <<-INLINE_C - #include - INLINE_C - ) - assert_detected_lib(s, XWindowsLib, CHeaderRule) - end - - - protected - - def assert_detected_lib(source_file, lib, triggered_rule) - libs = Ohcount::Gestalt::Library.detect_libraries(source_file) - assert_equal 1, libs.size - assert_equal lib, libs[0].class - - assert_equal 1, libs[0].triggered_rules.size - assert_equal triggered_rule, libs[0].triggered_rules[0].class - end -end diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index 980549c..76ffe30 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -5,6 +5,10 @@ class PlatformTest < Test::Unit::TestCase + def test_cakephp + assert_platform('cakephp', CakePHP) + end + def test_win32_not_enough assert_platform('win32_not_enough') end @@ -21,10 +25,6 @@ def test_ruby_not_enough assert_platform('ruby_not_enough') end - def test_cakephp - assert_platform('cakephp', CakePHP) - end - def test_spring_framework assert_platform('spring_framework', Java, SpringFramework) end diff --git a/test/unit/gestalt/rule_test.rb b/test/unit/gestalt/rule_test.rb new file mode 100644 index 0000000..809c1aa --- /dev/null +++ b/test/unit/gestalt/rule_test.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class RuleTest < Test::Unit::TestCase + + def test_here + + end +end + + From 93c3f5f1c43038a9c85d7aa377c2f51206ebe28e Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Fri, 7 Nov 2008 11:35:51 -0800 Subject: [PATCH 034/387] [FIX] Yanking unused libraries rules file (no longer needed) --- rules/libraries.rb | 56 ------------------------------------------------------ 1 file changed, 56 deletions(-) delete mode 100644 rules/libraries.rb diff --git a/rules/libraries.rb b/rules/libraries.rb deleted file mode 100644 index 945d903..0000000 --- a/rules/libraries.rb +++ /dev/null @@ -1,56 +0,0 @@ -# Libraries -# -module Ohcount - module Gestalt - - class VisualStudioFiles < Library - files '\.vcproj$', '\.vsproj$', '\.vbproj$', '\.vpb$', '\.sln$' - end - - class GnuLib < Library - c_headers 'pthread.h', 'xstrtol.h', 'xreadlink.h', 'fatal-signal.h', 'diacrit.h' - end - - class WindowsConstants < Library - c_headers 'windows.h' - c_keywords 'WM_PAINT', 'ReleaseDC', 'WndProc' - end - - class CakePhpCore < Library - php_keywords "CAKE_CORE_INCLUDE_PATH" - end - - class RailsCore < Library - ruby_keywords "RAILS_ROOT" - end - - class BSDLib < Library - c_keywords 'FTS_PHYSICAL' - end - - class SpringLibrary < Library - files 'spring\.jar' - end - - class JQueryLibrary < Library - files 'jquery-\d.\d.\d.min.js' - end - - class AppleEvents < Library - c_keywords 'AppleEvent', 'AEBuildAppleEvent' - end - - # Mac preference settings - class Plist < Library - files '\.plist' - end - - class XWindowsLib < Library - c_headers 'Xlib.h', 'X11\/xpm.h' - end - - class KDEHeaders < Library - c_headers 'KDEInit.h', 'kdeversion.h' - end - end -end From 506ebc5cfe4783bcd911a56999e789de4161b31c Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Fri, 7 Nov 2008 12:21:33 -0800 Subject: [PATCH 035/387] [NEW] Added a new file_rule : java_imports [NEW] Added a new platform: EclipsePlatform --- lib/gestalt/platform.rb | 1 + lib/gestalt/rules/logical_rule.rb | 4 ++++ rules/platforms.rb | 6 +++++- test/unit/gestalt/platform_test.rb | 4 ++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/gestalt/platform.rb b/lib/gestalt/platform.rb index 1b15bb0..28fa62a 100644 --- a/lib/gestalt/platform.rb +++ b/lib/gestalt/platform.rb @@ -9,6 +9,7 @@ require 'lib/gestalt/rules/keyword_rule' require 'lib/gestalt/rules/c_keyword_rule' require 'lib/gestalt/rules/platform_rule' +require 'lib/gestalt/rules/java_import_rule' module Ohcount module Gestalt diff --git a/lib/gestalt/rules/logical_rule.rb b/lib/gestalt/rules/logical_rule.rb index f363755..af1ba8f 100644 --- a/lib/gestalt/rules/logical_rule.rb +++ b/lib/gestalt/rules/logical_rule.rb @@ -48,6 +48,10 @@ def c_keywords(*args) new_rule CKeywordRule, *args end + def java_import(*args) + new_rule JavaImportRule, *args + end + def method_missing(m,*args) if /(.*)_keywords$/ =~ m.to_s language = $1 diff --git a/rules/platforms.rb b/rules/platforms.rb index faab34d..d82d8ad 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -45,7 +45,7 @@ class SpringFramework < Platform end class XWindows < Platform - c_headers 'Xlib.h', 'X11\/xpm.h' + c_headers 'Xlib.h', 'X11\/xpm.h', 'X11/Xlib.h' end class Mac < Platform @@ -66,3 +66,7 @@ class CakePHP < Platform class KDE < Platform c_headers 'KDEInit.h', 'kdeversion.h' end + +class EclipsePlatform < Platform + java_import 'org.eclipse.' +end diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index 326880b..2b44a5b 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -5,6 +5,10 @@ class PlatformTest < Test::Unit::TestCase + def test_eclipse_platform + assert_platform('eclipse_platform', Java, EclipsePlatform) + end + def test_cakephp assert_platform('cakephp', CakePHP) end From 042be486589d90b7b3b6e1e9c12393216deac4b7 Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Fri, 7 Nov 2008 13:42:47 -0800 Subject: [PATCH 036/387] [FIX] missed adding files to prev checkin --- lib/gestalt/rules/java_import_rule.rb | 26 ++++++++++++++++++++++++++ test/gestalt_files/eclipse_platform/main.java | 14 ++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 lib/gestalt/rules/java_import_rule.rb create mode 100644 test/gestalt_files/eclipse_platform/main.java diff --git a/lib/gestalt/rules/java_import_rule.rb b/lib/gestalt/rules/java_import_rule.rb new file mode 100644 index 0000000..fc2ac0c --- /dev/null +++ b/lib/gestalt/rules/java_import_rule.rb @@ -0,0 +1,26 @@ +module Ohcount + module Gestalt + # Triggers if a c or cpp header is present + class JavaImportRule < FileRule + attr_reader :imports + + def initialize(*args) + options = args.pop if args.last.is_a?(Hash) + @imports = args + super(options) + end + + def trigger_file?(source_file) + return false unless source_file.polyglot == 'java' + regexp.match(source_file.language_breakdowns('java').code) + end + + def regexp + @regexp ||= begin + imports_term = "(" + imports.join("|") + ")" + Regexp.new("import\s+#{ imports_term }") + end + end + end + end +end diff --git a/test/gestalt_files/eclipse_platform/main.java b/test/gestalt_files/eclipse_platform/main.java new file mode 100644 index 0000000..cdd268f --- /dev/null +++ b/test/gestalt_files/eclipse_platform/main.java @@ -0,0 +1,14 @@ +/******************************************************************************* + * Gibberish Code Copyrighted Just For The Hell Of It. + ******************************************************************************/ + package net.ohloh.www; + + import java.text.SimpleDateFormat; + import java.util.Date; + import java.util.HashMap; + import java.util.Map; + import org.eclipse.core.lotsa_stuff; + + public class AptPlugin extends Plugin { + public static final String PLUGIN_ID = "org.eclipse.jdt.apt.core"; //$NON-NLS-1$ + } From d2a8e5ec3172cc4b4a16a55336f8bdd72d978f13 Mon Sep 17 00:00:00 2001 From: "andy@ohloh.net" Date: Fri, 7 Nov 2008 13:52:50 -0800 Subject: [PATCH 037/387] [NEW] MSDos platform --- rules/platforms.rb | 4 ++++ test/gestalt_files/msdos/bar.c | 1 + test/gestalt_files/msdos/foo.c | 1 + test/unit/gestalt/platform_test.rb | 4 ++++ 4 files changed, 10 insertions(+) create mode 100644 test/gestalt_files/msdos/bar.c create mode 100644 test/gestalt_files/msdos/foo.c diff --git a/rules/platforms.rb b/rules/platforms.rb index faab34d..d437df8 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -66,3 +66,7 @@ class CakePHP < Platform class KDE < Platform c_headers 'KDEInit.h', 'kdeversion.h' end + +class MSDos < Platform + c_keywords '__MSDOS__', 'MSDOS', :min => 2 +end diff --git a/test/gestalt_files/msdos/bar.c b/test/gestalt_files/msdos/bar.c new file mode 100644 index 0000000..03949f9 --- /dev/null +++ b/test/gestalt_files/msdos/bar.c @@ -0,0 +1 @@ +#include "MSDOS" diff --git a/test/gestalt_files/msdos/foo.c b/test/gestalt_files/msdos/foo.c new file mode 100644 index 0000000..311ff65 --- /dev/null +++ b/test/gestalt_files/msdos/foo.c @@ -0,0 +1 @@ +#include "__MSDOS__" diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index 326880b..4cb03e7 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -57,6 +57,10 @@ def test_kde assert_platform('kde', KDE) end + def test_msdos + assert_platform('msdos', MSDos) + end + protected def assert_platform(path, *platforms) From 94737012cefbd79022e23bcb86cbd664650c3269 Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Fri, 7 Nov 2008 15:16:46 -0800 Subject: [PATCH 038/387] [NEW] Added WxWidgets Platform --- rules/platforms.rb | 20 ++++++++++++++++++-- test/gestalt_files/wx_widgets/main.h | 3 +++ test/unit/gestalt/platform_test.rb | 4 ++++ 3 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 test/gestalt_files/wx_widgets/main.h diff --git a/rules/platforms.rb b/rules/platforms.rb index 64e33b6..80a8299 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -2,8 +2,8 @@ include Ohcount::Gestalt class POSIX < Platform - # gnu_lib - c_headers 'pthread.h', 'xstrtol.h', 'xreadlink.h', 'fatal-signal.h', 'diacrit.h' + # gnu_lib && generic + c_headers 'pthread.h', 'xstrtol.h', 'xreadlink.h', 'fatal-signal.h', 'diacrit.h', 'syslog.h', 'sys/stat.h' # autoconf means m4 (unix macro processor) language :autoconf @@ -60,6 +60,10 @@ class PHP < Platform language :php, :min_percent => 15 end +class WxWidgets < Platform + c_headers 'wx/window.h' +end + class CakePHP < Platform _and( platform(PHP), @@ -71,6 +75,18 @@ class KDE < Platform c_headers 'KDEInit.h', 'kdeversion.h' end +class SQL < Platform + language :sql +end + +class MySQL < Platform + php_keywords('mysql_connect') +end + +class PostgreSQL < Platform + php_keywords('pg_connect') +end + class EclipsePlatform < Platform java_import 'org.eclipse.' end diff --git a/test/gestalt_files/wx_widgets/main.h b/test/gestalt_files/wx_widgets/main.h new file mode 100644 index 0000000..7b1cc39 --- /dev/null +++ b/test/gestalt_files/wx_widgets/main.h @@ -0,0 +1,3 @@ +/* some random includes (and one that's not so random) */ +#include +#include "wx/window.h" diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index 2fbc60d..185c814 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -5,6 +5,10 @@ class PlatformTest < Test::Unit::TestCase + def test_wx_widgets + assert_platform('wx_widgets', WxWidgets) + end + def test_eclipse_platform assert_platform('eclipse_platform', Java, EclipsePlatform) end From eb70d2e0d9a1d39258f03b0b6a7e74e9ec20570a Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Tue, 11 Nov 2008 12:35:06 -0800 Subject: [PATCH 039/387] [FIX] Ohcount now supports filename args again --- bin/ohcount | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/bin/ohcount b/bin/ohcount index 5c78852..9781ee4 100755 --- a/bin/ohcount +++ b/bin/ohcount @@ -15,11 +15,23 @@ class OhcountCommandLine def initialize(args=[]) args = args.clone # Because shift is destructive set_option(args.shift) while args.first =~ /^-/ - self.paths = args + assign_paths_and_files(args) + end + + def assign_paths_and_files(args) + @files = [] + @paths = [] + args.each do |file_or_path| + if File.directory?(file_or_path) + paths << file_or_path + else + files << file_or_path + end + end end def source_file_list - @source_file_list ||= Ohcount::SourceFileList.new(:paths => paths) + @source_file_list ||= Ohcount::SourceFileList.new(:paths => @paths, :files => @files) end def paths From a8fe3df775dd25fc93e5c98c11f45174960559f2 Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Tue, 11 Nov 2008 12:39:41 -0800 Subject: [PATCH 040/387] [FIX] similar to last one --- bin/ohcount | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/bin/ohcount b/bin/ohcount index 9781ee4..6ba50c4 100755 --- a/bin/ohcount +++ b/bin/ohcount @@ -22,28 +22,19 @@ class OhcountCommandLine @files = [] @paths = [] args.each do |file_or_path| - if File.directory?(file_or_path) - paths << file_or_path + if File.directory?(file_or_path) + @paths << file_or_path else - files << file_or_path + @files << file_or_path end end + @paths = ['.'] if @files.empty? && @paths.empty? end def source_file_list @source_file_list ||= Ohcount::SourceFileList.new(:paths => @paths, :files => @files) end - def paths - @paths.empty? ? ['.'] : @paths - end - - def paths=(p) - @paths=p - # If we change the search paths, clear the cached filenames - @files = @source_file_list = nil - end - # # TO DEPRECATE BEGIN # From d58d946dcf999643a395631fd1ce03ee0b7aaee8 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 11 Nov 2008 12:41:04 -0800 Subject: [PATCH 041/387] [NEW] XAML parser --- ext/ohcount_native/ragel_parser.c | 2 + ext/ohcount_native/ragel_parsers/xaml.rl | 123 +++++++++++++++++++++++++++++++ lib/ohcount/detector.rb | 1 + lib/ohcount/sloc_info.rb | 1 + test/expected_dir/click_me.xaml | 7 ++ test/src_dir/click_me.xaml | 7 ++ test/unit/parsers/xaml_test.rb | 16 ++++ 7 files changed, 157 insertions(+) create mode 100644 ext/ohcount_native/ragel_parsers/xaml.rl create mode 100644 test/expected_dir/click_me.xaml create mode 100644 test/src_dir/click_me.xaml create mode 100644 test/unit/parsers/xaml_test.rb diff --git a/ext/ohcount_native/ragel_parser.c b/ext/ohcount_native/ragel_parser.c index 744f905..06f3739 100644 --- a/ext/ohcount_native/ragel_parser.c +++ b/ext/ohcount_native/ragel_parser.c @@ -65,6 +65,7 @@ #include "vhdl_parser.h" #include "vim_parser.h" #include "visual_basic_parser.h" +#include "xaml_parser.h" #include "xml_parser.h" #include "xslt_parser.h" #include "xmlschema_parser.h" @@ -147,6 +148,7 @@ struct language languages[] = { { "vhdl", parse_vhdl }, { "vim", parse_vim }, { "visualbasic", parse_visual_basic }, + { "xaml", parse_xaml }, { "xml", parse_xml }, { "xslt", parse_xslt }, { "xmlschema", parse_xmlschema }, diff --git a/ext/ohcount_native/ragel_parsers/xaml.rl b/ext/ohcount_native/ragel_parsers/xaml.rl new file mode 100644 index 0000000..0effbf1 --- /dev/null +++ b/ext/ohcount_native/ragel_parsers/xaml.rl @@ -0,0 +1,123 @@ +/************************* Required for every parser *************************/ +#ifndef RAGEL_XAML_PARSER +#define RAGEL_XAML_PARSER + +#include "ragel_parser_macros.h" + +// the name of the language +const char *XAML_LANG = "xaml"; + +// the languages entities +const char *xaml_entities[] = { + "space", "comment", "doctype", + "tag", "entity", "any" +}; + +// constants associated with the entities +enum { + XAML_SPACE = 0, XAML_COMMENT, XAML_DOCTYPE, + XAML_TAG, XAML_ENTITY, XAML_ANY +}; + +/*****************************************************************************/ + +%%{ + machine xaml; + write data; + include common "common.rl"; + + # Line counting machine + + action xaml_ccallback { + switch(entity) { + case XAML_SPACE: + ls + break; + case XAML_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(XAML_LANG) + break; + case NEWLINE: + std_newline(XAML_LANG) + break; + case CHECK_BLANK_ENTRY: + check_blank_entry(XAML_LANG) + } + } + + xaml_comment = + ''; + + xaml_sq_str = '\'' [^\r\n\f']* '\'' @code; + xaml_dq_str = '"' [^\r\n\f"]* '"' @code; + xaml_cdata_str = + '> ']]>'; + xaml_string = xaml_sq_str | xaml_dq_str | xaml_cdata_str; + + xaml_line := |* + spaces ${ entity = XAML_SPACE; } => xaml_ccallback; + xaml_comment; + xaml_string; + newline ${ entity = NEWLINE; } => xaml_ccallback; + ^space ${ entity = XAML_ANY; } => xaml_ccallback; + *|; + + # Entity machine + + action xaml_ecallback { + callback(XAML_LANG, xaml_entities[entity], cint(ts), cint(te)); + } + + xaml_comment_entity = ''; + + xaml_entity := |* + space+ ${ entity = XAML_SPACE; } => xaml_ecallback; + xaml_comment_entity ${ entity = XAML_COMMENT; } => xaml_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with XAML markup. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_xaml(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int start, int end) + ) { + init + + %% write init; + cs = (count) ? xaml_en_xaml_line : xaml_en_xaml_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(XAML_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index ddf828d..9fadad4 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -216,6 +216,7 @@ def self.binary_filename?(filename) '.vhd' => "vhdl", '.vhdl' => "vhdl", '.vim' => "vim", + '.xaml' => "xaml", '.xml' => "xml", '.xs' => "c", '.xsd' => "xmlschema", diff --git a/lib/ohcount/sloc_info.rb b/lib/ohcount/sloc_info.rb index 82040a9..80f4ab7 100644 --- a/lib/ohcount/sloc_info.rb +++ b/lib/ohcount/sloc_info.rb @@ -98,6 +98,7 @@ def empty? 'vhdl' => {:nice_name => 'VHDL' , :category => 0}, 'visualbasic' => {:nice_name => 'Visual Basic' , :category => 0}, 'vim' => {:nice_name => 'Vim Script' , :category => 0}, + 'xaml' => {:nice_name => 'XAML' , :category => 1}, 'xml' => {:nice_name => 'XML' , :category => 1}, 'xmlschema' => {:nice_name => 'XML Schema' , :category => 1}, 'xslt' => {:nice_name => 'XSL Transformation',:category => 0}, diff --git a/test/expected_dir/click_me.xaml b/test/expected_dir/click_me.xaml new file mode 100644 index 0000000..1add23f --- /dev/null +++ b/test/expected_dir/click_me.xaml @@ -0,0 +1,7 @@ +xaml comment +xaml code +xaml code +xaml code diff --git a/test/src_dir/click_me.xaml b/test/src_dir/click_me.xaml new file mode 100644 index 0000000..7241415 --- /dev/null +++ b/test/src_dir/click_me.xaml @@ -0,0 +1,7 @@ + + + + diff --git a/test/unit/parsers/xaml_test.rb b/test/unit/parsers/xaml_test.rb new file mode 100644 index 0000000..c3feb46 --- /dev/null +++ b/test/unit/parsers/xaml_test.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::XamlTest < Ohcount::Test + def test_comment + lb = [Ohcount::LanguageBreakdown.new("xaml", "", "", 0)] + assert_equal lb, Ohcount::parse(" ", "xaml") + end + + def test_comprehensive + verify_parse("click_me.xaml") + end + + def test_comment_entities + assert_equal('', entities_array(" ", 'xaml', :comment).first) + end +end From a2bd5c3da3b160c55ee53ac2398229550fd61d96 Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Tue, 11 Nov 2008 12:58:06 -0800 Subject: [PATCH 042/387] [NEW] Tools support --- bin/ohcount | 10 +++++++--- lib/gestalt/platform.rb | 1 - lib/gestalt/tool.rb | 31 +++++++++++++++++++++++++++++++ lib/ohcount.rb | 2 ++ lib/ohcount/gestalt_facts.rb | 13 +++++++++++-- rules/tools.rb | 6 +----- test/gestalt_files/vs_1/my_proj.vpj | 1 + test/unit/gestalt/tool_test.rb | 24 ++++++++++++++++++++++++ 8 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 lib/gestalt/tool.rb create mode 100644 test/gestalt_files/vs_1/my_proj.vpj create mode 100644 test/unit/gestalt/tool_test.rb diff --git a/bin/ohcount b/bin/ohcount index 6ba50c4..9a51dea 100755 --- a/bin/ohcount +++ b/bin/ohcount @@ -99,16 +99,20 @@ class OhcountCommandLine puts "\n" end - def write_platforms + def write_gestalt platforms = source_file_list.gestalt_facts.platforms platforms = platforms.any? ? platforms.collect { |p| p.to_s }.join(", ") : 'None' puts "Platforms detected: #{ platforms }" + + tools = source_file_list.gestalt_facts.tools + tools = tools.any? ? tools.collect { |p| p.to_s }.join(", ") : 'None' + puts "Tools detected: #{ tools }" end # Gestalt def gestalt analyze_with_progress(:gestalt) - write_platforms + write_gestalt end def raw_entities @@ -243,7 +247,7 @@ HELP puts - write_platforms + write_gestalt end def write_summary_row(name, file_count, code, comment, blank) diff --git a/lib/gestalt/platform.rb b/lib/gestalt/platform.rb index 28fa62a..940e0fe 100644 --- a/lib/gestalt/platform.rb +++ b/lib/gestalt/platform.rb @@ -29,7 +29,6 @@ def self.method_missing(method, *args) def self.triggered?(g) top_level_or.triggered?(g) - end # tricky code to let us track the descendants... diff --git a/lib/gestalt/tool.rb b/lib/gestalt/tool.rb new file mode 100644 index 0000000..ec901ca --- /dev/null +++ b/lib/gestalt/tool.rb @@ -0,0 +1,31 @@ +module Ohcount + module Gestalt + class Tool + + # tool rules are assumed to be, at the top level, + # OR-ed. In other words, any one rule will trigger that platform. + # That's why we keep a top-level OrRule around. + def self.top_level_or + @top_level_or ||= OrRule.new + end + + # we delegate to the top_level_or trigger + def self.method_missing(method, *args) + top_level_or.send(method, *args) + end + + def self.triggered?(g) + top_level_or.triggered?(g) + end + + # tricky code to let us track the descendants... + class << self + def children() @children ||= [] end + def inherited(other) children << other and super end + def descendants() children.inject([]){|d,c| d.push(c, *c.descendants)} end + end + + end + end +end + diff --git a/lib/ohcount.rb b/lib/ohcount.rb index ecac09b..1535dfb 100644 --- a/lib/ohcount.rb +++ b/lib/ohcount.rb @@ -24,7 +24,9 @@ module Ohcount require "lib/licenses/license_sniffer" require "lib/gestalt/platform" +require "lib/gestalt/tool" # require the dynamic rules require 'rules/platforms' +require 'rules/tools' diff --git a/lib/ohcount/gestalt_facts.rb b/lib/ohcount/gestalt_facts.rb index 5ec8a67..10bfa8f 100644 --- a/lib/ohcount/gestalt_facts.rb +++ b/lib/ohcount/gestalt_facts.rb @@ -2,10 +2,11 @@ module Ohcount # Represents language statistics for a collection of files class GestaltFacts - attr_accessor :platforms, :file_rules, :language_counts + attr_accessor :platforms, :tools, :file_rules, :language_counts def initialize @platforms = [] + @tools = [] @file_rules = {} @language_counts = {} end @@ -30,7 +31,11 @@ def post_process uninfered_platforms.each do |p| platforms << p if p.triggered?(self) end - break if prev_platforms == self.platforms + prev_tools = self.tools.clone + uninfered_tools.each do |t| + tools << t if t.triggered?(self) + end + break if prev_platforms == self.platforms && prev_tools == self.tools end end @@ -38,6 +43,10 @@ def uninfered_platforms #:nodoc: Platform.descendants - @platforms end + def uninfered_tools #:nodoc: + Tool.descendants - @tools + end + def includes_language?(language, min_percent = 0) return false unless language_counts[language] language_percents[language] >= min_percent diff --git a/rules/tools.rb b/rules/tools.rb index 2ad8d31..9e2d2b8 100644 --- a/rules/tools.rb +++ b/rules/tools.rb @@ -2,9 +2,5 @@ include Ohcount::Gestalt class VisualStudio < Tool - trigger_libs :visual_studio_files -end - -class Eclipse < Tool - files 'Makefile.conf' + filenames '\.vpj' end diff --git a/test/gestalt_files/vs_1/my_proj.vpj b/test/gestalt_files/vs_1/my_proj.vpj new file mode 100644 index 0000000..bd3a44c --- /dev/null +++ b/test/gestalt_files/vs_1/my_proj.vpj @@ -0,0 +1 @@ +# a dummy vpj file diff --git a/test/unit/gestalt/tool_test.rb b/test/unit/gestalt/tool_test.rb new file mode 100644 index 0000000..72f0d27 --- /dev/null +++ b/test/unit/gestalt/tool_test.rb @@ -0,0 +1,24 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +include Ohcount +include Ohcount::Gestalt + +class ToolTest < Test::Unit::TestCase + + def test_vs_1 + assert_tool('vs_1', VisualStudio) + end + + protected + def assert_tool(path, *tools) + sfl = SourceFileList.new(:path => test_dir(path)) + sfl.analyze(:gestalt) + assert_equal tools, sfl.gestalt_facts.tools + end + + def test_dir(d) + File.expand_path(File.dirname(__FILE__) + "/../../gestalt_files/#{ d }") + end + +end + From d6f5bc04d4d488861cd9515b2212dec8b2fe0652 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 11 Nov 2008 14:07:45 -0800 Subject: [PATCH 043/387] [CHANGE] Parse hidden files, but do not recurse into hidden directories. [NEW] VisualStudio, Eclipse, ASP.NET, WPF detection --- bin/ohcount | 28 ---------------------------- lib/ohcount/source_file_list.rb | 20 +++++++++++++++----- rules/platforms.rb | 12 ++++++++++++ rules/tools.rb | 6 +++++- test/gestalt_files/asp_net/test.aspx | 0 test/gestalt_files/eclipse/.project | 17 +++++++++++++++++ test/gestalt_files/vs_1/my_proj.vpj | 1 - test/gestalt_files/vs_1/sample.sln | 30 ++++++++++++++++++++++++++++++ test/gestalt_files/wpf/wpf.xaml | 6 ++++++ test/unit/gestalt/platform_test.rb | 8 ++++++++ test/unit/gestalt/tool_test.rb | 4 ++++ 11 files changed, 97 insertions(+), 35 deletions(-) create mode 100644 test/gestalt_files/asp_net/test.aspx create mode 100755 test/gestalt_files/eclipse/.project delete mode 100644 test/gestalt_files/vs_1/my_proj.vpj create mode 100644 test/gestalt_files/vs_1/sample.sln create mode 100644 test/gestalt_files/wpf/wpf.xaml diff --git a/bin/ohcount b/bin/ohcount index 9a51dea..6b6e5c4 100755 --- a/bin/ohcount +++ b/bin/ohcount @@ -35,34 +35,6 @@ class OhcountCommandLine @source_file_list ||= Ohcount::SourceFileList.new(:paths => @paths, :files => @files) end - # - # TO DEPRECATE BEGIN - # - def files - return @files if @files - - @files = [] - (self.paths.any? ? self.paths : ['.']).each { | p | self.find_files_recursively @files, p } - - exit 1 unless @files.any? - @files - end - - def find_files_recursively array, path - s = File.lstat(path) - if s.directory? - Dir.foreach(path) do | d | - File.basename(d) =~ /^\./ and next - find_files_recursively array, File.join(path, d) - end - elsif s.file? - array << path - end - end - # - # TO DEPRECATE END - # - def annotate source_file_list.each_source_file do |s| s.parse do |language, semantic, line| diff --git a/lib/ohcount/source_file_list.rb b/lib/ohcount/source_file_list.rb index 6a5faf3..78c545b 100644 --- a/lib/ohcount/source_file_list.rb +++ b/lib/ohcount/source_file_list.rb @@ -24,14 +24,24 @@ def initialize(options = {}) when :files then v else raise(ArgumentError, "Unrecognized option: #{ k }") end - end + end.flatten.uniq super(files) end - def files_from_paths(paths) - paths.inject([]) do |files, path| - glob_path = File.join(path,"**","*") - files + Dir.glob(glob_path) + def files_from_paths(paths=[]) + paths.collect { |p| files_from_path(p) }.flatten + end + + def files_from_path(path) + s = File.lstat(path) + if s.directory? + if File.basename(path) =~ /^\./ # Don't recurse into hidden dirs + [] + else + Dir[File.join(path,"{.,?}*")].collect { |d| files_from_path(d) } # Include hidden files + end + elsif s.file? + path end end diff --git a/rules/platforms.rb b/rules/platforms.rb index 060ada6..083d522 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -14,6 +14,18 @@ class Win32 < Platform c_keywords 'WM_PAINT', 'ReleaseDC', 'WndProc', :min => 2 end +class WPF < Platform + filenames '\.xaml$' +end + +class Dot_NET < Platform + language :csharp, :min_percent => 10 +end + +class ASP_NET < Platform + filenames('\.(aspx|ascx|ashx|asax|axd)$') +end + class Ruby < Platform language :ruby, :min_percent => 15 end diff --git a/rules/tools.rb b/rules/tools.rb index 9e2d2b8..d0eea8a 100644 --- a/rules/tools.rb +++ b/rules/tools.rb @@ -2,5 +2,9 @@ include Ohcount::Gestalt class VisualStudio < Tool - filenames '\.vpj' + filenames '\.(sln|vcproj|vsproj|csproj|vbproj|vbp)$' +end + +class Eclipse < Tool + filenames '\.(project|classpath)$' end diff --git a/test/gestalt_files/asp_net/test.aspx b/test/gestalt_files/asp_net/test.aspx new file mode 100644 index 0000000..e69de29 diff --git a/test/gestalt_files/eclipse/.project b/test/gestalt_files/eclipse/.project new file mode 100755 index 0000000..64e993c --- /dev/null +++ b/test/gestalt_files/eclipse/.project @@ -0,0 +1,17 @@ + + + sample + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/test/gestalt_files/vs_1/my_proj.vpj b/test/gestalt_files/vs_1/my_proj.vpj deleted file mode 100644 index bd3a44c..0000000 --- a/test/gestalt_files/vs_1/my_proj.vpj +++ /dev/null @@ -1 +0,0 @@ -# a dummy vpj file diff --git a/test/gestalt_files/vs_1/sample.sln b/test/gestalt_files/vs_1/sample.sln new file mode 100644 index 0000000..e8ed0ed --- /dev/null +++ b/test/gestalt_files/vs_1/sample.sln @@ -0,0 +1,30 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sample", "Source\sample.csproj", "{7385FCA3-06F5-4896-88F5-EB31BF3CD292}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{42B2B588-DC14-457F-A13B-62C9D8BC8321}" + ProjectSection(SolutionItems) = preProject + Source\License.txt = Source\License.txt + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sample.csproj", "{4F22BC49-E03E-4340-B17F-BBD5AFC34DCF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7385FCA3-06F5-4896-88F5-EB31BF3CD292}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7385FCA3-06F5-4896-88F5-EB31BF3CD292}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7385FCA3-06F5-4896-88F5-EB31BF3CD292}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7385FCA3-06F5-4896-88F5-EB31BF3CD292}.Release|Any CPU.Build.0 = Release|Any CPU + {4F22BC49-E03E-4340-B17F-BBD5AFC34DCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4F22BC49-E03E-4340-B17F-BBD5AFC34DCF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4F22BC49-E03E-4340-B17F-BBD5AFC34DCF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4F22BC49-E03E-4340-B17F-BBD5AFC34DCF}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/test/gestalt_files/wpf/wpf.xaml b/test/gestalt_files/wpf/wpf.xaml new file mode 100644 index 0000000..4275c95 --- /dev/null +++ b/test/gestalt_files/wpf/wpf.xaml @@ -0,0 +1,6 @@ + + + diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index ccfa871..f258096 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -21,6 +21,14 @@ def test_win32_enough assert_platform('win32_enough', Win32) end + def test_wpf + assert_platform('wpf', WPF) + end + + def test_asp_net + assert_platform('asp_net', ASP_NET) + end + def test_ruby_just_enough assert_platform('ruby_just_enough', Ruby) end diff --git a/test/unit/gestalt/tool_test.rb b/test/unit/gestalt/tool_test.rb index 72f0d27..be5edaa 100644 --- a/test/unit/gestalt/tool_test.rb +++ b/test/unit/gestalt/tool_test.rb @@ -9,6 +9,10 @@ def test_vs_1 assert_tool('vs_1', VisualStudio) end + def test_eclipse + assert_tool('eclipse', Eclipse) + end + protected def assert_tool(path, *tools) sfl = SourceFileList.new(:path => test_dir(path)) From 9e36ce8ab10017fd6356dd4bd7bdc5aa99b68867 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 11 Nov 2008 14:59:20 -0800 Subject: [PATCH 044/387] [NEW] NetBeans IDE (Sun Java Studio) detection --- rules/tools.rb | 5 +++++ test/gestalt_files/netbeans/nbplatform/project.xml | 9 +++++++++ test/unit/gestalt/tool_test.rb | 4 ++++ 3 files changed, 18 insertions(+) create mode 100644 test/gestalt_files/netbeans/nbplatform/project.xml diff --git a/rules/tools.rb b/rules/tools.rb index d0eea8a..645a048 100644 --- a/rules/tools.rb +++ b/rules/tools.rb @@ -8,3 +8,8 @@ class VisualStudio < Tool class Eclipse < Tool filenames '\.(project|classpath)$' end + +class NetBeans < Tool + filenames '\bnbplatform\b' + filenames '\.nbm$' +end diff --git a/test/gestalt_files/netbeans/nbplatform/project.xml b/test/gestalt_files/netbeans/nbplatform/project.xml new file mode 100644 index 0000000..f5ec34c --- /dev/null +++ b/test/gestalt_files/netbeans/nbplatform/project.xml @@ -0,0 +1,9 @@ + + + org.netbeans.modules.apisupport.project.suite + + + sample + + + diff --git a/test/unit/gestalt/tool_test.rb b/test/unit/gestalt/tool_test.rb index be5edaa..2abc941 100644 --- a/test/unit/gestalt/tool_test.rb +++ b/test/unit/gestalt/tool_test.rb @@ -13,6 +13,10 @@ def test_eclipse assert_tool('eclipse', Eclipse) end + def test_netbeans + assert_tool('netbeans', NetBeans) + end + protected def assert_tool(path, *tools) sfl = SourceFileList.new(:path => test_dir(path)) From 6af58bf9ace18fe38db42edbf8d90f037fa0a32e Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 11 Nov 2008 16:47:00 -0800 Subject: [PATCH 045/387] [NEW] Parse *.apsx, *.ascx files. Resulted in new polyglots cs_aspx, vb_aspx. --- ext/ohcount_native/ragel_parser.c | 4 + ext/ohcount_native/ragel_parsers/cs_aspx.rl | 238 ++++++++++++++++++++++++++++ ext/ohcount_native/ragel_parsers/vb_aspx.rl | 235 +++++++++++++++++++++++++++ lib/ohcount/detector.rb | 13 +- test/expected_dir/cs.aspx | 29 ++++ test/expected_dir/vb.aspx | 26 +++ test/src_dir/cs.aspx | 29 ++++ test/src_dir/vb.aspx | 26 +++ test/unit/parsers/cs_aspx_test.rb | 15 ++ test/unit/parsers/vb_aspx_test.rb | 15 ++ 10 files changed, 629 insertions(+), 1 deletion(-) create mode 100644 ext/ohcount_native/ragel_parsers/cs_aspx.rl create mode 100644 ext/ohcount_native/ragel_parsers/vb_aspx.rl create mode 100644 test/expected_dir/cs.aspx create mode 100644 test/expected_dir/vb.aspx create mode 100644 test/src_dir/cs.aspx create mode 100644 test/src_dir/vb.aspx create mode 100644 test/unit/parsers/cs_aspx_test.rb create mode 100644 test/unit/parsers/vb_aspx_test.rb diff --git a/ext/ohcount_native/ragel_parser.c b/ext/ohcount_native/ragel_parser.c index 06f3739..9460667 100644 --- a/ext/ohcount_native/ragel_parser.c +++ b/ext/ohcount_native/ragel_parser.c @@ -16,6 +16,7 @@ #include "classic_basic_parser.h" #include "clearsilver_parser.h" #include "clearsilverhtml_parser.h" +#include "cs_aspx_parser.h" #include "css_parser.h" #include "d_parser.h" #include "dcl_parser.h" @@ -62,6 +63,7 @@ #include "sql_parser.h" #include "tcl_parser.h" #include "tex_parser.h" +#include "vb_aspx_parser.h" #include "vhdl_parser.h" #include "vim_parser.h" #include "visual_basic_parser.h" @@ -95,6 +97,7 @@ struct language languages[] = { { "clearsilver", parse_clearsilver }, { "clearsilver_template", parse_cshtml }, { "cpp", parse_cpp }, + { "cs_aspx", parse_cs_aspx }, { "csharp", parse_csharp }, { "css", parse_css }, { "dcl", parse_dcl }, @@ -145,6 +148,7 @@ struct language languages[] = { { "tcl", parse_tcl }, { "tex", parse_tex }, { "vala", parse_vala }, + { "vb_aspx", parse_vb_aspx }, { "vhdl", parse_vhdl }, { "vim", parse_vim }, { "visualbasic", parse_visual_basic }, diff --git a/ext/ohcount_native/ragel_parsers/cs_aspx.rl b/ext/ohcount_native/ragel_parsers/cs_aspx.rl new file mode 100644 index 0000000..0cfb805 --- /dev/null +++ b/ext/ohcount_native/ragel_parsers/cs_aspx.rl @@ -0,0 +1,238 @@ +/************************* Required for every parser *************************/ +#ifndef RAGEL_CS_ASPX_PARSER +#define RAGEL_CS_ASPX_PARSER + +#include "ragel_parser_macros.h" + +// the name of the language +const char *CS_ASPX_LANG = "html"; + +// the languages entities +const char *cs_aspx_entities[] = { + "space", "comment", "doctype", + "tag", "entity", "any" +}; + +// constants associated with the entities +enum { + CS_ASPX_SPACE = 0, CS_ASPX_COMMENT, CS_ASPX_DOCTYPE, + CS_ASPX_TAG, CS_ASPX_ENTITY, CS_ASPX_ANY +}; + +/*****************************************************************************/ + +#include "css_parser.h" +#include "javascript_parser.h" +#include "c_parser.h" + +%%{ + machine cs_aspx; + write data; + include common "common.rl"; + #EMBED(css) + #EMBED(javascript) + #EMBED(c) + + # Line counting machine + + action cs_aspx_ccallback { + switch(entity) { + case CS_ASPX_SPACE: + ls + break; + case CS_ASPX_ANY: + code + break; + case INTERNAL_NL: + emb_internal_newline(CS_ASPX_LANG) + break; + case NEWLINE: + emb_newline(CS_ASPX_LANG) + break; + case CHECK_BLANK_ENTRY: + check_blank_entry(CS_ASPX_LANG) + } + } + + cs_aspx_comment := ( + newline %{ entity = INTERNAL_NL; } %cs_aspx_ccallback + | + ws + | + ^(space | [\-<]) @comment + | + '<' '%' @{ saw(C_LANG); fcall cs_aspx_cs_line; } + | + '<' !'%' + )* :>> '-->' @comment @{ fgoto cs_aspx_line; }; + + cs_aspx_sq_str := ( + newline %{ entity = INTERNAL_NL; } %cs_aspx_ccallback + | + ws + | + [^\r\n\f\t '\\<] @code + | + '\\' nonnewline @code + | + '<' '%' @{ saw(C_LANG); fcall cs_aspx_cs_line; } + | + '<' !'%' + )* '\'' @{ fgoto cs_aspx_line; }; + cs_aspx_dq_str := ( + newline %{ entity = INTERNAL_NL; } %cs_aspx_ccallback + | + ws + | + [^\r\n\f\t "\\<] @code + | + '\\' nonnewline @code + | + '<' '%' @{ saw(C_LANG); fcall cs_aspx_cs_line; } + | + '<' !'%' + )* '"' @{ fgoto cs_aspx_line; }; + + ws_or_inl = (ws | newline @{ entity = INTERNAL_NL; } %cs_aspx_ccallback); + + cs_aspx_css_entry = '<' /style/i [^>]+ :>> 'text/css' [^>]+ '>' @code; + cs_aspx_css_outry = '' @check_blank_outry @code; + cs_aspx_css_line := |* + cs_aspx_css_outry @{ p = ts; fret; }; + # unmodified CSS patterns + spaces ${ entity = CSS_SPACE; } => css_ccallback; + css_comment; + css_string; + newline ${ entity = NEWLINE; } => css_ccallback; + ^space ${ entity = CSS_ANY; } => css_ccallback; + *|; + + cs_aspx_js_entry = '<' /script/i [^>]+ :>> 'text/javascript' [^>]+ '>' @code; + cs_aspx_js_outry = '' @check_blank_outry @code; + cs_aspx_js_line := |* + cs_aspx_js_outry @{ p = ts; fret; }; + # unmodified Javascript patterns + spaces ${ entity = JS_SPACE; } => js_ccallback; + js_comment; + js_string; + newline ${ entity = NEWLINE; } => js_ccallback; + ^space ${ entity = JS_ANY; } => js_ccallback; + *|; + + cs_aspx_cs_entry = ('<%' | '<' /script/i [^>]+ :>> 'server' [^>]+ '>') @code; + cs_aspx_cs_outry = ('%>' | '' @check_blank_outry) @code; + cs_aspx_cs_line := |* + cs_aspx_cs_outry @{ p = ts; fret; }; + # unmodified C patterns + spaces ${ entity = C_SPACE; } => c_ccallback; + c_comment; + c_string; + newline ${ entity = NEWLINE; } => c_ccallback; + ^space ${ entity = C_ANY; } => c_ccallback; + *|; + + cs_aspx_line := |* + cs_aspx_css_entry @{ entity = CHECK_BLANK_ENTRY; } @cs_aspx_ccallback + @{ saw(CSS_LANG); } => { fcall cs_aspx_css_line; }; + cs_aspx_js_entry @{ entity = CHECK_BLANK_ENTRY; } @cs_aspx_ccallback + @{ saw(JS_LANG); } => { fcall cs_aspx_js_line; }; + cs_aspx_cs_entry @{ entity = CHECK_BLANK_ENTRY; } @cs_aspx_ccallback + @{ saw(C_LANG); } => { fcall cs_aspx_cs_line; }; + # standard CS_ASPX patterns + spaces ${ entity = CS_ASPX_SPACE; } => cs_aspx_ccallback; + ''; + + cs_aspx_entity := |* + # TODO: cs_aspx_ecallback for cs_aspx_*_{entry,outry}_entity + cs_aspx_css_entry_entity => { fcall cs_aspx_css_entity; }; + cs_aspx_js_entry_entity => { fcall cs_aspx_js_entity; }; + cs_aspx_cs_entry_entity => { fcall cs_aspx_cs_entity; }; + # standard CS_ASPX patterns + space+ ${ entity = CS_ASPX_SPACE; } => cs_aspx_ecallback; + cs_aspx_comment_entity ${ entity = CS_ASPX_COMMENT; } => cs_aspx_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with CS_ASPX markup. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_cs_aspx(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int start, int end) + ) { + C_LANG = "csharp"; + init + + const char *seen = 0; + + %% write init; + cs = (count) ? cs_aspx_en_cs_aspx_line : cs_aspx_en_cs_aspx_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(CS_ASPX_LANG) } + + C_LANG = "c"; +} + +#endif + +/*****************************************************************************/ + diff --git a/ext/ohcount_native/ragel_parsers/vb_aspx.rl b/ext/ohcount_native/ragel_parsers/vb_aspx.rl new file mode 100644 index 0000000..c7eca7c --- /dev/null +++ b/ext/ohcount_native/ragel_parsers/vb_aspx.rl @@ -0,0 +1,235 @@ +/************************* Required for every parser *************************/ +#ifndef RAGEL_VB_ASPX_PARSER +#define RAGEL_VB_ASPX_PARSER + +#include "ragel_parser_macros.h" + +// the name of the language +const char *VB_ASPX_LANG = "html"; + +// the languages entities +const char *vb_aspx_entities[] = { + "space", "comment", "doctype", + "tag", "entity", "any" +}; + +// constants associated with the entities +enum { + VB_ASPX_SPACE = 0, VB_ASPX_COMMENT, VB_ASPX_DOCTYPE, + VB_ASPX_TAG, VB_ASPX_ENTITY, VB_ASPX_ANY +}; + +/*****************************************************************************/ + +#include "css_parser.h" +#include "javascript_parser.h" +#include "visual_basic_parser.h" + +%%{ + machine vb_aspx; + write data; + include common "common.rl"; + #EMBED(css) + #EMBED(javascript) + #EMBED(visual_basic) + + # Line counting machine + + action vb_aspx_ccallback { + switch(entity) { + case VB_ASPX_SPACE: + ls + break; + case VB_ASPX_ANY: + code + break; + case INTERNAL_NL: + emb_internal_newline(VB_ASPX_LANG) + break; + case NEWLINE: + emb_newline(VB_ASPX_LANG) + break; + case CHECK_BLANK_ENTRY: + check_blank_entry(VB_ASPX_LANG) + } + } + + vb_aspx_comment := ( + newline %{ entity = INTERNAL_NL; } %vb_aspx_ccallback + | + ws + | + ^(space | [\-<]) @comment + | + '<' '%' @{ saw(VB_LANG); fcall vb_aspx_cs_line; } + | + '<' !'%' + )* :>> '-->' @comment @{ fgoto vb_aspx_line; }; + + vb_aspx_sq_str := ( + newline %{ entity = INTERNAL_NL; } %vb_aspx_ccallback + | + ws + | + [^\r\n\f\t '\\<] @code + | + '\\' nonnewline @code + | + '<' '%' @{ saw(VB_LANG); fcall vb_aspx_cs_line; } + | + '<' !'%' + )* '\'' @{ fgoto vb_aspx_line; }; + vb_aspx_dq_str := ( + newline %{ entity = INTERNAL_NL; } %vb_aspx_ccallback + | + ws + | + [^\r\n\f\t "\\<] @code + | + '\\' nonnewline @code + | + '<' '%' @{ saw(VB_LANG); fcall vb_aspx_cs_line; } + | + '<' !'%' + )* '"' @{ fgoto vb_aspx_line; }; + + ws_or_inl = (ws | newline @{ entity = INTERNAL_NL; } %vb_aspx_ccallback); + + vb_aspx_css_entry = '<' /style/i [^>]+ :>> 'text/css' [^>]+ '>' @code; + vb_aspx_css_outry = '' @check_blank_outry @code; + vb_aspx_css_line := |* + vb_aspx_css_outry @{ p = ts; fret; }; + # unmodified CSS patterns + spaces ${ entity = CSS_SPACE; } => css_ccallback; + css_comment; + css_string; + newline ${ entity = NEWLINE; } => css_ccallback; + ^space ${ entity = CSS_ANY; } => css_ccallback; + *|; + + vb_aspx_js_entry = '<' /script/i [^>]+ :>> 'text/javascript' [^>]+ '>' @code; + vb_aspx_js_outry = '' @check_blank_outry @code; + vb_aspx_js_line := |* + vb_aspx_js_outry @{ p = ts; fret; }; + # unmodified Javascript patterns + spaces ${ entity = JS_SPACE; } => js_ccallback; + js_comment; + js_string; + newline ${ entity = NEWLINE; } => js_ccallback; + ^space ${ entity = JS_ANY; } => js_ccallback; + *|; + + vb_aspx_cs_entry = ('<%' | '<' /script/i [^>]+ :>> 'server' [^>]+ '>') @code; + vb_aspx_cs_outry = ('%>' | '' @check_blank_outry) @code; + vb_aspx_cs_line := |* + vb_aspx_cs_outry @{ p = ts; fret; }; + # unmodified VB patterns + spaces ${ entity = VB_SPACE; } => vb_ccallback; + vb_comment; + vb_string; + newline ${ entity = NEWLINE; } => vb_ccallback; + ^space ${ entity = VB_ANY; } => vb_ccallback; + *|; + + vb_aspx_line := |* + vb_aspx_css_entry @{ entity = CHECK_BLANK_ENTRY; } @vb_aspx_ccallback + @{ saw(CSS_LANG); } => { fcall vb_aspx_css_line; }; + vb_aspx_js_entry @{ entity = CHECK_BLANK_ENTRY; } @vb_aspx_ccallback + @{ saw(JS_LANG); } => { fcall vb_aspx_js_line; }; + vb_aspx_cs_entry @{ entity = CHECK_BLANK_ENTRY; } @vb_aspx_ccallback + @{ saw(VB_LANG); } => { fcall vb_aspx_cs_line; }; + # standard VB_ASPX patterns + spaces ${ entity = VB_ASPX_SPACE; } => vb_aspx_ccallback; + ''; + + vb_aspx_entity := |* + # TODO: vb_aspx_ecallback for vb_aspx_*_{entry,outry}_entity + vb_aspx_css_entry_entity => { fcall vb_aspx_css_entity; }; + vb_aspx_js_entry_entity => { fcall vb_aspx_js_entity; }; + vb_aspx_cs_entry_entity => { fcall vb_aspx_cs_entity; }; + # standard VB_ASPX patterns + space+ ${ entity = VB_ASPX_SPACE; } => vb_aspx_ecallback; + vb_aspx_comment_entity ${ entity = VB_ASPX_COMMENT; } => vb_aspx_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with VB_ASPX markup. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_vb_aspx(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int start, int end) + ) { + init + + const char *seen = 0; + + %% write init; + cs = (count) ? vb_aspx_en_vb_aspx_line : vb_aspx_en_vb_aspx_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(VB_ASPX_LANG) } +} + +#endif + +/*****************************************************************************/ + diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index 9fadad4..e7f2a74 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -114,6 +114,8 @@ def self.binary_filename?(filename) '.adb' => "ada", '.ads' => "ada", '.as' => "actionscript", + '.ascx' => :disambiguate_aspx, + '.aspx' => :disambiguate_aspx, '.asm' => "assembler", '.awk' => "awk", '.b' => :disambiguate_non_visual_basic, @@ -506,9 +508,18 @@ def self.disambiguate_fortran(file_context) return 'fortranfree' end + # A *.aspx file may be scripted with either C# or VB.NET. + def self.disambiguate_aspx(file_context) + if file_context.contents.match(/<%@\s*Page[^>]+Language="VB"[^>]+%>/i) + 'vb_aspx' + else + 'cs_aspx' + end + end + # Attempts to tell apart VB, classic BASIC and structured BASIC. # First, checks if it is classic BASIC based on syntax. - # If not checks for .vb, .vbp, .frx and .frm files (associated with VB) + # If not checks for .vb, .bp, .frx and .frm files (associated with VB) # in file context # # If these files are absent, assumes structured BASIC diff --git a/test/expected_dir/cs.aspx b/test/expected_dir/cs.aspx new file mode 100644 index 0000000..7ce4677 --- /dev/null +++ b/test/expected_dir/cs.aspx @@ -0,0 +1,29 @@ +csharp code <%@ Page Language="C#" %> +html code +html code +html code +html code Basic ASP.NET Web Page +html code +html code +csharp code <%if( ViewData["Message"] != null ){ %> +csharp code

<%=ViewData["Message"]%>


+csharp code <% } %> +html code
+html code

Welcome to ASP.NET

+html code

Type your name and click the button.

+html code

+html code +html code +html code

+html code

+html code +html code

+html code
+html code +html code diff --git a/test/expected_dir/vb.aspx b/test/expected_dir/vb.aspx new file mode 100644 index 0000000..aed2fe2 --- /dev/null +++ b/test/expected_dir/vb.aspx @@ -0,0 +1,26 @@ +visualbasic code <%@ Page Language="VB" %> +html code +html code +html code +html code Basic ASP.NET Web Page +html code +html code +html code
+html code

Welcome to ASP.NET

+html code

Type your name and click the button.

+html code

+html code +html code +html code

+html code

+html code +html code

+html code
+html code +html code diff --git a/test/src_dir/cs.aspx b/test/src_dir/cs.aspx new file mode 100644 index 0000000..b945fb2 --- /dev/null +++ b/test/src_dir/cs.aspx @@ -0,0 +1,29 @@ +<%@ Page Language="C#" %> + + + + Basic ASP.NET Web Page + + + <%if( ViewData["Message"] != null ){ %> +

<%=ViewData["Message"]%>


+ <% } %> +
+

Welcome to ASP.NET

+

Type your name and click the button.

+

+ + +

+

+ +

+
+ + diff --git a/test/src_dir/vb.aspx b/test/src_dir/vb.aspx new file mode 100644 index 0000000..8b7669e --- /dev/null +++ b/test/src_dir/vb.aspx @@ -0,0 +1,26 @@ +<%@ Page Language="VB" %> + + + + Basic ASP.NET Web Page + + +
+

Welcome to ASP.NET

+

Type your name and click the button.

+

+ + +

+

+ +

+
+ + diff --git a/test/unit/parsers/cs_aspx_test.rb b/test/unit/parsers/cs_aspx_test.rb new file mode 100644 index 0000000..0660bd3 --- /dev/null +++ b/test/unit/parsers/cs_aspx_test.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::CsAspxTest < Ohcount::Test + + def test_comment + html_lb = Ohcount::LanguageBreakdown.new("html", "<%\n%>", "", 0) + csharp_lb = Ohcount::LanguageBreakdown.new("csharp", "", "//comment\n", 0) + assert_equal [html_lb, csharp_lb], Ohcount::parse("<%\n //comment\n%>", "cs_aspx") + end + + def test_comprehensive + verify_parse("cs.aspx") + end + +end diff --git a/test/unit/parsers/vb_aspx_test.rb b/test/unit/parsers/vb_aspx_test.rb new file mode 100644 index 0000000..1cd10f0 --- /dev/null +++ b/test/unit/parsers/vb_aspx_test.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::VbAspxTest < Ohcount::Test + + def test_comment + html_lb = Ohcount::LanguageBreakdown.new("html", "<%\n%>", "", 0) + vb_lb = Ohcount::LanguageBreakdown.new("visualbasic", "", "'comment\n", 0) + assert_equal [html_lb, vb_lb], Ohcount::parse("<%\n 'comment\n%>", "vb_aspx") + end + + def test_comprehensive + verify_parse("vb.aspx") + end + +end From cd0d1071f76775278989d77fdf63545a8378e609 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 11 Nov 2008 16:51:42 -0800 Subject: [PATCH 046/387] [FIX] bin/ohcount failed when no dir given, or '.' specified --- lib/ohcount/source_file_list.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ohcount/source_file_list.rb b/lib/ohcount/source_file_list.rb index 78c545b..8100d56 100644 --- a/lib/ohcount/source_file_list.rb +++ b/lib/ohcount/source_file_list.rb @@ -29,7 +29,7 @@ def initialize(options = {}) end def files_from_paths(paths=[]) - paths.collect { |p| files_from_path(p) }.flatten + paths.collect { |p| files_from_path(File.expand_path(p)) }.flatten end def files_from_path(path) From 75f7fdd0b2f733369ed048bdf3eb7f785ba0b494 Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Tue, 11 Nov 2008 20:58:53 -0800 Subject: [PATCH 047/387] [FIX] Porting changes back from ohloh --- lib/ohcount/sloc_info.rb | 31 +++++++++++++++---------------- lib/ohcount/source_file.rb | 6 ++++++ 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/lib/ohcount/sloc_info.rb b/lib/ohcount/sloc_info.rb index 80f4ab7..40053b9 100644 --- a/lib/ohcount/sloc_info.rb +++ b/lib/ohcount/sloc_info.rb @@ -8,15 +8,16 @@ class Ohcount::SlocInfo attr_reader :language attr_accessor :code_added, :code_removed, :comments_added, :comments_removed, :blanks_added, :blanks_removed - def initialize(language) + def initialize(language, counts = {}) raise ArgumentError.new('language can not be nil') unless language @language = language - @code_added = 0 - @code_removed = 0 - @comments_added = 0 - @comments_removed = 0 - @blanks_added = 0 - @blanks_removed = 0 + + @code_added = counts[:code_added] || 0 + @code_removed = counts[:code_removed] || 0 + @comments_added = counts[:comments_added] || 0 + @comments_removed = counts[:comments_removed] || 0 + @blanks_added = counts[:blanks_added] || 0 + @blanks_removed = counts[:blanks_removed] || 0 end def ==(b) @@ -29,15 +30,6 @@ def ==(b) @blanks_removed == b.blanks_removed end - def empty? - if (@code_added == 0 && @code_removed == 0 && - @comments_added == 0 && @comments_removed == 0 && - @blanks_added == 0 && @blanks_removed == 0) - return true - end - return false - end - @@lang_map = { 'actionscript' => {:nice_name => 'ActionScript' , :category => 0}, 'ada' => {:nice_name => 'Ada' , :category => 0}, @@ -126,4 +118,11 @@ def language_category @@lang_map[self.language][:category] end + # return true if this sloc_info contains no measurable changes + def no_changes? + @code_added == 0 && @code_removed == 0 && + @comments_added == 0 && @comments_removed == 0 && + @blanks_added == 0 && @blanks_removed == 0 + end + end diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb index ded72cf..d76e3cf 100644 --- a/lib/ohcount/source_file.rb +++ b/lib/ohcount/source_file.rb @@ -116,5 +116,11 @@ def raw_entities(&block) Ohcount::parse_entities(contents, polyglot, &block) end + # returns the list of languages included in the parsed + # language_breakdowns + def languages + parse unless parsed? + @language_breakdowns.collect { |lb| lb.name } + end end end From 191d72101da27f621c6b9b97276ace03d27c13b7 Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Tue, 11 Nov 2008 21:08:44 -0800 Subject: [PATCH 048/387] [FIX] APplying ohloh integration changes --- rules/platforms.rb | 214 +++++++++++++++++++++++++++-------------------------- 1 file changed, 109 insertions(+), 105 deletions(-) diff --git a/rules/platforms.rb b/rules/platforms.rb index 083d522..d4bba83 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -1,108 +1,112 @@ # platforms -include Ohcount::Gestalt -class POSIX < Platform - # gnu_lib && generic - c_headers 'pthread.h', 'xstrtol.h', 'xreadlink.h', 'fatal-signal.h', 'diacrit.h', 'syslog.h', 'sys/stat.h' - - # autoconf means m4 (unix macro processor) - language :autoconf -end - -class Win32 < Platform - c_headers 'windows.h' - c_keywords 'WM_PAINT', 'ReleaseDC', 'WndProc', :min => 2 -end - -class WPF < Platform - filenames '\.xaml$' -end - -class Dot_NET < Platform - language :csharp, :min_percent => 10 -end - -class ASP_NET < Platform - filenames('\.(aspx|ascx|ashx|asax|axd)$') -end - -class Ruby < Platform - language :ruby, :min_percent => 15 -end - -class Rails < Platform - _and( - platform(Ruby), - ruby_keywords("RAILS_ROOT") - ) -end - -class Java < Platform - language :java, :min_percent => 15 -end - -class Javascript < Platform - language :javascript, :min_percent => 20 -end - -class JQuery < Platform - filenames 'jquery-\d.\d.\d.min.js' -end - -class SpringFramework < Platform - _and( - platform(Java), - filenames('spring\.jar$') - ) -end - -class XWindows < Platform - c_headers 'Xlib.h', 'X11\/xpm.h', 'X11/Xlib.h' -end - -class Mac < Platform - # apple events - c_keywords 'AppleEvent', 'AEBuildAppleEvent' - - # plist is a mac thing, right? - filenames '\.plist' -end - -class PHP < Platform - language :php, :min_percent => 15 -end - -class WxWidgets < Platform - c_headers 'wx/window.h' -end - -class CakePHP < Platform - _and( - platform(PHP), - php_keywords('CAKE_CORE_INCLUDE_PATH') - ) -end - -class KDE < Platform - c_headers 'KDEInit.h', 'kdeversion.h' -end - -class SQL < Platform - language :sql -end - -class MySQL < Platform - php_keywords('mysql_connect') -end - -class PostgreSQL < Platform - php_keywords('pg_connect') -end - -class MSDos < Platform - c_keywords '__MSDOS__', 'MSDOS', :min => 2 -end - -class EclipsePlatform < Platform - java_import 'org.eclipse.' +module Ohcount + module Gestalt + + class POSIX < Platform + # gnu_lib && generic + c_headers 'pthread.h', 'xstrtol.h', 'xreadlink.h', 'fatal-signal.h', 'diacrit.h', 'syslog.h', 'sys/stat.h' + + # autoconf means m4 (unix macro processor) + language :autoconf + end + + class Win32 < Platform + c_headers 'windows.h' + c_keywords 'WM_PAINT', 'ReleaseDC', 'WndProc', :min => 2 + end + + class WPF < Platform + filenames '\.xaml$' + end + + class Dot_NET < Platform + language :csharp, :min_percent => 10 + end + + class ASP_NET < Platform + filenames('\.(aspx|ascx|ashx|asax|axd)$') + end + + class Ruby < Platform + language :ruby, :min_percent => 15 + end + + class Rails < Platform + _and( + platform(Ruby), + ruby_keywords("RAILS_ROOT") + ) + end + + class Java < Platform + language :java, :min_percent => 15 + end + + class Javascript < Platform + language :javascript, :min_percent => 20 + end + + class JQuery < Platform + filenames 'jquery-\d.\d.\d.min.js' + end + + class SpringFramework < Platform + _and( + platform(Java), + filenames('spring\.jar$') + ) + end + + class XWindows < Platform + c_headers 'Xlib.h', 'X11\/xpm.h', 'X11/Xlib.h' + end + + class Mac < Platform + # apple events + c_keywords 'AppleEvent', 'AEBuildAppleEvent' + + # plist is a mac thing, right? + filenames '\.plist' + end + + class PHP < Platform + language :php, :min_percent => 15 + end + + class WxWidgets < Platform + c_headers 'wx/window.h' + end + + class CakePHP < Platform + _and( + platform(PHP), + php_keywords('CAKE_CORE_INCLUDE_PATH') + ) + end + + class KDE < Platform + c_headers 'KDEInit.h', 'kdeversion.h' + end + + class SQL < Platform + language :sql + end + + class MySQL < Platform + php_keywords('mysql_connect') + end + + class PostgreSQL < Platform + php_keywords('pg_connect') + end + + class MSDos < Platform + c_keywords '__MSDOS__', 'MSDOS', :min => 2 + end + + class EclipsePlatform < Platform + java_import 'org.eclipse.' + end + end end From 84295292d5ad629ee11e5dbcffafb2097babad2a Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Wed, 12 Nov 2008 10:51:38 -0800 Subject: [PATCH 049/387] [FIX] Detector now works against source files that aren't backed by real files --- lib/ohcount/detector.rb | 93 ++++++++++++++++++++----------------------- lib/ohcount/scratch_dir.rb | 16 ++------ lib/ohcount/source_file.rb | 38 +++++++++++++++++- test/unit/detector_test.rb | 13 +++++- test/unit/source_file_test.rb | 7 ++++ 5 files changed, 103 insertions(+), 64 deletions(-) diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index e7f2a74..4dd3ee4 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -254,12 +254,12 @@ def self.lines_matching(buffer, re) # This is done with a weighted heuristic that # scans the *.m file contents for keywords, # and also checks for the presence of matching *.h files. - def self.matlab_or_objective_c(file_context) - buffer = file_context.contents + def self.matlab_or_objective_c(source_file) + buffer = source_file.contents # if there are .h files in same directory, this probably isn't matlab h_headers = 0.0 - h_headers = -0.5 if file_context.filenames.select { |a| a =~ /\.h$/ }.any? + h_headers = -0.5 if source_file.filenames.select { |a| a =~ /\.h$/ }.any? # if the contents contain 'function (' on a single line - very likely to be matlab # if the contents contain lines starting with '%', its probably matlab comments @@ -281,22 +281,22 @@ def self.matlab_or_objective_c(file_context) # scans the *.h file contents for Objective-C keywords, # C++ keywords and C++ headers, and also checks for the # presence of matching *.m files. - def self.disambiguate_h_header(file_context) - buffer = file_context.contents + def self.disambiguate_h_header(source_file) + buffer = source_file.contents # could it be realistically be objective_c ? are there any .m files at all? # Speed hack - remember our findings in case we get the same filenames over and over - unless defined?(file_context.filenames.contains_m) - file_context.filenames.extend(ContainsM) - file_context.filenames.contains_m = file_context.filenames.select { |a| a =~ /\.m$/ }.any? - file_context.filenames.contains_pike_or_pmod = file_context.filenames.select { |a| a =~ /\.p(ike|mod)$/ }.any? + unless defined?(source_file.filenames.contains_m) + source_file.filenames.extend(ContainsM) + source_file.filenames.contains_m = source_file.filenames.select { |a| a =~ /\.m$/ }.any? + source_file.filenames.contains_pike_or_pmod = source_file.filenames.select { |a| a =~ /\.p(ike|mod)$/ }.any? end - if file_context.filenames.contains_m + if source_file.filenames.contains_m # if the dir contains a matching *.m file, likely objective_c - if file_context.filename =~ /\.h$/ - m_counterpart = file_context.filename.gsub(/\.h$/, ".m") - return 'objective_c' if file_context.filenames.include?(m_counterpart) + if source_file.filename =~ /\.h$/ + m_counterpart = source_file.filename.gsub(/\.h$/, ".m") + return 'objective_c' if source_file.filenames.include?(m_counterpart) end # ok - it just might be objective_c, let's check contents for objective_c signatures @@ -305,7 +305,7 @@ def self.disambiguate_h_header(file_context) return 'objective_c' if objective_c > 1 end - if file_context.filenames.contains_pike_or_pmod + if source_file.filenames.contains_pike_or_pmod # The string "pike" and a selection of common Pike keywords. pike_signatures = /([Pp][Ii][Kk][Ee])|(string )|(mapping)|(multiset)|(import )|(inherit )|(predef)/ pike = lines_matching(buffer, pike_signatures) @@ -464,35 +464,31 @@ def self.php_instruction?(buffer) # For *.in files, checks the prior extension. # Typically used for template files (eg Makefile.in, auto.c.in, etc). def self.disambiguate_in(source_file) - # if the filename has an extension prior to the .in - if source_file.filename =~ /\..*\.in$/ - undecorated_filename = source_file.filename.gsub(/\.in$/, "") - undecorated_source = Ohcount::SourceFile.new(undecorated_filename, - :filenames => source_file.filenames, - :contents => source_file.contents, - :file_location => source_file.file_location) - return detect(undecorated_source) - end - nil + # only if the filename has an extension prior to the .in + return nil unless source_file.filename =~ /\..*\.in$/ + + undecorated_filename = source_file.filename.gsub(/\.in$/, "") + undecorated_source = source_file.clone_and_rename(undecorated_filename) + detect(undecorated_source) end # For *.inc files, checks for a PHP class. - def self.disambiguate_inc(file_context) - buffer = file_context.contents + def self.disambiguate_inc(source_file) + buffer = source_file.contents return nil if binary_buffer?(buffer) return 'php' if php_instruction?(buffer) nil end # For files with extention *.cs, differentiates C# from Clearsilver. - def self.disambiguate_cs(file_context) - buffer = file_context.contents - return 'clearsilver_template' if lines_matching(file_context.contents, /\<\?cs/) > 0 + def self.disambiguate_cs(source_file) + buffer = source_file.contents + return 'clearsilver_template' if lines_matching(source_file.contents, /\<\?cs/) > 0 return 'csharp' end - def self.disambiguate_fortran(file_context) - buffer = file_context.contents + def self.disambiguate_fortran(source_file) + buffer = source_file.contents definitely_not_f77 = /^ [^0-9 ]{5}/ return 'fortranfixed' if lines_matching(buffer, definitely_not_f77) > 0 @@ -509,8 +505,8 @@ def self.disambiguate_fortran(file_context) end # A *.aspx file may be scripted with either C# or VB.NET. - def self.disambiguate_aspx(file_context) - if file_context.contents.match(/<%@\s*Page[^>]+Language="VB"[^>]+%>/i) + def self.disambiguate_aspx(source_file) + if source_file.contents.match(/<%@\s*Page[^>]+Language="VB"[^>]+%>/i) 'vb_aspx' else 'cs_aspx' @@ -524,18 +520,18 @@ def self.disambiguate_aspx(file_context) # # If these files are absent, assumes structured BASIC # - def self.disambiguate_basic(file_context) + def self.disambiguate_basic(source_file) classic_basic_line = /^\d+\s+\w+.*$/ vb_filename = /\.fr[mx]$|\.vb([aps]?)$/ - buffer = file_context.contents + buffer = source_file.contents if lines_matching(buffer,classic_basic_line) > 0 return 'classic_basic' else - unless defined?(file_context.filenames.contains_vb) - file_context.filenames.extend(ContainsVB) - file_context.filenames.contains_vb = file_context.filenames.select { |a| a =~ vb_filename }.any? + unless defined?(source_file.filenames.contains_vb) + source_file.filenames.extend(ContainsVB) + source_file.filenames.contains_vb = source_file.filenames.select { |a| a =~ vb_filename }.any? end - if file_context.filenames.contains_vb + if source_file.filenames.contains_vb return 'visualbasic' else return 'structured_basic' @@ -543,9 +539,9 @@ def self.disambiguate_basic(file_context) end end - def self.disambiguate_non_visual_basic(file_context) + def self.disambiguate_non_visual_basic(source_file) classic_basic_line = /^\d+\s+\w+.*$/ - buffer = file_context.contents + buffer = source_file.contents if lines_matching(buffer,classic_basic_line) > 0 return 'classic_basic' @@ -554,18 +550,17 @@ def self.disambiguate_non_visual_basic(file_context) end end - # Attempts to determine the Polyglot for files that do not have a - # filename extension. + # Attempts to determine the Polyglot for files that do not have a filename + # extension. # # Relies on the bash +file+ command line tool as its primary method. # - # There must be a file at file_context.file_location for +file+ - # to operate on. + # There must be a file at source_file.file_location for +file+ to + # operate on. # - def self.disambiguate_nil(file_context) - file_location = file_context.file_location - output = `file -b '#{ file_location }'` - case output + def self.disambiguate_nil(source_file) + file_output = source_file.realize_file { |f| `file -b '#{ f }'` } + case file_output when /([\w\/]+)(?: -[\w_]+)* script text/, /script text executable for ([\w\/]+)/ script = $1 if script =~ /\/(\w*)$/ diff --git a/lib/ohcount/scratch_dir.rb b/lib/ohcount/scratch_dir.rb index f29fdad..c8050cb 100644 --- a/lib/ohcount/scratch_dir.rb +++ b/lib/ohcount/scratch_dir.rb @@ -1,5 +1,4 @@ require 'fileutils' -require 'tmpdir' # A utility class to manage the creation and automatic cleanup of temporary directories. class ScratchDir @@ -21,17 +20,10 @@ class ScratchDir # end # Scratch directory is deleted here # def initialize - until @path - @path = File.join(Dir.tmpdir, Time.now.utc.strftime("ohloh_%Y%H%m%S#{rand(900) + 100}")) - begin - Dir.mkdir(@path) - rescue Errno::EEXIST - @path = nil - end - end + @path = `mktemp -d /tmp/ohcount_XXXXX`.strip if block_given? begin - yield @path + return yield @path ensure FileUtils.rm_rf(@path) end @@ -44,8 +36,8 @@ def initialize ScratchDir.new do |d| path = d - STDOUT.puts "Created scratch direcory #{d}" - File.open(File.join(d, "test"), "w") do |io| + filename = File.join(d,"test") + File.open(filename, "w") do |io| io.write "test" end end diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb index d76e3cf..f2a3031 100644 --- a/lib/ohcount/source_file.rb +++ b/lib/ohcount/source_file.rb @@ -1,3 +1,5 @@ +require 'tempfile' + module Ohcount # SourceFile abstracts a source code file and allows easy querying of ohcount-related @@ -46,7 +48,7 @@ def initialize(filename, options = {}) @filename = filename @filenames = options[:filenames] || [] @contents = options[:contents] - @file_location = options[:file_location] || @filename + @file_location = options[:file_location] end def contents @@ -67,7 +69,9 @@ def polyglot # returns true iff we represent a file (could be a dir) def file? - File.file?(@file_location) || @contents + File.exist?(@filename) && File.file?(@filename) || + @file_location && File.exist?(@file_location) && File.file?(@file_location) || + @contents end def basename @@ -99,6 +103,36 @@ def language_breakdowns(language = nil) @language_breakdowns end + def clone_and_rename(new_name) + attributes = { + :filenames => filenames, + :contents => contents, + :file_location => file_location || filename + } + Ohcount::SourceFile.new(new_name, attributes) + end + + # will yield with the current directory set in a way that the filename + # exists and contains the actual file contents. + # + # This is useful to call when a file must absolutely be referenced on disk. + def realize_file + raise ArgumentError.new('Missing block?') unless block_given? + + if File.exist?(@filename) + yield @filename + elsif @file_location && File.basename(@file_location) == basename + yield @file_location + else + # must recreate a directory and stuff + ScratchDir.new do |d| + realized_filename = File.join(d,basename) + File.open(realized_filename, "w") { |io| io.write(contents) } + return yield realized_filename + end + end + end + def licenses @licenses ||= begin comments = '' diff --git a/test/unit/detector_test.rb b/test/unit/detector_test.rb index 59e18dc..12e92cf 100644 --- a/test/unit/detector_test.rb +++ b/test/unit/detector_test.rb @@ -20,6 +20,17 @@ # class Ohcount::DetectorTest < Ohcount::Test + def test_with_source_file_without_backing_file + contents = < contents) + assert_equal 'ruby', source_file.polyglot + end + def do_detect(filename, filenames = []) filepath = File.dirname(__FILE__) + "/../detect_files/" + filename SourceFile.new(filepath, {:filenames => filenames}).polyglot @@ -41,7 +52,7 @@ def test_matlab_or_objective_c assert_equal 'objective_c', do_detect("t2.m") end - def text_fortran_fixedfree + def test_fortran_fixedfree assert_equal 'fortranfixed', do_detect("fortranfixed.f") assert_equal 'fortranfree', do_detect("fortranfree.f") end diff --git a/test/unit/source_file_test.rb b/test/unit/source_file_test.rb index bfd5ffd..8548daf 100644 --- a/test/unit/source_file_test.rb +++ b/test/unit/source_file_test.rb @@ -29,5 +29,12 @@ def test_parse end assert_equal contents, ruby_code end + + def test_realize_file + s = SourceFile.new('foo.c', :contents => 'i') + s.realize_file do |f| + assert_equal 'i', File.new(f).read + end + end end From c16d24b01cea4ad501e2198aa878a63b0e2ab41a Mon Sep 17 00:00:00 2001 From: brucey Date: Wed, 29 Oct 2008 15:46:00 -0700 Subject: [PATCH 050/387] [NEW] Blitzmax parser --- ext/ohcount_native/ragel_parser.c | 2 + ext/ohcount_native/ragel_parsers/blitzmax.rl | 123 +++++++++++++++++++++++++++ lib/ohcount/detector.rb | 1 + lib/ohcount/sloc_info.rb | 1 + test/detect_files/blitzmax.bmx | 32 +++++++ test/expected_dir/blitzmax.bmx | 32 +++++++ test/src_dir/blitzmax.bmx | 32 +++++++ test/unit/blitzmax_test.rb | 16 ++++ 8 files changed, 239 insertions(+) create mode 100644 ext/ohcount_native/ragel_parsers/blitzmax.rl create mode 100644 test/detect_files/blitzmax.bmx create mode 100644 test/expected_dir/blitzmax.bmx create mode 100644 test/src_dir/blitzmax.bmx create mode 100644 test/unit/blitzmax_test.rb diff --git a/ext/ohcount_native/ragel_parser.c b/ext/ohcount_native/ragel_parser.c index 9aa02dc..c00c942 100644 --- a/ext/ohcount_native/ragel_parser.c +++ b/ext/ohcount_native/ragel_parser.c @@ -11,6 +11,7 @@ #include "automake_parser.h" #include "awk_parser.h" #include "bat_parser.h" +#include "blitzmax_parser.h" #include "boo_parser.h" #include "c_parser.h" #include "classic_basic_parser.h" @@ -88,6 +89,7 @@ struct language languages[] = { { "automake", parse_automake }, { "awk", parse_awk }, { "bat", parse_bat }, + { "blitzmax", parse_blitzmax }, { "boo", parse_boo }, { "c", parse_c }, { "classic_basic", parse_classic_basic }, diff --git a/ext/ohcount_native/ragel_parsers/blitzmax.rl b/ext/ohcount_native/ragel_parsers/blitzmax.rl new file mode 100644 index 0000000..43a58df --- /dev/null +++ b/ext/ohcount_native/ragel_parsers/blitzmax.rl @@ -0,0 +1,123 @@ +// blitzmax.rl written by Bruce A Henderson (http://brucey.net) + +/************************* Required for every parser *************************/ +#ifndef RAGEL_BLITZMAX_PARSER +#define RAGEL_BLITZMAX_PARSER + +#include "ragel_parser_macros.h" + +// the name of the language +const char *BLITZMAX_LANG = "blitzmax"; + +// the languages entities +const char *blitzmax_entities[] = { + "space", "comment", "string", "any" +}; + +// constants associated with the entities +enum { + BLITZMAX_SPACE = 0, BLITZMAX_COMMENT, BLITZMAX_STRING, BLITZMAX_ANY +}; + +/*****************************************************************************/ + +%%{ + machine blitzmax; + write data; + include common "common.rl"; + + # Line counting machine + + action blitzmax_ccallback { + switch(entity) { + case BLITZMAX_SPACE: + ls + break; + case BLITZMAX_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(BLITZMAX_LANG) + break; + case NEWLINE: + std_newline(BLITZMAX_LANG) + } + } + + blitzmax_line_comment = '\'' @comment nonnewline*; + blitzmax_rem_block_comment = + /rem/i @comment ( + newline %{ entity = INTERNAL_NL; } %blitzmax_ccallback + | + ws + | + (nonnewline - ws) @comment + )* :>> (/end rem/i | /endrem/i); + + blitzmax_comment = blitzmax_line_comment | blitzmax_rem_block_comment; + + blitzmax_string = '"' @code ([^\r\n\f"\\] | '\\' nonnewline)* '"'; + + blitzmax_line := |* + spaces ${ entity = BLITZMAX_SPACE; } => blitzmax_ccallback; + blitzmax_comment; + blitzmax_string; + newline ${ entity = NEWLINE; } => blitzmax_ccallback; + ^space ${ entity = BLITZMAX_ANY; } => blitzmax_ccallback; + *|; + + # Entity machine + + action blitzmax_ecallback { + callback(BLITZMAX_LANG, blitzmax_entities[entity], cint(ts), cint(te)); + } + + blitzmax_line_comment_entity = '\'' nonnewline*; + blitzmax_rem_block_comment_entity = + /rem/i ( + newline %{ entity = INTERNAL_NL; } %blitzmax_ecallback + | + ws + | + (nonnewline - ws) + )* :>> (/end rem/i | /endrem/i); + + blitzmax_comment_entity = blitzmax_line_comment_entity | blitzmax_line_comment_entity; + + blitzmax_entity := |* + space+ ${ entity = BLITZMAX_SPACE; } => blitzmax_ecallback; + blitzmax_comment_entity ${ entity = BLITZMAX_COMMENT; } => blitzmax_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with BlitzMax code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_blitzmax(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int start, int end) + ) { + init + + %% write init; + cs = (count) ? blitzmax_en_blitzmax_line : blitzmax_en_blitzmax_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(BLITZMAX_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index f18a7b2..68c68fc 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -119,6 +119,7 @@ def self.binary_filename?(filename) '.bas' => :disambiguate_basic, '.bat' => "bat", '.bi' => :disambiguate_non_visual_basic, + '.bmx' => "blitzmax", '.boo' => "boo", '.c' => "c", '.C' => "cpp", diff --git a/lib/ohcount/sloc_info.rb b/lib/ohcount/sloc_info.rb index 82040a9..b8a28f9 100644 --- a/lib/ohcount/sloc_info.rb +++ b/lib/ohcount/sloc_info.rb @@ -46,6 +46,7 @@ def empty? 'automake' => {:nice_name => 'Automake' , :category => 2}, 'awk' => {:nice_name => 'AWK' , :category => 0}, 'bat' => {:nice_name => 'DOS batch script' , :category => 0}, + 'bmx' => {:nice_name => 'BlitzMax' , :category => 0}, 'boo' => {:nice_name => 'Boo' , :category => 0}, 'c' => {:nice_name => 'C' , :category => 0}, 'classic_basic' => {:nice_name => 'Classic Basic' , :category => 0}, diff --git a/test/detect_files/blitzmax.bmx b/test/detect_files/blitzmax.bmx new file mode 100644 index 0000000..da4ae51 --- /dev/null +++ b/test/detect_files/blitzmax.bmx @@ -0,0 +1,32 @@ +' +' Comments +' +SuperStrict + +Rem +bbdoc: docs +End Rem +Module bah.fish + +Import BRL.StandardIO + +Import "test.bmx" ' comment + +rem +some comments + + +Type blah +still in comments +End Type + +endrem + +Type TABC + + Method hello() + End Method + +End Type + +print "hello rem fish ' " diff --git a/test/expected_dir/blitzmax.bmx b/test/expected_dir/blitzmax.bmx new file mode 100644 index 0000000..02af933 --- /dev/null +++ b/test/expected_dir/blitzmax.bmx @@ -0,0 +1,32 @@ +blitzmax comment ' +blitzmax comment ' Comments +blitzmax comment ' +blitzmax code SuperStrict +blitzmax blank +blitzmax comment Rem +blitzmax comment bbdoc: docs +blitzmax comment End Rem +blitzmax code Module bah.fish +blitzmax blank +blitzmax code Import BRL.StandardIO +blitzmax blank +blitzmax code Import "test.bmx" ' comment +blitzmax blank +blitzmax comment rem +blitzmax comment some comments +blitzmax blank +blitzmax blank +blitzmax comment Type blah +blitzmax comment still in comments +blitzmax comment End Type +blitzmax blank +blitzmax comment endrem +blitzmax blank +blitzmax code Type TABC +blitzmax blank +blitzmax code Method hello() +blitzmax code End Method +blitzmax blank +blitzmax code End Type +blitzmax blank +blitzmax code print "hello rem fish ' " diff --git a/test/src_dir/blitzmax.bmx b/test/src_dir/blitzmax.bmx new file mode 100644 index 0000000..da4ae51 --- /dev/null +++ b/test/src_dir/blitzmax.bmx @@ -0,0 +1,32 @@ +' +' Comments +' +SuperStrict + +Rem +bbdoc: docs +End Rem +Module bah.fish + +Import BRL.StandardIO + +Import "test.bmx" ' comment + +rem +some comments + + +Type blah +still in comments +End Type + +endrem + +Type TABC + + Method hello() + End Method + +End Type + +print "hello rem fish ' " diff --git a/test/unit/blitzmax_test.rb b/test/unit/blitzmax_test.rb new file mode 100644 index 0000000..75317e3 --- /dev/null +++ b/test/unit/blitzmax_test.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class Ohcount::BlitzMaxTest < Ohcount::Test + def test_sb_comments + lb = [Ohcount::LanguageBreakdown.new("blitzmax", "", "' comment", 0)] + assert_equal lb, Ohcount::parse("' comment", "blitzmax") + end + + def test_comprehensive + verify_parse("blitzmax.bmx") + end + + def test_comment_entities + assert_equal('\' comment', entities_array(" ' comment", 'blitzmax', :comment).first) + end +end From c7bf6c655830ce6bbc82dafc8e645f5bcd030891 Mon Sep 17 00:00:00 2001 From: inequation Date: Fri, 31 Oct 2008 17:25:00 -0700 Subject: [PATCH 051/387] [NEW] GLSL parser --- ext/ohcount_native/ragel_parser.c | 2 + ext/ohcount_native/ragel_parsers/glsl.rl | 183 +++++++++++++++++++++++++++++++ lib/ohcount/detector.rb | 3 + lib/ohcount/sloc_info.rb | 1 + test/detect_files/foo.glsl | 6 + test/detect_files/foo_glsl.vert | 4 + test/expected_dir/foo.glsl | 4 + test/expected_dir/foo_glsl.vert | 43 ++++++++ test/src_dir/foo.glsl | 4 + test/src_dir/foo_glsl.vert | 43 ++++++++ test/unit/detector_test.rb | 3 + test/unit/glsl_test.rb | 31 ++++++ 12 files changed, 327 insertions(+) create mode 100644 ext/ohcount_native/ragel_parsers/glsl.rl create mode 100644 test/detect_files/foo.glsl create mode 100644 test/detect_files/foo_glsl.vert create mode 100644 test/expected_dir/foo.glsl create mode 100644 test/expected_dir/foo_glsl.vert create mode 100644 test/src_dir/foo.glsl create mode 100644 test/src_dir/foo_glsl.vert create mode 100644 test/unit/glsl_test.rb diff --git a/ext/ohcount_native/ragel_parser.c b/ext/ohcount_native/ragel_parser.c index 9aa02dc..8740e1c 100644 --- a/ext/ohcount_native/ragel_parser.c +++ b/ext/ohcount_native/ragel_parser.c @@ -27,6 +27,7 @@ #include "factor_parser.h" #include "fortranfixed_parser.h" #include "fortranfree_parser.h" +#include "glsl_parser.h" #include "groovy_parser.h" #include "haml_parser.h" #include "haskell_parser.h" @@ -107,6 +108,7 @@ struct language languages[] = { { "factor", parse_factor }, { "fortranfixed", parse_fortranfixed }, { "fortranfree", parse_fortranfree }, + { "glsl", parse_glsl }, { "groovy", parse_groovy }, { "haskell", parse_haskell }, { "haml", parse_haml }, diff --git a/ext/ohcount_native/ragel_parsers/glsl.rl b/ext/ohcount_native/ragel_parsers/glsl.rl new file mode 100644 index 0000000..93a2426 --- /dev/null +++ b/ext/ohcount_native/ragel_parsers/glsl.rl @@ -0,0 +1,183 @@ +// glsl.rl by Leszek Godlewski +// Written according to GLSL 1.20.8 specificiation +// Based on c.rl written by Mitchell Foral. mitchellcaladbolgnet. + +/************************* Required for every parser *************************/ +#ifndef RAGEL_GLSL_PARSER +#define RAGEL_GLSL_PARSER + +#include "ragel_parser_macros.h" + +// the name of the language +const char *GLSL_LANG = "glsl"; + +// the languages entities +const char *glsl_entities[] = { + "space", "comment", "string", "number", "preproc", + "keyword", "identifier", "operator", "any" +}; + +// constants associated with the entities +enum { + GLSL_SPACE = 0, GLSL_COMMENT, GLSL_STRING, GLSL_NUMBER, GLSL_PREPROC, + GLSL_KEYWORD, GLSL_IDENTIFIER, GLSL_OPERATOR, GLSL_ANY +}; + +/*****************************************************************************/ + +%%{ + machine glsl; + write data; + include common "common.rl"; + + # Line counting machine + + action glsl_ccallback { + switch(entity) { + case GLSL_SPACE: + ls + break; + case GLSL_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(GLSL_LANG) + break; + case NEWLINE: + std_newline(GLSL_LANG) + } + } + + glsl_line_comment = + '//' @comment ( + escaped_newline %{ entity = INTERNAL_NL; } %glsl_ccallback + | + ws + | + (nonnewline - ws) @comment + )*; + glsl_block_comment = + '/*' @comment ( + newline %{ entity = INTERNAL_NL; } %glsl_ccallback + | + ws + | + (nonnewline - ws) @comment + )* :>> '*/'; + glsl_comment = glsl_line_comment | glsl_block_comment; + + glsl_sq_str = + '\'' @code ( + escaped_newline %{ entity = INTERNAL_NL; } %glsl_ccallback + | + ws + | + [^\t '\\] @code + | + '\\' nonnewline @code + )* '\''; + glsl_dq_str = + '"' @code ( + escaped_newline %{ entity = INTERNAL_NL; } %glsl_ccallback + | + ws + | + [^\t "\\] @code + | + '\\' nonnewline @code + )* '"'; + glsl_string = glsl_sq_str | glsl_dq_str; + + glsl_line := |* + spaces ${ entity = GLSL_SPACE; } => glsl_ccallback; + glsl_comment; + glsl_string; + newline ${ entity = NEWLINE; } => glsl_ccallback; + ^space ${ entity = GLSL_ANY; } => glsl_ccallback; + *|; + + # Entity machine + + action glsl_ecallback { + callback(GLSL_LANG, glsl_entities[entity], cint(ts), cint(te)); + } + + glsl_line_comment_entity = '//' (escaped_newline | nonnewline)*; + glsl_block_comment_entity = '/*' any* :>> '*/'; + glsl_comment_entity = glsl_line_comment_entity | glsl_block_comment_entity; + + glsl_string_entity = sq_str_with_escapes | dq_str_with_escapes; + + glsl_number_entity = float | integer; + + glsl_preproc_word = + # macros + 'define' | 'undef' | + # conditionals + 'if' | 'ifdef' | 'ifndef' | 'else' | 'elif' | 'endif' | + # miscellanous + 'pragma' | 'error' | 'extension' | 'version' | 'line'; + # TODO: find some way of making preproc match the beginning of a line. + # Putting a 'when starts_line' conditional throws an assertion error. + glsl_preproc_entity = + '#' space* (glsl_block_comment_entity space*)? + glsl_preproc_word (escaped_newline | nonnewline)*; + + glsl_identifier_entity = (alpha | '_') (alnum | '_')*; + + glsl_keyword_entity = + 'attribute' | 'const' | 'uniform' | 'varying' | 'centroid' | 'break' | + 'continue' | 'do' | 'for' | 'while' | 'if' | 'else' | 'in' | 'out' | + 'inout' | 'float' | 'int' | 'void' | 'bool' | 'true' | 'false' | + 'invariant' | 'discard' | 'return' | 'mat2' | 'mat3' | 'mat4' | + 'mat2x2' | 'mat2x3' | 'mat2x4' | 'mat3x2' | 'mat3x3' | 'mat3x4' | + 'mat4x2' | 'mat4x3' | 'mat4x4' | 'vec2' | 'vec3' | 'vec4' | 'ivec2' | + 'ivec3' | 'ivec4' | 'bvec2' | 'bvec3' | 'bvec4' | 'sampler1D' | + 'sampler2D' | 'sampler3D' | 'samplerCube' | 'sampler1DShadow' | + 'sampler2DShadow' | 'struct'; + # not including keywords reserved for future use + + glsl_operator_entity = [+\-/*%<>!=^&|?~:;.,()\[\]{}]; + + glsl_entity := |* + space+ ${ entity = GLSL_SPACE; } => glsl_ecallback; + glsl_comment_entity ${ entity = GLSL_COMMENT; } => glsl_ecallback; + glsl_string_entity ${ entity = GLSL_STRING; } => glsl_ecallback; + glsl_number_entity ${ entity = GLSL_NUMBER; } => glsl_ecallback; + glsl_preproc_entity ${ entity = GLSL_PREPROC; } => glsl_ecallback; + glsl_identifier_entity ${ entity = GLSL_IDENTIFIER; } => glsl_ecallback; + glsl_keyword_entity ${ entity = GLSL_KEYWORD; } => glsl_ecallback; + glsl_operator_entity ${ entity = GLSL_OPERATOR; } => glsl_ecallback; + ^(space | digit) ${ entity = GLSL_ANY; } => glsl_ecallback; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with OpenGL Shading Language code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_glsl(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int start, int end) + ) { + init + + %% write init; + cs = (count) ? glsl_en_glsl_line : glsl_en_glsl_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(GLSL_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index f18a7b2..8cc102f 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -147,7 +147,9 @@ def self.binary_filename?(filename) '.f90' => :disambiguate_fortran, '.f95' => :disambiguate_fortran, '.f03' => :disambiguate_fortran, + '.frag' => "glsl", '.frx' => "visualbasic", + '.glsl' => "glsl", '.groovy'=> "groovy", '.h' => :disambiguate_h_header, '.haml' => 'haml', @@ -214,6 +216,7 @@ def self.binary_filename?(filename) '.vb' => "visualbasic", '.vba' => "visualbasic", '.vbs' => "visualbasic", + '.vert' => "glsl", '.vhd' => "vhdl", '.vhdl' => "vhdl", '.vim' => "vim", diff --git a/lib/ohcount/sloc_info.rb b/lib/ohcount/sloc_info.rb index 82040a9..4c78216 100644 --- a/lib/ohcount/sloc_info.rb +++ b/lib/ohcount/sloc_info.rb @@ -63,6 +63,7 @@ def empty? 'factor' => {:nice_name => 'Factor' , :category => 0}, 'fortranfixed' => {:nice_name => 'Fortran (Fixed-format)', :category => 0}, 'fortranfree' => {:nice_name => 'Fortran (Free-format)', :category => 0}, + 'glsl' => {:nice_name => 'OpenGL Shading Language', :category => 0}, 'groovy' => {:nice_name => 'Groovy' , :category => 0}, 'haml' => {:nice_name => 'Haml' , :category => 1}, 'haxe' => {:nice_name => 'HaXe' , :category => 0}, diff --git a/test/detect_files/foo.glsl b/test/detect_files/foo.glsl new file mode 100644 index 0000000..8c69fe1 --- /dev/null +++ b/test/detect_files/foo.glsl @@ -0,0 +1,6 @@ +// GLSL fragment shader +uniform sampler2D tex; + +void main() { + gl_FragColor = gl_Color * texture2D(tex, gl_TexCoord[0].xy); +} \ No newline at end of file diff --git a/test/detect_files/foo_glsl.vert b/test/detect_files/foo_glsl.vert new file mode 100644 index 0000000..e134a61 --- /dev/null +++ b/test/detect_files/foo_glsl.vert @@ -0,0 +1,4 @@ +// GLSL vertex shader +void main() { + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; +} \ No newline at end of file diff --git a/test/expected_dir/foo.glsl b/test/expected_dir/foo.glsl new file mode 100644 index 0000000..97f3b9a --- /dev/null +++ b/test/expected_dir/foo.glsl @@ -0,0 +1,4 @@ +glsl comment // GLSL vertex shader +glsl code void main() { +glsl code gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; +glsl code } \ No newline at end of file diff --git a/test/expected_dir/foo_glsl.vert b/test/expected_dir/foo_glsl.vert new file mode 100644 index 0000000..48dafda --- /dev/null +++ b/test/expected_dir/foo_glsl.vert @@ -0,0 +1,43 @@ +glsl comment // from OGRE3D's skinningTwoWeightsShadowCasterVp.glsl +glsl comment // Example GLSL program for skinning with two bone weights per vertex +glsl blank +glsl code attribute vec4 vertex; +glsl code attribute vec4 uv0; +glsl code attribute vec4 blendIndices; +glsl code attribute vec4 blendWeights; +glsl blank +glsl comment // 3x4 matrix, passed as vec4's for compatibility with GL 2.0 +glsl comment // GL 2.0 supports 3x4 matrices +glsl comment // Support 24 bones ie 24*3, but use 72 since our parser can pick that out for sizing +glsl code uniform vec4 worldMatrix3x4Array[72]; +glsl code uniform mat4 viewProjectionMatrix; +glsl code uniform vec4 ambient; +glsl blank +glsl code void main() +glsl code { +glsl code vec3 blendPos = vec3(0,0,0); +glsl blank +glsl code for (int bone = 0; bone < 2; ++bone) +glsl code { +glsl comment // perform matrix multiplication manually since no 3x4 matrices +glsl comment // ATI GLSL compiler can't handle indexing an array within an array so calculate the inner index first +glsl code int idx = int(blendIndices[bone]) * 3; +glsl comment // ATI GLSL compiler can't handle unrolling the loop so do it manually +glsl comment // ATI GLSL has better performance when mat4 is used rather than using individual dot product +glsl comment // There is a bug in ATI mat4 constructor (Cat 7.2) when indexed uniform array elements are used as vec4 parameter so manually assign +glsl code mat4 worldMatrix; +glsl code worldMatrix[0] = worldMatrix3x4Array[idx]; +glsl code worldMatrix[1] = worldMatrix3x4Array[idx + 1]; +glsl code worldMatrix[2] = worldMatrix3x4Array[idx + 2]; +glsl code worldMatrix[3] = vec4(0); +glsl comment // now weight this into final +glsl code blendPos += (vertex * worldMatrix).xyz * blendWeights[bone]; +glsl code } +glsl blank +glsl comment // apply view / projection to position +glsl code gl_Position = viewProjectionMatrix * vec4(blendPos, 1); +glsl blank +glsl code gl_FrontSecondaryColor = vec4(0,0,0,0); +glsl code gl_FrontColor = ambient; +glsl code gl_TexCoord[0] = uv0; +glsl code } diff --git a/test/src_dir/foo.glsl b/test/src_dir/foo.glsl new file mode 100644 index 0000000..e134a61 --- /dev/null +++ b/test/src_dir/foo.glsl @@ -0,0 +1,4 @@ +// GLSL vertex shader +void main() { + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; +} \ No newline at end of file diff --git a/test/src_dir/foo_glsl.vert b/test/src_dir/foo_glsl.vert new file mode 100644 index 0000000..4f2d4fc --- /dev/null +++ b/test/src_dir/foo_glsl.vert @@ -0,0 +1,43 @@ +// from OGRE3D's skinningTwoWeightsShadowCasterVp.glsl +// Example GLSL program for skinning with two bone weights per vertex + +attribute vec4 vertex; +attribute vec4 uv0; +attribute vec4 blendIndices; +attribute vec4 blendWeights; + +// 3x4 matrix, passed as vec4's for compatibility with GL 2.0 +// GL 2.0 supports 3x4 matrices +// Support 24 bones ie 24*3, but use 72 since our parser can pick that out for sizing +uniform vec4 worldMatrix3x4Array[72]; +uniform mat4 viewProjectionMatrix; +uniform vec4 ambient; + +void main() +{ + vec3 blendPos = vec3(0,0,0); + + for (int bone = 0; bone < 2; ++bone) + { + // perform matrix multiplication manually since no 3x4 matrices + // ATI GLSL compiler can't handle indexing an array within an array so calculate the inner index first + int idx = int(blendIndices[bone]) * 3; + // ATI GLSL compiler can't handle unrolling the loop so do it manually + // ATI GLSL has better performance when mat4 is used rather than using individual dot product + // There is a bug in ATI mat4 constructor (Cat 7.2) when indexed uniform array elements are used as vec4 parameter so manually assign + mat4 worldMatrix; + worldMatrix[0] = worldMatrix3x4Array[idx]; + worldMatrix[1] = worldMatrix3x4Array[idx + 1]; + worldMatrix[2] = worldMatrix3x4Array[idx + 2]; + worldMatrix[3] = vec4(0); + // now weight this into final + blendPos += (vertex * worldMatrix).xyz * blendWeights[bone]; + } + + // apply view / projection to position + gl_Position = viewProjectionMatrix * vec4(blendPos, 1); + + gl_FrontSecondaryColor = vec4(0,0,0,0); + gl_FrontColor = ambient; + gl_TexCoord[0] = uv0; +} diff --git a/test/unit/detector_test.rb b/test/unit/detector_test.rb index c917674..519a718 100644 --- a/test/unit/detector_test.rb +++ b/test/unit/detector_test.rb @@ -72,6 +72,9 @@ def test_detect_polyglot assert_equal "ocaml", do_detect("ocaml.ml") assert_equal "stratego", do_detect("stratego.str") assert_equal "r",do_detect("foo.R") + assert_equal "glsl", do_detect("foo.glsl") + assert_equal "glsl", do_detect("foo_glsl.vert") + assert_equal "glsl", do_detect("foo_glsl.frag") end def test_upper_case_extensions diff --git a/test/unit/glsl_test.rb b/test/unit/glsl_test.rb new file mode 100644 index 0000000..b3f4a2e --- /dev/null +++ b/test/unit/glsl_test.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class Ohcount::GLSLTest < Ohcount::Test + + def test_comments + lb = [Ohcount::LanguageBreakdown.new("glsl", "", "//comment", 0)] + assert_equal lb, Ohcount::parse(" //comment", "glsl") + end + + def test_empty_comments + lb = [Ohcount::LanguageBreakdown.new("glsl", "","//\n", 0)] + assert_equal lb, Ohcount::parse(" //\n", "glsl") + end + + + def test_block_comment + lb = [Ohcount::LanguageBreakdown.new("glsl", "","/*glsl*/", 0)] + assert_equal lb, Ohcount::parse("/*glsl*/", "glsl") + end + + def test_comprehensive + verify_parse("foo.glsl") + verify_parse("foo_glsl.vert") + end + + def test_comment_entities + assert_equal('//comment', entities_array(" //comment", 'glsl', :comment).first) + assert_equal('/*comment*/', entities_array(" /*comment*/", 'glsl', :comment).first) + end + +end From edaf2b9ceab1d36c0acce3973e9f55c327513a4f Mon Sep 17 00:00:00 2001 From: rotty Date: Sat, 8 Nov 2008 22:05:00 -0800 Subject: [PATCH 052/387] [NEW] Add .sps, .sls and .ss as filename extensions for Scheme code --- lib/ohcount/detector.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index 11a5247..8418cfd 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -208,6 +208,9 @@ def self.binary_filename?(filename) '.sc' => "scheme", '.scala' => "scala", '.scm' => "scheme", + '.sps' => "scheme", + '.sls' => "scheme", + '.ss' => "scheme", '.sh' => "shell", '.sql' => "sql", '.st' => "smalltalk", From e78d0944bd49fb847c362a763bc7d50fdc761be0 Mon Sep 17 00:00:00 2001 From: "Pascal \"Pixel\" Rigaux" Date: Thu, 23 Oct 2008 14:55:21 +0200 Subject: [PATCH 053/387] Add support for Emacs Mode header lines (#213) disambiguate_using_emacs_mode is created, it looks for "emacs variables" on the first line (also on second line when first line is sheebang #!) it is called before checking through `file ...` otherwise test tcl_script fails (reporting "shell" since "file" returns "POSIX shell script text executable") --- lib/ohcount/detector.rb | 38 +++++++++++++++++++++++++++++++++++++- test/detect_files/python.data | 24 ++++++++++++++++++++++++ test/detect_files/python2.data | 24 ++++++++++++++++++++++++ test/detect_files/tcl_script | 8 ++++++++ test/unit/detector_test.rb | 4 ++++ 5 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 test/detect_files/python.data create mode 100644 test/detect_files/python2.data create mode 100644 test/detect_files/tcl_script diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index f18a7b2..0af89e1 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -543,12 +543,18 @@ def self.disambiguate_non_visual_basic(file_context) # Attempts to determine the Polyglot for files that do not have a # filename extension. # - # Relies on the bash +file+ command line tool as its primary method. + # First it tries to find emacs mode specification (-*- .... -*-) + # Otherwise on the bash +file+ command line tool. # # There must be a file at file_context.file_location for +file+ # to operate on. # def self.disambiguate_nil(file_context) + script = self.disambiguate_using_emacs_mode(file_context) + if script + return script + end + file_location = file_context.file_location output = `file -b '#{ file_location }'` case output @@ -570,4 +576,34 @@ def self.disambiguate_nil(file_context) nil end + def self.disambiguate_using_emacs_mode(file_context) + begin + File.open(file_context.file_location) do |f| + mode = nil + first_line = f.readline + if first_line =~ /^#!/ + # read next line too + first_line += f.readline + end + case first_line + when /-\*-.*\bmode\s*:\s*([^\s;]+).*-\*-/i + mode = $1 + when /-\*-\s*(\S+)\s*-\*-/ + mode = $1 + end + if mode + remap = { + 'c++' => 'cpp', + 'caml' => 'ocaml', + } + script = remap[mode] || mode + + known_languages = EXTENSION_MAP.values + return script.downcase if known_languages.include?(script.downcase) + end + end + rescue + nil + end + end end diff --git a/test/detect_files/python.data b/test/detect_files/python.data new file mode 100644 index 0000000..aac316c --- /dev/null +++ b/test/detect_files/python.data @@ -0,0 +1,24 @@ +# -*- python -*- + +""" + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details, + which is available at www.gnu.org +""" + +import gettext +import locale + +import os, sys, time, stat + +try: + True, False +except NameError: + True, False = 1, 0 diff --git a/test/detect_files/python2.data b/test/detect_files/python2.data new file mode 100644 index 0000000..d592f8f --- /dev/null +++ b/test/detect_files/python2.data @@ -0,0 +1,24 @@ +# -*- mode: python -*- + +""" + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details, + which is available at www.gnu.org +""" + +import gettext +import locale + +import os, sys, time, stat + +try: + True, False +except NameError: + True, False = 1, 0 diff --git a/test/detect_files/tcl_script b/test/detect_files/tcl_script new file mode 100644 index 0000000..1b1edae --- /dev/null +++ b/test/detect_files/tcl_script @@ -0,0 +1,8 @@ +#!/bin/sh +# -*-Mode: TCL;-*- +# the next line restarts using wish \ +exec wish "$0" "$@" + +button .hello -text Hello \ + -command {puts stdout "Hello, World!"} +pack .hello -padx 20 -pady 10 diff --git a/test/unit/detector_test.rb b/test/unit/detector_test.rb index c917674..5fbc23b 100644 --- a/test/unit/detector_test.rb +++ b/test/unit/detector_test.rb @@ -86,6 +86,10 @@ def test_no_extensions assert_equal "shell", do_detect("bash_script", []) assert_equal "perl", do_detect("perl_w", []) assert_equal "dmd", do_detect("d_script", []) + + assert_equal "tcl", do_detect("tcl_script", []) + assert_equal "python", do_detect("python.data", []) + assert_equal "python", do_detect("python2.data", []) end def test_by_filename From 6836cf212612d5f97241189853759a639d81b6bc Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Wed, 12 Nov 2008 11:57:03 -0800 Subject: [PATCH 054/387] [FIX] Integration into ohloh --- lib/licenses/license.rb | 25 +- lib/licenses/license_map.rb | 712 ++++++++++++++++++++-------------------- lib/licenses/license_sniffer.rb | 76 ++--- lib/ohcount.rb | 2 +- lib/ohcount/scratch_dir.rb | 98 +++--- lib/ohcount/source_file.rb | 5 +- 6 files changed, 462 insertions(+), 456 deletions(-) diff --git a/lib/licenses/license.rb b/lib/licenses/license.rb index 5db282e..07abd86 100644 --- a/lib/licenses/license.rb +++ b/lib/licenses/license.rb @@ -1,14 +1,15 @@ -module LicenseSniffer - class SoftwareLicense - attr_reader :symbol, :url, :nice_name, :re, :exclude +module Ohcount + module LicenseSniffer + class SoftwareLicense + attr_reader :symbol, :url, :nice_name, :re, :exclude - def initialize(symbol, url, nice_name, re, exclude = nil) - @symbol = symbol - @url = url - @nice_name = nice_name - @re = re - @exclude = exclude - end - end + def initialize(symbol, url, nice_name, re, exclude = nil) + @symbol = symbol + @url = url + @nice_name = nice_name + @re = re + @exclude = exclude + end + end + end end - diff --git a/lib/licenses/license_map.rb b/lib/licenses/license_map.rb index d1e5d24..e8bf5a8 100644 --- a/lib/licenses/license_map.rb +++ b/lib/licenses/license_map.rb @@ -1,359 +1,361 @@ require File.dirname(__FILE__) + '/license' require 'singleton' -module LicenseSniffer - class LicenseMap - include Singleton - - attr_reader :map, :licenses, :license_overrides - - def initialize() - @map = {} - @licenses = [] - - [ - SoftwareLicense.new(:academic, - "http://www.opensource.org/licenses/afl-3.0.php", - "Academic Free License", - /\bAcademic\s*Free\s*License\b/i ), - - SoftwareLicense.new(:adaptive, - "http://www.opensource.org/licenses/apl1.0.php", - "Adaptive Public License", - /\bAdaptive\s*Public\s*License\b/i ), - - SoftwareLicense.new(:affero, - "http://www.affero.org/oagpl.html", - "GNU Affero General Public License", - /\bGNU\s+Affero\s+General\s+Public\s+License\b/i ), - - SoftwareLicense.new(:apache, - "http://www.opensource.org/licenses/apachepl.php", - "Apache Software License", - /(\bApache\s*Software\s*License(?![\s,]*2))|(\bapache\s*license(?![\s,]*2))/i ), - - SoftwareLicense.new(:apache_2, - "http://www.opensource.org/licenses/apache2.0.php", - "Apache License, 2.0", - /\bapache\s+(software\s+)?license,?\s+(version\s+)?2/i ), - - SoftwareLicense.new(:apple_open_source, - "http://www.opensource.org/licenses/apsl-2.0.php", - "Apple Public Source License", - /\bApple\s*Public\s*Source\s*License\b/i ), - - SoftwareLicense.new(:artistic, - "http://www.opensource.org/licenses/artistic-license.php", - "Artistic license", - /\bartistic\s*license\b/i ), - - SoftwareLicense.new(:attribution_assurance, - "http://www.opensource.org/licenses/attribution.php", - "Attribution Assurance Licenses", - /\battribution\s*assurance\s*license(s)?\b/i ), - - SoftwareLicense.new(:bsd, - "http://www.opensource.org/licenses/bsd-license.php", - "New BSD license", - /(\bbsd\s*license\b)|(The Regents of the University of California)/i ), - - SoftwareLicense.new(:computer_associates_trusted, - "http://www.opensource.org/licenses/ca-tosl1.1.php", - "Computer Associates Trusted Open Source License 1.1", - /\bcomputer\s*associates\s*trusted\s*open\s*source\s*license\b/i ), - - SoftwareLicense.new(:common_development_and_distribution, - "http://www.opensource.org/licenses/cddl1.php", - "Common Development and Distribution License", - /\bcommon\s*development\s*and\s*distribution\s*license\b/i ), - - SoftwareLicense.new(:common_public, - "http://www.opensource.org/licenses/cpl1.0.php", - "Common Public License 1.0", - /\bcommon\s*public\s*license\b/i ), - - SoftwareLicense.new(:cua_office, - "http://www.opensource.org/licenses/cuaoffice.php", - "CUA Office Public License Version 1.0", - /\bCUA\s*office\s*public\s*license\b/i ), - - SoftwareLicense.new(:eu_datagrid, - "http://www.opensource.org/licenses/eudatagrid.php", - "EU DataGrid Software License", - /\beu\s*datagrid\s*software\s*license\b/i ), - - SoftwareLicense.new(:eclipse, - "http://www.opensource.org/licenses/eclipse-1.0.php", - "Eclipse Public License", - /\beclipse\s*public\s*license\b/i ), - - SoftwareLicense.new(:educational, - "http://www.opensource.org/licenses/ecl1.php", - "Educational Community License", - /\beducational\s*community\s*license\b/i ), - - SoftwareLicense.new(:eiffel, - "http://www.opensource.org/licenses/eiffel.php", - "Eiffel Forum License", - /\beiffel\s*forum\s*license(?![,V\s]*2)\b/i ), - - SoftwareLicense.new(:eiffel_2, - "http://www.opensource.org/licenses/ver2_eiffel.php", - "Eiffel Forum License V2.0", - /\beiffel\s*forum\s*license [,V\s]*2/i ), - - SoftwareLicense.new(:entessa, - "http://www.opensource.org/licenses/entessa.php", - "Entessa Public License", - /\bentessa\s*public\s*license\b/i ), - - SoftwareLicense.new(:fair, - "http://www.opensource.org/licenses/fair.php", - "Fair License", - /\bfair\s*license\b/i ), - - SoftwareLicense.new(:frameworx, - "http://www.opensource.org/licenses/frameworx.php", - "Frameworx License", - /\bframeworx\s*license\b/i ), - - SoftwareLicense.new(:gpl3_or_later, - "http://www.gnu.org/licenses/gpl-3.0.html", - "GNU General Public License 3.0", - /\b(GNU GENERAL PUBLIC LICENSE|GPL).{0,100}(Version)? 3.{0,50}later/im), - - SoftwareLicense.new(:gpl3, - "http://www.gnu.org/licenses/gpl-3.0.html", - "GNU General Public License 3.0", - /GNU (GENERAL PUBLIC LICENSE|GPL).{0,100}(Version |v)3/im, - /((at your option) any later version)|(GENERAL PUBLIC LICENSE.*GENERAL PUBLIC LICENSE)/i), - - SoftwareLicense.new(:lgpl3, - "http://www.gnu.org/licenses/lgpl-3.0.html", - "GNU Lesser General Public License 3.0", - /((\blgpl\b)|(\bgnu\s*(library|lesser)\s*(general\s*)?(public\s*)?license\b)|(\b(lesser|library)\s*gpl\b)).{0,10}(\bas published by the free software foundation\b)?.{0,10}(\bversion\b)?.{0,10}\b3(\.0)?\b/i ), - - SoftwareLicense.new(:gpl, - "http://www.opensource.org/licenses/gpl-license.php", - "GNU General Public License (GPL)", - /(\bgpl\b)|(\bgplv2\b)|(\bgnu\s*general\s*public\s*license\b)|(\bwww\.gnu\.org\/licenses\/gpl\.txt\b)/i ), - - SoftwareLicense.new(:lgpl, - "http://www.opensource.org/licenses/lgpl-license.php", - "GNU Library or \"Lesser\" GPL (LGPL)", - /(\blgpl\b)|(\bgnu\s*(library|lesser)\s*(general\s*)?(public\s*)?license\b)|(\b(lesser|library)\s*gpl\b)/i ), - - SoftwareLicense.new(:historical, - "http://www.opensource.org/licenses/historical.php", - "Historical Permission Notice and Disclaimer", - /\bhistorical\s*permission\s*notice\s*and\s*disclaimer\b/i ), - - SoftwareLicense.new(:ibm_public, - "http://www.opensource.org/licenses/ibmpl.php", - "IBM Public License", - /\bibm\s*public\s*license\b/i ), - - SoftwareLicense.new(:intel_open_source, - "http://www.opensource.org/licenses/intel-open-source-license.php", - "Intel Open Source License", - /\bintel\s*open\s*source\s*license\b/i ), - - SoftwareLicense.new(:jabber_open_source, - "http://www.opensource.org/licenses/jabberpl.php", - "Jabber Open Source License", - /\bjabber\s*open\s*source\s*license\b/i ), - - SoftwareLicense.new(:lucent_plan9, - "http://www.opensource.org/licenses/plan9.php", - "Lucent Public License (Plan9)", - /\blucent\s*public\s*license[\s(]*plan9/i ), - - SoftwareLicense.new(:lucent_public, - "http://www.opensource.org/licenses/lucent1.02.php", - "Lucent Public License Version 1.02", - /\blucent\s*public\s*license\s*(version)?\s+1/i ), - - SoftwareLicense.new(:mit, - "http://www.opensource.org/licenses/mit-license.php", - "MIT license", - /(\bmit\s*license\b)|(\bMIT\/X11\s*license\b)/i ), - - SoftwareLicense.new(:mitre, - "http://www.opensource.org/licenses/mitrepl.php", - "MITRE Collaborative Virtual Workspace License (CVW License)", - /\bmitre\s*collaborative\s*virtual\s*workspace\s*license\b/i ), - - SoftwareLicense.new(:motosoto, - "http://www.opensource.org/licenses/motosoto.php", - "Motosoto License", - /\bmotosoto\s*license\b/i ), - - SoftwareLicense.new(:mozilla_public_1, - "http://www.opensource.org/licenses/mozilla1.0.php", - "Mozilla Public License 1.0 (MPL)", - /\bmozilla\s*public\s*license\b/i ), - - SoftwareLicense.new(:mozilla_public_1_1, - "http://www.opensource.org/licenses/mozilla1.1.php", - "Mozilla Public License 1.1 (MPL)", - /\bmozilla\s*public\s*license 1\.1\b/i ), - - SoftwareLicense.new(:nasa_open, - "http://www.opensource.org/licenses/nasa1.3.php", - "NASA Open Source Agreement 1.3", - /\bnasa\s*open\s*source\s*agreement\b/i ), - - SoftwareLicense.new(:naumen, - "http://www.opensource.org/licenses/naumen.php", - "Naumen Public License", - /\bnaumen\s*public\s*license\b/i ), - - SoftwareLicense.new(:nethack, - "http://www.opensource.org/licenses/nethack.php", - "Nethack General Public License", - /\bnethack\s*general\s*public\s*license\b/i ), - - SoftwareLicense.new(:nokia_open_source, - "http://www.opensource.org/licenses/nokia.php", - "Nokia Open Source License", - /\bnokia\s*open\s*source\s*license\b/i ), - - SoftwareLicense.new(:oclc_research, - "http://www.opensource.org/licenses/oclc2.php", - "OCLC Research Public License 2.0", - /\boclc\s*research\s*public\s*license\b/i ), - - SoftwareLicense.new(:open_group_test, - "http://www.opensource.org/licenses/opengroup.php", - "Open Group Test Suite License", - /\bopen\s*group\s*test\s*suite\s*license\b/i ), - - SoftwareLicense.new(:open_software, - "http://www.opensource.org/licenses/osl-3.0.php", - "Open Software License", - /\bopen\s*software\s*license\b/i ), - - SoftwareLicense.new(:php_license, - "http://www.opensource.org/licenses/php.php", - "PHP License", - /\bphp\s*license\b/i ), - - SoftwareLicense.new(:python_license, - "http://www.opensource.org/licenses/pythonpl.php", - "Python license", - /\bpython\s*license\b/i ), - - SoftwareLicense.new(:python_software_foundation, - "http://www.opensource.org/licenses/PythonSoftFoundation.php", - "Python Software Foundation License", - /\bpython\s*software\s*foundation\s*license\b/i ), - - SoftwareLicense.new(:qt_public, - "http://www.opensource.org/licenses/qtpl.php", - "Qt Public License (QPL)", - /\bqt\s*public\s*license\b/i ), - - SoftwareLicense.new(:realnetworks_public_source, - "http://www.opensource.org/licenses/real.php", - "RealNetworks Public Source License V1.0", - /\brealnetworks\s*public\s*source\s*license\b/i ), - - SoftwareLicense.new(:reciprocal_public, - "http://www.opensource.org/licenses/rpl.php", - "Reciprocal Public License", - /\breciprocal\s*public\s*license\b/i ), - - SoftwareLicense.new(:ricoh_source, - "http://www.opensource.org/licenses/ricohpl.php", - "Ricoh Source Code Public License", - /\bricoh\s*source\s*code\s*public\s*license\b/i ), - - SoftwareLicense.new(:sleepycat, - "http://www.opensource.org/licenses/sleepycat.php", - "Sleepycat License", - /\bsleepycat\s*license\b/i ), - - SoftwareLicense.new(:sugarcrm_1_1_3, - "http://www.sugarcrm.com/SPL", - "SugarCRM Public License 1.1.3", - /\bsugar\s*public\s*license\s*version\s*1\.1\.3\b/i ), - - SoftwareLicense.new(:sun_industry_standards, - "http://www.opensource.org/licenses/sisslpl.php", - "Sun Industry Standards Source License (SISSL)", - /\bsun\s*industry\s*standards\s*source\s*license\b/i ), - - SoftwareLicense.new(:sun_public, - "http://www.opensource.org/licenses/sunpublic.php", - "Sun Public License", - /\bsun\s*public\s*license\b/i ), - - SoftwareLicense.new(:sybase_open_watcom, - "http://www.opensource.org/licenses/sybase.php", - "Sybase Open Watcom Public License 1.0", - /\bsybase\s*open\s*watcom\s*public\s*license\b/i ), - - SoftwareLicense.new(:u_of_i_ncsa, - "http://www.opensource.org/licenses/UoI-NCSA.php", - "University of Illinois/NCSA Open Source License", - /\buniversity\s*of\s*illinois\/ncsa\s*open\s*source\s*license\b/i ), - - SoftwareLicense.new(:vovida_software, - "http://www.opensource.org/licenses/vovidapl.php", - "Vovida Software License v. 1.0", - /\bvovida\s*software\s*license\b/i ), - - SoftwareLicense.new(:w3c, - "http://www.opensource.org/licenses/W3C.php", - "W3C License", - /\bw3c\s*license\b/i ), - - SoftwareLicense.new(:wx_windows, - "http://www.opensource.org/licenses/wxwindows.php", - "wxWindows Library License", - /\bwxwindows\s*library\s*license\b/i ), - - SoftwareLicense.new(:x_net, - "http://www.opensource.org/licenses/xnet.php", - "X.Net License", - /\bx\.net\s*license\b/i ), - - SoftwareLicense.new(:zope, - "http://www.opensource.org/licenses/zpl.php", - "Zope Public License", - /\bzope\s*public\s*license\b/i ), - - SoftwareLicense.new(:zlib_libpng, - "http://www.opensource.org/licenses/zlib-license.php", - "zlib/libpng license", - /\bzlib\/libpng\s*license\b/i ), - - SoftwareLicense.new(:apache_ish, - "", - "Apache-ish License", - /(\bapache-style.*license\b)|(\bapache-like.*license\b)/i ), - - SoftwareLicense.new(:bsd_ish, - "", - "BSD-ish License", - /Copyright\s.{1,40}All rights reserved.{0,40}Redistribution and use in source and binary forms, with or without.{0,20}modification, are permitted provided that the following conditions.{0,20}\sare met.{1,40}Redistributions of source code must retain the above copyright\s.*notice, this list of conditions and the following disclaimer\.\s+.*Redistributions in binary form must reproduce the above.*copyright\s+.{0,10}notice, this list of conditions and the following.*disclaimer in the\s+.*documentation.*(The (name|names) of the (author|contributors) may not|Neither the name of the).*be used to endorse or promote\s+.*products\s+.*derived\s+.*from this software without specific prior written\s+.*permission.*HOWEVER\s+.*CAUSED AND ON ANY.*THEORY OF LIABILITY, WHETHER IN CONTRACT/m, - /The Regents of the University of California/), - - SoftwareLicense.new(:bsd_2clause_ish, - "", - "BSD-ish (2 clause) License", - /Copyright\s.{1,60}All rights reserved.{1,40}Redistribution and use in source and binary forms, with or without.{0,20}modification, are permitted provided that the following conditions.{0,20}\sare met.{0,20}\s{1,20}.{0,20}Redistributions of source code must retain the above copyright\s+.*notice, this list of conditions and the following disclaimer.\s+.*Redistributions in binary form must reproduce the above copyright\s+.*notice, this list of conditions and the following disclaimer in the\s+.*documentation and\/or other materials provided with the distribution\.\s+.*HOWEVER CAUSED AND ON ANY.*THEORY OF LIABILITY, WHETHER IN CONTRACT/m, - /(The Regents of the University of California)|(may not be used to endorse or promote\s+.*products\s+.*prior\s+.*written\s+.*permission\.)/m), - ].each do |l| - @licenses << l - @map[l.symbol] = l - end - # gpl3 is more specific than gpl, so only include gpl3. Be careful -- we don't want to miss cases that are conflicts - @license_overrides = { - :gpl => [ :gpl3, :gpl3_or_later], - :gpl3 => [ :gpl3_or_later], - :bsd_ish => [:bsd_2clause_ish] - } - end - end +module Ohcount + module LicenseSniffer + class LicenseMap + include Singleton + + attr_reader :map, :licenses, :license_overrides + + def initialize() + @map = {} + @licenses = [] + + [ + SoftwareLicense.new(:academic, + "http://www.opensource.org/licenses/afl-3.0.php", + "Academic Free License", + /\bAcademic\s*Free\s*License\b/i ), + + SoftwareLicense.new(:adaptive, + "http://www.opensource.org/licenses/apl1.0.php", + "Adaptive Public License", + /\bAdaptive\s*Public\s*License\b/i ), + + SoftwareLicense.new(:affero, + "http://www.affero.org/oagpl.html", + "GNU Affero General Public License", + /\bGNU\s+Affero\s+General\s+Public\s+License\b/i ), + + SoftwareLicense.new(:apache, + "http://www.opensource.org/licenses/apachepl.php", + "Apache Software License", + /(\bApache\s*Software\s*License(?![\s,]*2))|(\bapache\s*license(?![\s,]*2))/i ), + + SoftwareLicense.new(:apache_2, + "http://www.opensource.org/licenses/apache2.0.php", + "Apache License, 2.0", + /\bapache\s+(software\s+)?license,?\s+(version\s+)?2/i ), + + SoftwareLicense.new(:apple_open_source, + "http://www.opensource.org/licenses/apsl-2.0.php", + "Apple Public Source License", + /\bApple\s*Public\s*Source\s*License\b/i ), + + SoftwareLicense.new(:artistic, + "http://www.opensource.org/licenses/artistic-license.php", + "Artistic license", + /\bartistic\s*license\b/i ), + + SoftwareLicense.new(:attribution_assurance, + "http://www.opensource.org/licenses/attribution.php", + "Attribution Assurance Licenses", + /\battribution\s*assurance\s*license(s)?\b/i ), + + SoftwareLicense.new(:bsd, + "http://www.opensource.org/licenses/bsd-license.php", + "New BSD license", + /(\bbsd\s*license\b)|(The Regents of the University of California)/i ), + + SoftwareLicense.new(:computer_associates_trusted, + "http://www.opensource.org/licenses/ca-tosl1.1.php", + "Computer Associates Trusted Open Source License 1.1", + /\bcomputer\s*associates\s*trusted\s*open\s*source\s*license\b/i ), + + SoftwareLicense.new(:common_development_and_distribution, + "http://www.opensource.org/licenses/cddl1.php", + "Common Development and Distribution License", + /\bcommon\s*development\s*and\s*distribution\s*license\b/i ), + + SoftwareLicense.new(:common_public, + "http://www.opensource.org/licenses/cpl1.0.php", + "Common Public License 1.0", + /\bcommon\s*public\s*license\b/i ), + + SoftwareLicense.new(:cua_office, + "http://www.opensource.org/licenses/cuaoffice.php", + "CUA Office Public License Version 1.0", + /\bCUA\s*office\s*public\s*license\b/i ), + + SoftwareLicense.new(:eu_datagrid, + "http://www.opensource.org/licenses/eudatagrid.php", + "EU DataGrid Software License", + /\beu\s*datagrid\s*software\s*license\b/i ), + + SoftwareLicense.new(:eclipse, + "http://www.opensource.org/licenses/eclipse-1.0.php", + "Eclipse Public License", + /\beclipse\s*public\s*license\b/i ), + + SoftwareLicense.new(:educational, + "http://www.opensource.org/licenses/ecl1.php", + "Educational Community License", + /\beducational\s*community\s*license\b/i ), + + SoftwareLicense.new(:eiffel, + "http://www.opensource.org/licenses/eiffel.php", + "Eiffel Forum License", + /\beiffel\s*forum\s*license(?![,V\s]*2)\b/i ), + + SoftwareLicense.new(:eiffel_2, + "http://www.opensource.org/licenses/ver2_eiffel.php", + "Eiffel Forum License V2.0", + /\beiffel\s*forum\s*license [,V\s]*2/i ), + + SoftwareLicense.new(:entessa, + "http://www.opensource.org/licenses/entessa.php", + "Entessa Public License", + /\bentessa\s*public\s*license\b/i ), + + SoftwareLicense.new(:fair, + "http://www.opensource.org/licenses/fair.php", + "Fair License", + /\bfair\s*license\b/i ), + + SoftwareLicense.new(:frameworx, + "http://www.opensource.org/licenses/frameworx.php", + "Frameworx License", + /\bframeworx\s*license\b/i ), + + SoftwareLicense.new(:gpl3_or_later, + "http://www.gnu.org/licenses/gpl-3.0.html", + "GNU General Public License 3.0", + /\b(GNU GENERAL PUBLIC LICENSE|GPL).{0,100}(Version)? 3.{0,50}later/im), + + SoftwareLicense.new(:gpl3, + "http://www.gnu.org/licenses/gpl-3.0.html", + "GNU General Public License 3.0", + /GNU (GENERAL PUBLIC LICENSE|GPL).{0,100}(Version |v)3/im, + /((at your option) any later version)|(GENERAL PUBLIC LICENSE.*GENERAL PUBLIC LICENSE)/i), + + SoftwareLicense.new(:lgpl3, + "http://www.gnu.org/licenses/lgpl-3.0.html", + "GNU Lesser General Public License 3.0", + /((\blgpl\b)|(\bgnu\s*(library|lesser)\s*(general\s*)?(public\s*)?license\b)|(\b(lesser|library)\s*gpl\b)).{0,10}(\bas published by the free software foundation\b)?.{0,10}(\bversion\b)?.{0,10}\b3(\.0)?\b/i ), + + SoftwareLicense.new(:gpl, + "http://www.opensource.org/licenses/gpl-license.php", + "GNU General Public License (GPL)", + /(\bgpl\b)|(\bgplv2\b)|(\bgnu\s*general\s*public\s*license\b)|(\bwww\.gnu\.org\/licenses\/gpl\.txt\b)/i ), + + SoftwareLicense.new(:lgpl, + "http://www.opensource.org/licenses/lgpl-license.php", + "GNU Library or \"Lesser\" GPL (LGPL)", + /(\blgpl\b)|(\bgnu\s*(library|lesser)\s*(general\s*)?(public\s*)?license\b)|(\b(lesser|library)\s*gpl\b)/i ), + + SoftwareLicense.new(:historical, + "http://www.opensource.org/licenses/historical.php", + "Historical Permission Notice and Disclaimer", + /\bhistorical\s*permission\s*notice\s*and\s*disclaimer\b/i ), + + SoftwareLicense.new(:ibm_public, + "http://www.opensource.org/licenses/ibmpl.php", + "IBM Public License", + /\bibm\s*public\s*license\b/i ), + + SoftwareLicense.new(:intel_open_source, + "http://www.opensource.org/licenses/intel-open-source-license.php", + "Intel Open Source License", + /\bintel\s*open\s*source\s*license\b/i ), + + SoftwareLicense.new(:jabber_open_source, + "http://www.opensource.org/licenses/jabberpl.php", + "Jabber Open Source License", + /\bjabber\s*open\s*source\s*license\b/i ), + + SoftwareLicense.new(:lucent_plan9, + "http://www.opensource.org/licenses/plan9.php", + "Lucent Public License (Plan9)", + /\blucent\s*public\s*license[\s(]*plan9/i ), + + SoftwareLicense.new(:lucent_public, + "http://www.opensource.org/licenses/lucent1.02.php", + "Lucent Public License Version 1.02", + /\blucent\s*public\s*license\s*(version)?\s+1/i ), + + SoftwareLicense.new(:mit, + "http://www.opensource.org/licenses/mit-license.php", + "MIT license", + /(\bmit\s*license\b)|(\bMIT\/X11\s*license\b)/i ), + + SoftwareLicense.new(:mitre, + "http://www.opensource.org/licenses/mitrepl.php", + "MITRE Collaborative Virtual Workspace License (CVW License)", + /\bmitre\s*collaborative\s*virtual\s*workspace\s*license\b/i ), + + SoftwareLicense.new(:motosoto, + "http://www.opensource.org/licenses/motosoto.php", + "Motosoto License", + /\bmotosoto\s*license\b/i ), + + SoftwareLicense.new(:mozilla_public_1, + "http://www.opensource.org/licenses/mozilla1.0.php", + "Mozilla Public License 1.0 (MPL)", + /\bmozilla\s*public\s*license\b/i ), + + SoftwareLicense.new(:mozilla_public_1_1, + "http://www.opensource.org/licenses/mozilla1.1.php", + "Mozilla Public License 1.1 (MPL)", + /\bmozilla\s*public\s*license 1\.1\b/i ), + + SoftwareLicense.new(:nasa_open, + "http://www.opensource.org/licenses/nasa1.3.php", + "NASA Open Source Agreement 1.3", + /\bnasa\s*open\s*source\s*agreement\b/i ), + + SoftwareLicense.new(:naumen, + "http://www.opensource.org/licenses/naumen.php", + "Naumen Public License", + /\bnaumen\s*public\s*license\b/i ), + + SoftwareLicense.new(:nethack, + "http://www.opensource.org/licenses/nethack.php", + "Nethack General Public License", + /\bnethack\s*general\s*public\s*license\b/i ), + + SoftwareLicense.new(:nokia_open_source, + "http://www.opensource.org/licenses/nokia.php", + "Nokia Open Source License", + /\bnokia\s*open\s*source\s*license\b/i ), + + SoftwareLicense.new(:oclc_research, + "http://www.opensource.org/licenses/oclc2.php", + "OCLC Research Public License 2.0", + /\boclc\s*research\s*public\s*license\b/i ), + + SoftwareLicense.new(:open_group_test, + "http://www.opensource.org/licenses/opengroup.php", + "Open Group Test Suite License", + /\bopen\s*group\s*test\s*suite\s*license\b/i ), + + SoftwareLicense.new(:open_software, + "http://www.opensource.org/licenses/osl-3.0.php", + "Open Software License", + /\bopen\s*software\s*license\b/i ), + + SoftwareLicense.new(:php_license, + "http://www.opensource.org/licenses/php.php", + "PHP License", + /\bphp\s*license\b/i ), + + SoftwareLicense.new(:python_license, + "http://www.opensource.org/licenses/pythonpl.php", + "Python license", + /\bpython\s*license\b/i ), + + SoftwareLicense.new(:python_software_foundation, + "http://www.opensource.org/licenses/PythonSoftFoundation.php", + "Python Software Foundation License", + /\bpython\s*software\s*foundation\s*license\b/i ), + + SoftwareLicense.new(:qt_public, + "http://www.opensource.org/licenses/qtpl.php", + "Qt Public License (QPL)", + /\bqt\s*public\s*license\b/i ), + + SoftwareLicense.new(:realnetworks_public_source, + "http://www.opensource.org/licenses/real.php", + "RealNetworks Public Source License V1.0", + /\brealnetworks\s*public\s*source\s*license\b/i ), + + SoftwareLicense.new(:reciprocal_public, + "http://www.opensource.org/licenses/rpl.php", + "Reciprocal Public License", + /\breciprocal\s*public\s*license\b/i ), + + SoftwareLicense.new(:ricoh_source, + "http://www.opensource.org/licenses/ricohpl.php", + "Ricoh Source Code Public License", + /\bricoh\s*source\s*code\s*public\s*license\b/i ), + + SoftwareLicense.new(:sleepycat, + "http://www.opensource.org/licenses/sleepycat.php", + "Sleepycat License", + /\bsleepycat\s*license\b/i ), + + SoftwareLicense.new(:sugarcrm_1_1_3, + "http://www.sugarcrm.com/SPL", + "SugarCRM Public License 1.1.3", + /\bsugar\s*public\s*license\s*version\s*1\.1\.3\b/i ), + + SoftwareLicense.new(:sun_industry_standards, + "http://www.opensource.org/licenses/sisslpl.php", + "Sun Industry Standards Source License (SISSL)", + /\bsun\s*industry\s*standards\s*source\s*license\b/i ), + + SoftwareLicense.new(:sun_public, + "http://www.opensource.org/licenses/sunpublic.php", + "Sun Public License", + /\bsun\s*public\s*license\b/i ), + + SoftwareLicense.new(:sybase_open_watcom, + "http://www.opensource.org/licenses/sybase.php", + "Sybase Open Watcom Public License 1.0", + /\bsybase\s*open\s*watcom\s*public\s*license\b/i ), + + SoftwareLicense.new(:u_of_i_ncsa, + "http://www.opensource.org/licenses/UoI-NCSA.php", + "University of Illinois/NCSA Open Source License", + /\buniversity\s*of\s*illinois\/ncsa\s*open\s*source\s*license\b/i ), + + SoftwareLicense.new(:vovida_software, + "http://www.opensource.org/licenses/vovidapl.php", + "Vovida Software License v. 1.0", + /\bvovida\s*software\s*license\b/i ), + + SoftwareLicense.new(:w3c, + "http://www.opensource.org/licenses/W3C.php", + "W3C License", + /\bw3c\s*license\b/i ), + + SoftwareLicense.new(:wx_windows, + "http://www.opensource.org/licenses/wxwindows.php", + "wxWindows Library License", + /\bwxwindows\s*library\s*license\b/i ), + + SoftwareLicense.new(:x_net, + "http://www.opensource.org/licenses/xnet.php", + "X.Net License", + /\bx\.net\s*license\b/i ), + + SoftwareLicense.new(:zope, + "http://www.opensource.org/licenses/zpl.php", + "Zope Public License", + /\bzope\s*public\s*license\b/i ), + + SoftwareLicense.new(:zlib_libpng, + "http://www.opensource.org/licenses/zlib-license.php", + "zlib/libpng license", + /\bzlib\/libpng\s*license\b/i ), + + SoftwareLicense.new(:apache_ish, + "", + "Apache-ish License", + /(\bapache-style.*license\b)|(\bapache-like.*license\b)/i ), + + SoftwareLicense.new(:bsd_ish, + "", + "BSD-ish License", + /Copyright\s.{1,40}All rights reserved.{0,40}Redistribution and use in source and binary forms, with or without.{0,20}modification, are permitted provided that the following conditions.{0,20}\sare met.{1,40}Redistributions of source code must retain the above copyright\s.*notice, this list of conditions and the following disclaimer\.\s+.*Redistributions in binary form must reproduce the above.*copyright\s+.{0,10}notice, this list of conditions and the following.*disclaimer in the\s+.*documentation.*(The (name|names) of the (author|contributors) may not|Neither the name of the).*be used to endorse or promote\s+.*products\s+.*derived\s+.*from this software without specific prior written\s+.*permission.*HOWEVER\s+.*CAUSED AND ON ANY.*THEORY OF LIABILITY, WHETHER IN CONTRACT/m, + /The Regents of the University of California/), + + SoftwareLicense.new(:bsd_2clause_ish, + "", + "BSD-ish (2 clause) License", + /Copyright\s.{1,60}All rights reserved.{1,40}Redistribution and use in source and binary forms, with or without.{0,20}modification, are permitted provided that the following conditions.{0,20}\sare met.{0,20}\s{1,20}.{0,20}Redistributions of source code must retain the above copyright\s+.*notice, this list of conditions and the following disclaimer.\s+.*Redistributions in binary form must reproduce the above copyright\s+.*notice, this list of conditions and the following disclaimer in the\s+.*documentation and\/or other materials provided with the distribution\.\s+.*HOWEVER CAUSED AND ON ANY.*THEORY OF LIABILITY, WHETHER IN CONTRACT/m, + /(The Regents of the University of California)|(may not be used to endorse or promote\s+.*products\s+.*prior\s+.*written\s+.*permission\.)/m), + ].each do |l| + @licenses << l + @map[l.symbol] = l + end + # gpl3 is more specific than gpl, so only include gpl3. Be careful -- we don't want to miss cases that are conflicts + @license_overrides = { + :gpl => [ :gpl3, :gpl3_or_later], + :gpl3 => [ :gpl3_or_later], + :bsd_ish => [:bsd_2clause_ish] + } + end + end +end end diff --git a/lib/licenses/license_sniffer.rb b/lib/licenses/license_sniffer.rb index 78ea0ac..6f860ab 100644 --- a/lib/licenses/license_sniffer.rb +++ b/lib/licenses/license_sniffer.rb @@ -9,45 +9,47 @@ # ...i find the GNU Public License really dumb... # # Otherwise, it strives to be complete...add any new licenses to the license map. -module LicenseSniffer +module Ohcount + module LicenseSniffer - def self.sniff(s) - ranges = [] - # Check each license for a match. With each matching license, store its first and last character index. - LicenseMap.instance.licenses.each do |l| - m0 = ( s =~ l.re) # m0 = match start character - m1 = m0 + $&.length if m0 # m1, first character after end of match + def self.sniff(s) + ranges = [] + # Check each license for a match. With each matching license, store its first and last character index. + LicenseMap.instance.licenses.each do |l| + m0 = ( s =~ l.re) # m0 = match start character + m1 = m0 + $&.length if m0 # m1, first character after end of match - # exclude terms that may not be exist in the license, useful distinguishing between BSD licenses - if m0 - match = s[m0...m1] - m0 = nil if l.exclude && match =~ l.exclude - end + # exclude terms that may not be exist in the license, useful distinguishing between BSD licenses + if m0 + match = s[m0...m1] + m0 = nil if l.exclude && match =~ l.exclude + end - if m0 - ranges << [l.symbol, m0, m1] - end - end - # Remove any match whose range is contained completely within another license's range. - # This prevents matching the same string to two different licenses, such as "Lesser GPL" and "GPL". - ranges.each do |r1| - ranges.each do |r2| - # This comparison is a little complex because we want to catch the two edge cases in which - # the first letter or the last letter are shared, but we don't want to catch the case - # in which both the first AND last letter are shared, which would mean they are exactly the same range. - if (r1[1] < r2[1] and r1[2] >= r2[2]) or (r1[1] <= r2[1] and r1[2] > r2[2]) - # r2 lies completely completely within r1, so ignore it - r2[0] = nil # mark as nil instead of deleting to avoid breaking the iterators - end - end - end - LicenseMap.instance.license_overrides.each_pair do |base, specific| - found_licenses = ranges.collect {|r| r.first} - if !(found_licenses & specific).empty? - ranges.delete_if { |r| r.first == base} - end - end - ranges.collect { |r| r[0] }.compact.uniq - end + if m0 + ranges << [l.symbol, m0, m1] + end + end + # Remove any match whose range is contained completely within another license's range. + # This prevents matching the same string to two different licenses, such as "Lesser GPL" and "GPL". + ranges.each do |r1| + ranges.each do |r2| + # This comparison is a little complex because we want to catch the two edge cases in which + # the first letter or the last letter are shared, but we don't want to catch the case + # in which both the first AND last letter are shared, which would mean they are exactly the same range. + if (r1[1] < r2[1] and r1[2] >= r2[2]) or (r1[1] <= r2[1] and r1[2] > r2[2]) + # r2 lies completely completely within r1, so ignore it + r2[0] = nil # mark as nil instead of deleting to avoid breaking the iterators + end + end + end + LicenseMap.instance.license_overrides.each_pair do |base, specific| + found_licenses = ranges.collect {|r| r.first} + if !(found_licenses & specific).empty? + ranges.delete_if { |r| r.first == base} + end + end + ranges.collect { |r| r[0] }.compact.uniq + end + end end diff --git a/lib/ohcount.rb b/lib/ohcount.rb index 1535dfb..c5aed60 100644 --- a/lib/ohcount.rb +++ b/lib/ohcount.rb @@ -12,11 +12,11 @@ module Ohcount require "lib/#{Config::CONFIG['arch']}/ohcount_native" end +require "lib/ohcount/scratch_dir" require "lib/ohcount/helpers" require "lib/ohcount/detector" require "lib/ohcount/language_breakdown" require "lib/ohcount/sloc_info" -require "lib/ohcount/scratch_dir" require "lib/ohcount/source_file" require "lib/ohcount/language_facts" require "lib/ohcount/gestalt_facts" diff --git a/lib/ohcount/scratch_dir.rb b/lib/ohcount/scratch_dir.rb index c8050cb..8a18318 100644 --- a/lib/ohcount/scratch_dir.rb +++ b/lib/ohcount/scratch_dir.rb @@ -1,57 +1,59 @@ require 'fileutils' # A utility class to manage the creation and automatic cleanup of temporary directories. -class ScratchDir - attr_reader :path +module Ohcount + class ScratchDir + attr_reader :path - # Creates a uniquely named directory in the system tmp directory. - # - # If a block is passed to the constructor, the path to the created directory - # will be yielded to the block. The directory will then be deleted - # when this block returns. - # - # Sample usage: - # - # ScratchDir.new do |path| - # # Do some work in the new directory - # File.new( path + '/foobaz', 'w' ) do - # # ... - # end - # end # Scratch directory is deleted here - # - def initialize - @path = `mktemp -d /tmp/ohcount_XXXXX`.strip - if block_given? - begin - return yield @path - ensure - FileUtils.rm_rf(@path) - end - end - end -end + # Creates a uniquely named directory in the system tmp directory. + # + # If a block is passed to the constructor, the path to the created directory + # will be yielded to the block. The directory will then be deleted + # when this block returns. + # + # Sample usage: + # + # ScratchDir.new do |path| + # # Do some work in the new directory + # File.new( path + '/foobaz', 'w' ) do + # # ... + # end + # end # Scratch directory is deleted here + # + def initialize + @path = `mktemp -d /tmp/ohcount_XXXXX`.strip + if block_given? + begin + return yield(@path) + ensure + FileUtils.rm_rf(@path) + end + end + end + end -if $0 == __FILE__ - path = nil + if $0 == __FILE__ + path = nil - ScratchDir.new do |d| - path = d - filename = File.join(d,"test") - File.open(filename, "w") do |io| - io.write "test" - end - end - raise RuntimeError.new("Directory wasn't cleaned up") if FileTest.directory?(path) + ScratchDir.new do |d| + path = d + filename = File.join(d,"test") + File.open(filename, "w") do |io| + io.write "test" + end + end + raise RuntimeError.new("Directory wasn't cleaned up") if FileTest.directory?(path) - begin - ScratchDir.new do |d| - path = d - STDOUT.puts "Created scratch direcory #{d}" - raise RuntimeError.new("This error should not prevent cleanup") - end - rescue - end - raise RuntimeError.new("Directory wasn't cleaned up") if FileTest.directory?(path) + begin + ScratchDir.new do |d| + path = d + STDOUT.puts "Created scratch direcory #{d}" + raise RuntimeError.new("This error should not prevent cleanup") + end + rescue + end + raise RuntimeError.new("Directory wasn't cleaned up") if FileTest.directory?(path) - STDOUT.puts "Tests passed." + STDOUT.puts "Tests passed." + end end diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb index f2a3031..0cf6e2e 100644 --- a/lib/ohcount/source_file.rb +++ b/lib/ohcount/source_file.rb @@ -1,5 +1,3 @@ -require 'tempfile' - module Ohcount # SourceFile abstracts a source code file and allows easy querying of ohcount-related @@ -124,11 +122,12 @@ def realize_file elsif @file_location && File.basename(@file_location) == basename yield @file_location else + # must recreate a directory and stuff ScratchDir.new do |d| realized_filename = File.join(d,basename) File.open(realized_filename, "w") { |io| io.write(contents) } - return yield realized_filename + return yield(realized_filename) end end end From 723d7012576130adf97d24303306f4900dc28221 Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Thu, 13 Nov 2008 10:28:45 -0800 Subject: [PATCH 055/387] [FIX] mktemp on linux needs 6 X's! --- lib/ohcount/scratch_dir.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ohcount/scratch_dir.rb b/lib/ohcount/scratch_dir.rb index 8a18318..d6164d7 100644 --- a/lib/ohcount/scratch_dir.rb +++ b/lib/ohcount/scratch_dir.rb @@ -21,7 +21,7 @@ class ScratchDir # end # Scratch directory is deleted here # def initialize - @path = `mktemp -d /tmp/ohcount_XXXXX`.strip + @path = `mktemp -d /tmp/ohcount_XXXXXX`.strip if block_given? begin return yield(@path) From 520debeb8cef06559c781928e01bc40bf84982df Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Thu, 13 Nov 2008 21:08:47 -0800 Subject: [PATCH 056/387] [FIX] Ohloh integration --- lib/ohcount/gestalt_facts.rb | 6 +++--- rules/tools.rb | 23 +++++++++++++---------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/lib/ohcount/gestalt_facts.rb b/lib/ohcount/gestalt_facts.rb index 10bfa8f..c16af2f 100644 --- a/lib/ohcount/gestalt_facts.rb +++ b/lib/ohcount/gestalt_facts.rb @@ -12,7 +12,7 @@ def initialize end def process(source_file) - FileRule.rules_triggered_by(source_file).each do |r| + Gestalt::FileRule.rules_triggered_by(source_file).each do |r| @file_rules[r] ||= 0 @file_rules[r] += 1 end @@ -40,11 +40,11 @@ def post_process end def uninfered_platforms #:nodoc: - Platform.descendants - @platforms + Gestalt::Platform.descendants - @platforms end def uninfered_tools #:nodoc: - Tool.descendants - @tools + Gestalt::Tool.descendants - @tools end def includes_language?(language, min_percent = 0) diff --git a/rules/tools.rb b/rules/tools.rb index 645a048..e1073d2 100644 --- a/rules/tools.rb +++ b/rules/tools.rb @@ -1,15 +1,18 @@ # Tools -include Ohcount::Gestalt -class VisualStudio < Tool - filenames '\.(sln|vcproj|vsproj|csproj|vbproj|vbp)$' -end +module Ohcount + module Gestalt + class VisualStudio < Tool + filenames '\.(sln|vcproj|vsproj|csproj|vbproj|vbp)$' + end -class Eclipse < Tool - filenames '\.(project|classpath)$' -end + class Eclipse < Tool + filenames '\.(project|classpath)$' + end -class NetBeans < Tool - filenames '\bnbplatform\b' - filenames '\.nbm$' + class NetBeans < Tool + filenames '\bnbplatform\b' + filenames '\.nbm$' + end + end end From 298085f4cb19ed1dad8858117f847eede2a96cdb Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Fri, 14 Nov 2008 00:58:04 -0800 Subject: [PATCH 057/387] [NEW] Added VisualBasic platform [FIX] fixed ohcount -i --- bin/ohcount | 2 +- lib/ohcount/detector.rb | 1 + rules/platforms.rb | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/bin/ohcount b/bin/ohcount index 6b6e5c4..e86265b 100755 --- a/bin/ohcount +++ b/bin/ohcount @@ -158,7 +158,7 @@ HELP end def individual - STDOUT.write "Examining #{files.size} file(s)" + STDOUT.write "Examining #{source_file_list.size} file(s)" puts puts "Ohloh Line Count".center(76) diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index 44ba0a1..e99f92e 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -151,6 +151,7 @@ def self.binary_filename?(filename) '.f03' => :disambiguate_fortran, '.frag' => "glsl", '.frx' => "visualbasic", + '.frm' => "visualbasic", '.glsl' => "glsl", '.groovy' => "groovy", '.h' => :disambiguate_h_header, diff --git a/rules/platforms.rb b/rules/platforms.rb index d4bba83..7f91516 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -24,6 +24,10 @@ class Dot_NET < Platform language :csharp, :min_percent => 10 end + class VisualBasic < Platform + language :visualbasic, :min_percent => 5 + end + class ASP_NET < Platform filenames('\.(aspx|ascx|ashx|asax|axd)$') end From e2ca177a98f8d921481da78a001d9cca501bbf1f Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Fri, 14 Nov 2008 13:39:33 -0800 Subject: [PATCH 058/387] [NEW] Symfony platform detection --- rules/platforms.rb | 7 +++++++ test/gestalt_files/symfony/config.php | 2 ++ test/unit/gestalt/platform_test.rb | 4 ++++ 3 files changed, 13 insertions(+) create mode 100644 test/gestalt_files/symfony/config.php diff --git a/rules/platforms.rb b/rules/platforms.rb index d4bba83..f4d8d93 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -78,6 +78,13 @@ class WxWidgets < Platform c_headers 'wx/window.h' end + class Symfony < Platform + _and( + platform(PHP), + php_keywords('sfCore', 'sfConfig') + ) + end + class CakePHP < Platform _and( platform(PHP), diff --git a/test/gestalt_files/symfony/config.php b/test/gestalt_files/symfony/config.php new file mode 100644 index 0000000..9ba03b2 --- /dev/null +++ b/test/gestalt_files/symfony/config.php @@ -0,0 +1,2 @@ + Date: Fri, 14 Nov 2008 14:00:08 -0800 Subject: [PATCH 059/387] [NEW] Pear platform detection --- lib/gestalt/rules/xml_keyword_rule.rb | 15 +++++++++++++++ rules/platforms.rb | 10 ++++++++++ test/gestalt_files/pear/Sample.class.php | 10 ++++++++++ test/gestalt_files/pear/package.xml | 9 +++++++++ test/unit/gestalt/platform_test.rb | 4 ++++ 5 files changed, 48 insertions(+) create mode 100644 lib/gestalt/rules/xml_keyword_rule.rb create mode 100644 test/gestalt_files/pear/Sample.class.php create mode 100644 test/gestalt_files/pear/package.xml diff --git a/lib/gestalt/rules/xml_keyword_rule.rb b/lib/gestalt/rules/xml_keyword_rule.rb new file mode 100644 index 0000000..c9607ba --- /dev/null +++ b/lib/gestalt/rules/xml_keyword_rule.rb @@ -0,0 +1,15 @@ +module Ohcount + module Gestalt + class XmlKeywordRule < KeywordRule + + def initialize(*keywords) + super('xml',*keywords) + end + + def trigger_file?(source_file) + return false unless source_file.polyglot = 'xml' + regexp.match(source_file.language_breakdowns('xml').code) + end + end + end +end diff --git a/rules/platforms.rb b/rules/platforms.rb index 408657a..21dad55 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -96,6 +96,16 @@ class CakePHP < Platform ) end + class Pear < Platform + _and( + platform(PHP), + _or( + filenames('\bpackage\.xml(\.tpl)?$'), + xml_keywords('pear.php.net/dtd/package-2.0') + ) + ) + end + class KDE < Platform c_headers 'KDEInit.h', 'kdeversion.h' end diff --git a/test/gestalt_files/pear/Sample.class.php b/test/gestalt_files/pear/Sample.class.php new file mode 100644 index 0000000..243e5dd --- /dev/null +++ b/test/gestalt_files/pear/Sample.class.php @@ -0,0 +1,10 @@ + diff --git a/test/gestalt_files/pear/package.xml b/test/gestalt_files/pear/package.xml new file mode 100644 index 0000000..942a309 --- /dev/null +++ b/test/gestalt_files/pear/package.xml @@ -0,0 +1,9 @@ + + + diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index c654453..68318bb 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -45,6 +45,10 @@ def test_symfony assert_platform('symfony', PHP, Symfony) end + def test_pear + assert_platform('pear', PHP, Pear) + end + def test_spring_framework assert_platform('spring_framework', Java, SpringFramework) end From df6090c2fa998abaa828a363493c5c3a8e7e3015 Mon Sep 17 00:00:00 2001 From: Jason Allen Date: Fri, 14 Nov 2008 14:21:19 -0800 Subject: [PATCH 060/387] [NEW] Zend Framework Platform --- rules/platforms.rb | 7 +++ .../ZendWildfirePluginFirePhpController.php | 50 ++++++++++++++++++++++ test/unit/gestalt/platform_test.rb | 4 ++ 3 files changed, 61 insertions(+) create mode 100644 test/gestalt_files/zend_framework/application/controllers/ZendWildfirePluginFirePhpController.php diff --git a/rules/platforms.rb b/rules/platforms.rb index 7f91516..ee60649 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -82,6 +82,13 @@ class WxWidgets < Platform c_headers 'wx/window.h' end + class ZendFramework < Platform + _and( + platform(PHP), + php_keywords('Zend_Controller_Action') + ) + end + class CakePHP < Platform _and( platform(PHP), diff --git a/test/gestalt_files/zend_framework/application/controllers/ZendWildfirePluginFirePhpController.php b/test/gestalt_files/zend_framework/application/controllers/ZendWildfirePluginFirePhpController.php new file mode 100644 index 0000000..8273004 --- /dev/null +++ b/test/gestalt_files/zend_framework/application/controllers/ZendWildfirePluginFirePhpController.php @@ -0,0 +1,50 @@ + Date: Fri, 14 Nov 2008 14:21:28 -0800 Subject: [PATCH 061/387] [NEW] GTK & Python --- rules/platforms.rb | 9 +++++++++ test/gestalt_files/gtk/simple.c | 13 +++++++++++++ test/gestalt_files/python/hello_world.py | 1 + test/unit/gestalt/platform_test.rb | 8 ++++++++ 4 files changed, 31 insertions(+) create mode 100644 test/gestalt_files/gtk/simple.c create mode 100644 test/gestalt_files/python/hello_world.py diff --git a/rules/platforms.rb b/rules/platforms.rb index f0b982a..c476627 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -56,6 +56,10 @@ class Mac < Platform filenames '\.plist' end +class Python < Platform + language :python, :min_percent => 15 +end + class PHP < Platform language :php, :min_percent => 15 end @@ -71,6 +75,10 @@ class KDE < Platform c_headers 'KDEInit.h', 'kdeversion.h' end +class GTK < Platform + c_keywords 'gtk_init', 'gtk_main', 'gtk_window_new', 'GtkWidget' +end + class MSDos < Platform c_keywords '__MSDOS__', 'MSDOS', :min => 2 end @@ -78,3 +86,4 @@ class MSDos < Platform class EclipsePlatform < Platform java_import 'org.eclipse.' end + diff --git a/test/gestalt_files/gtk/simple.c b/test/gestalt_files/gtk/simple.c new file mode 100644 index 0000000..2910064 --- /dev/null +++ b/test/gestalt_files/gtk/simple.c @@ -0,0 +1,13 @@ +#include +int main(int argc, char *argv[]) +{ + GtkWidget *gtkWindow; + + gtk_init(&argc, &argv); + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_show(window); + + gtk_main(); + return 0; +} diff --git a/test/gestalt_files/python/hello_world.py b/test/gestalt_files/python/hello_world.py new file mode 100644 index 0000000..18d9f87 --- /dev/null +++ b/test/gestalt_files/python/hello_world.py @@ -0,0 +1 @@ +print "Hello, World!" diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index 812a82c..c57c39a 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -45,6 +45,10 @@ def test_php assert_platform('php', PHP) end + def test_python + assert_platform('python', Python) + end + def test_mac assert_platform('mac', Mac) end @@ -69,6 +73,10 @@ def test_msdos assert_platform('msdos', MSDos) end + def test_gtk + assert_platform('gtk', GTK) + end + protected def assert_platform(path, *platforms) From 1d56cfbc944be23283db2ac8ac869d1becf62372 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Fri, 14 Nov 2008 14:32:50 -0800 Subject: [PATCH 062/387] [NEW] Moodle platform detection --- rules/platforms.rb | 7 +++++++ test/gestalt_files/moodle/moodle.php | 8 ++++++++ test/unit/gestalt/platform_test.rb | 4 ++++ 3 files changed, 19 insertions(+) create mode 100644 test/gestalt_files/moodle/moodle.php diff --git a/rules/platforms.rb b/rules/platforms.rb index 21dad55..fb9d2d9 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -106,6 +106,13 @@ class Pear < Platform ) end + class Moodle < Platform + _and( + platform(PHP), + php_keywords("moodle") + ) + end + class KDE < Platform c_headers 'KDEInit.h', 'kdeversion.h' end diff --git a/test/gestalt_files/moodle/moodle.php b/test/gestalt_files/moodle/moodle.php new file mode 100644 index 0000000..1ecdedd --- /dev/null +++ b/test/gestalt_files/moodle/moodle.php @@ -0,0 +1,8 @@ + diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index 68318bb..751cdf0 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -49,6 +49,10 @@ def test_pear assert_platform('pear', PHP, Pear) end + def test_moodle + assert_platform('moodle', PHP, Moodle) + end + def test_spring_framework assert_platform('spring_framework', Java, SpringFramework) end From d19289d3d0ac6bff8cccc122ccb765d8a7204cea Mon Sep 17 00:00:00 2001 From: "andy@ohloh.net" Date: Fri, 14 Nov 2008 14:42:09 -0800 Subject: [PATCH 063/387] [NEW] Add Drupal platform detection --- rules/platforms.rb | 11 +++++++++++ test/gestalt_files/drupal/bar.php | 4 ++++ test/unit/gestalt/platform_test.rb | 4 ++++ 3 files changed, 19 insertions(+) create mode 100644 test/gestalt_files/drupal/bar.php diff --git a/rules/platforms.rb b/rules/platforms.rb index 8aa87ee..bbd09f1 100644 --- a/rules/platforms.rb +++ b/rules/platforms.rb @@ -157,6 +157,17 @@ class GTK < Platform c_keywords 'gtk_init', 'gtk_main', 'gtk_window_new', 'GtkWidget' end + class Drupal < Platform + _and( + platform(PHP), + _or( + php_keywords('drupal_set_message'), + php_keywords('drupal_render'), + php_keywords('Drupal', :min => 3) + ) + ) + end + class MSDos < Platform c_keywords '__MSDOS__', 'MSDOS', :min => 2 end diff --git a/test/gestalt_files/drupal/bar.php b/test/gestalt_files/drupal/bar.php new file mode 100644 index 0000000..af5d41f --- /dev/null +++ b/test/gestalt_files/drupal/bar.php @@ -0,0 +1,4 @@ + diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index 15b85ae..7b5236a 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -97,6 +97,10 @@ def test_gtk assert_platform('gtk', GTK) end + def test_drupal + assert_platform('drupal', PHP, Drupal) + end + protected def assert_platform(path, *platforms) From b8f47d14be24caa61dba1f564aa448486601c67d Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 18 Nov 2008 09:40:41 -0800 Subject: [PATCH 064/387] [FIX] Don't try to sloc null file names :-) --- lib/ohcount/source_file_list.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ohcount/source_file_list.rb b/lib/ohcount/source_file_list.rb index 8100d56..a8cff6d 100644 --- a/lib/ohcount/source_file_list.rb +++ b/lib/ohcount/source_file_list.rb @@ -24,7 +24,7 @@ def initialize(options = {}) when :files then v else raise(ArgumentError, "Unrecognized option: #{ k }") end - end.flatten.uniq + end.flatten.uniq.compact super(files) end From 80ebac282df611d962503aca576fe24957fa2861 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 18 Nov 2008 09:43:19 -0800 Subject: [PATCH 065/387] [FIX] When printing platforms to the console output, suppress the namespace prefixes --- bin/ohcount | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/ohcount b/bin/ohcount index e86265b..45a409d 100755 --- a/bin/ohcount +++ b/bin/ohcount @@ -73,11 +73,11 @@ class OhcountCommandLine def write_gestalt platforms = source_file_list.gestalt_facts.platforms - platforms = platforms.any? ? platforms.collect { |p| p.to_s }.join(", ") : 'None' + platforms = platforms.any? ? platforms.collect { |p| p.to_s.split('::').last }.join(", ") : 'None' puts "Platforms detected: #{ platforms }" tools = source_file_list.gestalt_facts.tools - tools = tools.any? ? tools.collect { |p| p.to_s }.join(", ") : 'None' + tools = tools.any? ? tools.collect { |p| p.to_s.split('::').last }.join(", ") : 'None' puts "Tools detected: #{ tools }" end From 6c35d59b6fa166d5a41573aae11c0af12edddb7d Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 18 Nov 2008 11:58:11 -0800 Subject: [PATCH 066/387] [NEW] Add .ctp as a php extension --- lib/ohcount/detector.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index e99f92e..1120462 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -127,6 +127,7 @@ def self.binary_filename?(filename) '.c' => "c", '.C' => "cpp", '.cc' => "cpp", + '.ctp' => "php", '.cpp' => "cpp", '.css' => "css", '.c++' => "cpp", From 09e172139dc347a141d2e26e29c02450bc16b144 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 18 Nov 2008 16:39:03 -0800 Subject: [PATCH 067/387] [FIX] Stop parsing binary files. --- lib/ohcount/detector.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index 1120462..bc05e96 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -53,6 +53,8 @@ module ContainsVB # end # def self.detect(source_file) + return nil if binary_filename?(source_file.filename) + # start with filename and extension polyglot = [ lambda { | f | FILENAME_MAP[File.basename(source_file.filename)] }, From fc9593d10a6b806745587086f519d376c7c44176 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Wed, 19 Nov 2008 10:42:48 -0800 Subject: [PATCH 068/387] [FIX] Better detection of binary files, more binary extensions --- lib/ohcount/detector.rb | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index bc05e96..817b8c7 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -54,6 +54,7 @@ module ContainsVB # def self.detect(source_file) return nil if binary_filename?(source_file.filename) + return nil if binary_buffer?(source_file.contents) # start with filename and extension polyglot = [ @@ -78,32 +79,36 @@ def self.detect(source_file) # Based solely on the filename, makes a judgment whether a file is a binary format. def self.binary_filename?(filename) ignore = [ - ".svn", - ".jar", - ".tar", - ".gz", - ".tgz", - ".zip", + ".aiff", + ".au", + ".avi", + ".bmp", + ".doc", ".gif", - ".jpg", + ".gz", + ".jar", ".jpeg", - ".bmp", + ".jpg", + ".m4a", + ".mov", + ".mp3", + ".mpg", + ".ogg", + ".pdf", ".png", + ".ppt", + ".qt", + ".ra", + ".svn", + ".swf", + ".tar", + ".tgz", ".tif", ".tiff", - ".ogg", - ".aiff", ".wav", - ".mp3", - ".au", - ".ra", - ".m4a", - ".pdf", - ".mpg", - ".mov", - ".qt", - ".avi", - ".swf" + ".xls", + ".xlw", + ".zip" ] ignore.include?(File.extname(filename)) end From 9be44cc0b9fe99bbbb076cca13f7ba594660d3a1 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Wed, 19 Nov 2008 10:52:29 -0800 Subject: [PATCH 069/387] [FIX] If detect() returns a nil result, remember that result and don't keep re-detecting --- lib/ohcount/source_file.rb | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb index 0cf6e2e..7fa1da5 100644 --- a/lib/ohcount/source_file.rb +++ b/lib/ohcount/source_file.rb @@ -55,14 +55,15 @@ def contents end end + # A bit complicated because a nil value can either mean that we haven't checked, + # or that we have checked but received a nil result. def polyglot - @polyglot ||= begin - if file? - Ohcount::Detector.detect(self) - else - nil - end - end + return @polyglot if @polyglot + return nil if @is_nil + + @polyglot = Ohcount::Detector.detect(self) if file? + @is_nil = !@polyglot + @polyglot end # returns true iff we represent a file (could be a dir) From 78b22371d6ab5426843edfea9e1077aaeeb32721 Mon Sep 17 00:00:00 2001 From: "andy@ohloh.net" Date: Wed, 19 Nov 2008 11:52:49 -0800 Subject: [PATCH 070/387] [CHANGE] simpler memoization for polyglot --- lib/ohcount/source_file.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb index 7fa1da5..ca0eebf 100644 --- a/lib/ohcount/source_file.rb +++ b/lib/ohcount/source_file.rb @@ -58,12 +58,8 @@ def contents # A bit complicated because a nil value can either mean that we haven't checked, # or that we have checked but received a nil result. def polyglot - return @polyglot if @polyglot - return nil if @is_nil - + return @polyglot if defined?(@polyglot) @polyglot = Ohcount::Detector.detect(self) if file? - @is_nil = !@polyglot - @polyglot end # returns true iff we represent a file (could be a dir) From f2064f5a75dacd19db86bd6c732136fb3029f565 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Fri, 5 Dec 2008 13:34:25 -0800 Subject: [PATCH 071/387] [NEW] When 'file -b' replies with XML, we didn't recognize it. --- lib/ohcount/detector.rb | 2 ++ test/detect_files/xml.custom_ext | 1 + test/unit/detector_test.rb | 5 ++++- 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 test/detect_files/xml.custom_ext diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index 817b8c7..2347b70 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -592,6 +592,8 @@ def self.disambiguate_nil(source_file) when "Bourne-Again" return "shell" end + when /XML 1\.0 document text/ + return 'xml' end # dang... no dice nil diff --git a/test/detect_files/xml.custom_ext b/test/detect_files/xml.custom_ext new file mode 100644 index 0000000..2b5d411 --- /dev/null +++ b/test/detect_files/xml.custom_ext @@ -0,0 +1 @@ + diff --git a/test/unit/detector_test.rb b/test/unit/detector_test.rb index 9ae0992..036cd21 100644 --- a/test/unit/detector_test.rb +++ b/test/unit/detector_test.rb @@ -123,8 +123,11 @@ def test_basic assert_equal "structured_basic", do_detect("visual_basic.bas") assert_equal "visualbasic", do_detect("visual_basic.bas", ["frx1.frx"]) assert_equal "classic_basic", do_detect("classic_basic.b") - assert_equal "structured_basic", do_detect("structured_basic.b") + assert_equal "structured_basic", do_detect("structured_basic.b") end + def test_xml_with_custom_extension + assert_equal 'xml', do_detect("xml.custom_ext") + end end From bae6501a0b91b56192228037dc69110a7499b981 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Fri, 5 Dec 2008 13:36:33 -0800 Subject: [PATCH 072/387] [FIX] What works on Mac OS X doesn't always work on Ubuntu... :-( --- lib/ohcount/detector.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index 2347b70..6829b80 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -592,7 +592,7 @@ def self.disambiguate_nil(source_file) when "Bourne-Again" return "shell" end - when /XML 1\.0 document text/ + when /XML( 1\.0)? document text/ return 'xml' end # dang... no dice From e446d8a98d33938a4936dcaf904eda736866c23d Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Sat, 6 Dec 2008 14:42:43 -0800 Subject: [PATCH 073/387] Support for Objective-J. --- ext/ohcount_native/ragel_parser.c | 2 + ext/ohcount_native/ragel_parsers/objective_j.rl | 124 ++++++++++++++++++++++++ lib/ohcount/detector.rb | 1 + lib/ohcount/sloc_info.rb | 1 + 4 files changed, 128 insertions(+) create mode 100644 ext/ohcount_native/ragel_parsers/objective_j.rl diff --git a/ext/ohcount_native/ragel_parser.c b/ext/ohcount_native/ragel_parser.c index 1bf97f4..9d035b3 100644 --- a/ext/ohcount_native/ragel_parser.c +++ b/ext/ohcount_native/ragel_parser.c @@ -47,6 +47,7 @@ #include "metapost_with_tex_parser.h" #include "mxml_parser.h" #include "objective_c_parser.h" +#include "objective_j_parser.h" #include "ocaml_parser.h" #include "pascal_parser.h" #include "perl_parser.h" @@ -132,6 +133,7 @@ struct language languages[] = { { "metapost_with_tex", parse_mptex }, { "mxml", parse_mxml }, { "objective_c", parse_objective_c }, + { "objective_j", parse_objective_j }, { "ocaml", parse_ocaml }, { "pascal", parse_pascal }, { "perl", parse_perl }, diff --git a/ext/ohcount_native/ragel_parsers/objective_j.rl b/ext/ohcount_native/ragel_parsers/objective_j.rl new file mode 100644 index 0000000..a0090dc --- /dev/null +++ b/ext/ohcount_native/ragel_parsers/objective_j.rl @@ -0,0 +1,124 @@ +// objective_j.rl written by Francisco tolmasky. francisco280northcom. +// Modified from file by Mitchell Foral. mitchellcaladbolgnet. + +/************************* Required for every parser *************************/ +#ifndef RAGEL_OBJECTIVE_J_PARSER +#define RAGEL_OBJECTIVE_J_PARSER + +#include "ragel_parser_macros.h" + +// the name of the language +const char *OBJJ_LANG = "objective_j"; + +// the languages entities +const char *objj_entities[] = { + "space", "comment", "string", "any" +}; + +// constants associated with the entities +enum { + OBJJ_SPACE = 0, OBJJ_COMMENT, OBJJ_STRING, OBJJ_ANY, +}; + +/*****************************************************************************/ + +%%{ + machine objective_j; + write data; + include common "common.rl"; + + # Line counting machine + + action objj_ccallback { + switch(entity) { + case OBJJ_SPACE: + ls + break; + case OBJJ_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(OBJJ_LANG) + break; + case NEWLINE: + std_newline(OBJJ_LANG) + } + } + + objj_line_comment = + '//' @comment ( + escaped_newline %{ entity = INTERNAL_NL; } %objj_ccallback + | + ws + | + (nonnewline - ws) @comment + )*; + objj_block_comment = + '/*' @comment ( + newline %{ entity = INTERNAL_NL; } %objj_ccallback + | + ws + | + (nonnewline - ws) @comment + )* :>> '*/'; + objj_comment = objj_line_comment | objj_block_comment; + + objj_sq_str = '\'' @code ([^\r\n\f'\\] | '\\' nonnewline)* '\''; + objj_dq_str = '"' @code ([^\r\n\f"\\] | '\\' nonnewline)* '"'; + objj_string = objj_sq_str | objj_dq_str; + + objj_line := |* + spaces ${ entity = OBJJ_SPACE; } => objj_ccallback; + objj_comment; + objj_string; + newline ${ entity = NEWLINE; } => objj_ccallback; + ^space ${ entity = OBJJ_ANY; } => objj_ccallback; + *|; + + # Entity machine + + action objj_ecallback { + callback(OBJJ_LANG, objj_entities[entity], cint(ts), cint(te)); + } + + objj_line_comment_entity = '//' (escaped_newline | nonnewline)*; + objj_block_comment_entity = '/*' any* :>> '*/'; + objj_comment_entity = objj_line_comment_entity | objj_block_comment_entity; + + objj_entity := |* + space+ ${ entity = OBJJ_SPACE; } => objj_ecallback; + objj_comment_entity ${ entity = OBJJ_COMMENT; } => objj_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with Objective C code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_objective_j(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int start, int end) + ) { + init + + %% write init; + cs = (count) ? objective_j_en_objj_line : objective_j_en_objj_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(OBJJ_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index 6829b80..0e67797 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -176,6 +176,7 @@ def self.binary_filename?(filename) '.html' => "html", '.in' => :disambiguate_in, '.inc' => :disambiguate_inc, + '.j' => "objective_j", '.java' => "java", '.js' => "javascript", '.jsp' => "jsp", diff --git a/lib/ohcount/sloc_info.rb b/lib/ohcount/sloc_info.rb index 395559b..410a8e2 100644 --- a/lib/ohcount/sloc_info.rb +++ b/lib/ohcount/sloc_info.rb @@ -71,6 +71,7 @@ def ==(b) 'metapost' => {:nice_name => 'MetaPost' , :category => 1}, 'mxml' => {:nice_name => 'Flex' , :category => 1}, 'objective_c' => {:nice_name => 'Objective C' , :category => 0}, + 'objective_j' => {:nice_name => 'Objective-J' , :category => 0}, 'ocaml' => {:nice_name => 'Objective Caml' , :category => 0}, 'pascal' => {:nice_name => 'Pascal' , :category => 0}, 'perl' => {:nice_name => 'Perl' , :category => 0}, From 6d67cd63fbf5f5569918d631407dfe8bfd4039d6 Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Mon, 15 Dec 2008 19:29:07 -0800 Subject: [PATCH 074/387] Added tests for Objective-J mode. Reviewed by me. --- test/expected_dir/objj.j | 25 +++++++++++++++++++++++++ test/src_dir/objj.j | 25 +++++++++++++++++++++++++ test/unit/parsers/objective_j_test.rb | 18 ++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 test/expected_dir/objj.j create mode 100644 test/src_dir/objj.j create mode 100644 test/unit/parsers/objective_j_test.rb diff --git a/test/expected_dir/objj.j b/test/expected_dir/objj.j new file mode 100644 index 0000000..c2e598c --- /dev/null +++ b/test/expected_dir/objj.j @@ -0,0 +1,25 @@ +objective_j blank +objective_j code @import +objective_j code @import +objective_j blank +objective_j code @import "Superclass.j" +objective_j blank +objective_j comment /* +objective_j comment I'm commenting this class +objective_j comment */ +objective_j code @implementation Class : Superclass +objective_j code { +objective_j code var x @accessors; +objective_j code } +objective_j blank +objective_j code + (void)classMethod +objective_j code { +objective_j code return self; // this is a comment +objective_j code } +objective_j blank +objective_j code - (void)instanceMethod +objective_j code { +objective_j code return self; +objective_j code } +objective_j blank +objective_j code @end diff --git a/test/src_dir/objj.j b/test/src_dir/objj.j new file mode 100644 index 0000000..88cb674 --- /dev/null +++ b/test/src_dir/objj.j @@ -0,0 +1,25 @@ + +@import +@import + +@import "Superclass.j" + +/* + I'm commenting this class +*/ +@implementation Class : Superclass +{ + var x @accessors; +} + ++ (void)classMethod +{ + return self; // this is a comment +} + +- (void)instanceMethod +{ + return self; +} + +@end diff --git a/test/unit/parsers/objective_j_test.rb b/test/unit/parsers/objective_j_test.rb new file mode 100644 index 0000000..507f3d6 --- /dev/null +++ b/test/unit/parsers/objective_j_test.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::ObjectiveJTest < Ohcount::Test + def test_comments + lb = [Ohcount::LanguageBreakdown.new("objective_j", "", "//comment", 0)] + assert_equal lb, Ohcount::parse(" //comment", "objective_j") + end + + def test_comprehensive + verify_parse("objj.j") + end + + def test_comment_entities + assert_equal('//comment', entities_array(" //comment", 'objective_j', :comment).first) + assert_equal('/*comment*/', entities_array(" /*comment*/", 'objective_j', :comment).first) + end + +end From 1c4c415863a00ba550844f6bf1f20d2aff4bda24 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Fri, 23 Jan 2009 09:07:56 -0800 Subject: [PATCH 075/387] [FIX] Add a new binary file extension (.cache) --- lib/ohcount/detector.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index 0e67797..c1f0f12 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -83,6 +83,7 @@ def self.binary_filename?(filename) ".au", ".avi", ".bmp", + ".cache", ".doc", ".gif", ".gz", From eda1d5e18c11bb91d1d97a811684b4841cbbe7fb Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Fri, 23 Jan 2009 15:51:54 -0800 Subject: [PATCH 076/387] [NEW] Move the sloc diff'ing code out of Ohloh and into Ohcount --- lib/ohcount.rb | 4 +- lib/ohcount/source_file.rb | 44 + test/unit/source_file_test.rb | 58 + vendor/gems/diff-lcs-1.1.2/ChangeLog | 46 + vendor/gems/diff-lcs-1.1.2/Install | 6 + vendor/gems/diff-lcs-1.1.2/README | 76 ++ vendor/gems/diff-lcs-1.1.2/Rakefile | 116 ++ vendor/gems/diff-lcs-1.1.2/bin/htmldiff | 112 ++ vendor/gems/diff-lcs-1.1.2/bin/ldiff | 45 + vendor/gems/diff-lcs-1.1.2/diff-lcs.gemspec | 40 + vendor/gems/diff-lcs-1.1.2/install.rb | 262 +++++ vendor/gems/diff-lcs-1.1.2/lib/diff/lcs.rb | 1106 ++++++++++++++++++++ vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/array.rb | 21 + vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/block.rb | 51 + .../gems/diff-lcs-1.1.2/lib/diff/lcs/callbacks.rb | 322 ++++++ vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/change.rb | 172 +++ vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/hunk.rb | 257 +++++ vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/ldiff.rb | 226 ++++ vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/string.rb | 19 + vendor/gems/diff-lcs-1.1.2/tests/00test.rb | 626 +++++++++++ 20 files changed, 3607 insertions(+), 2 deletions(-) create mode 100644 vendor/gems/diff-lcs-1.1.2/ChangeLog create mode 100644 vendor/gems/diff-lcs-1.1.2/Install create mode 100644 vendor/gems/diff-lcs-1.1.2/README create mode 100644 vendor/gems/diff-lcs-1.1.2/Rakefile create mode 100755 vendor/gems/diff-lcs-1.1.2/bin/htmldiff create mode 100755 vendor/gems/diff-lcs-1.1.2/bin/ldiff create mode 100644 vendor/gems/diff-lcs-1.1.2/diff-lcs.gemspec create mode 100644 vendor/gems/diff-lcs-1.1.2/install.rb create mode 100644 vendor/gems/diff-lcs-1.1.2/lib/diff/lcs.rb create mode 100644 vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/array.rb create mode 100644 vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/block.rb create mode 100644 vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/callbacks.rb create mode 100644 vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/change.rb create mode 100644 vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/hunk.rb create mode 100644 vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/ldiff.rb create mode 100644 vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/string.rb create mode 100644 vendor/gems/diff-lcs-1.1.2/tests/00test.rb diff --git a/lib/ohcount.rb b/lib/ohcount.rb index c5aed60..84dcd74 100644 --- a/lib/ohcount.rb +++ b/lib/ohcount.rb @@ -3,8 +3,9 @@ module Ohcount require 'rbconfig' -OHCOUNT_ROOT = File.dirname(__FILE__) + "/.." +OHCOUNT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..')) $: << OHCOUNT_ROOT +$: << File.join(OHCOUNT_ROOT, 'vendor', 'gems', 'diff-lcs-1.1.2', 'lib') begin require 'ohcount_native' @@ -29,4 +30,3 @@ module Ohcount # require the dynamic rules require 'rules/platforms' require 'rules/tools' - diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb index ca0eebf..3175292 100644 --- a/lib/ohcount/source_file.rb +++ b/lib/ohcount/source_file.rb @@ -1,4 +1,5 @@ module Ohcount + require 'diff/lcs' # SourceFile abstracts a source code file and allows easy querying of ohcount-related # information. @@ -152,5 +153,48 @@ def languages parse unless parsed? @language_breakdowns.collect { |lb| lb.name } end + + # returns a collection of sloc_infos containing + # the diffs from the this current object to the + # new object + def diff(new) + all_languages = (self.languages + new.languages).uniq + all_languages.collect do |language| + si = Ohcount::SlocInfo.new(language) + lb_old = language_breakdowns(language) + lb_new = new.language_breakdowns(language) + + #code + si.code_added, si.code_removed = calc_diff(lb_old.code, lb_new.code) + si.comments_added, si.comments_removed = calc_diff(lb_old.comment, lb_new.comment) + si.blanks_added = lb_new.blanks - lb_old.blanks + si.blanks_removed = lb_old.blanks - lb_new.blanks + + # strip negative blank counts + si.blanks_added = 0 if si.blanks_added < 0 + si.blanks_removed = 0 if si.blanks_removed < 0 + + si + end.reject do |si| + # remove meangingless sloc_infos + si.no_changes? + end + end + + # takes 2 strings and returns an array containing the count + # of added lines and deleted lines. Example + # + # calc_diff("a\nb", "a\nc") # [1,1] -> one added, one deleted + # + def calc_diff(a,b) + a = a.split("\n") + b = b.split("\n") + diffs = LCSDiff::Diff::LCS.diff(a,b) + LCSDiff::Diff::LCS.diff(a,b).flatten.inject([0,0]) do |m, change| + m[0] += 1 if change.adding? + m[1] += 1 if change.deleting? + m + end + end end end diff --git a/test/unit/source_file_test.rb b/test/unit/source_file_test.rb index 8548daf..93a8ea7 100644 --- a/test/unit/source_file_test.rb +++ b/test/unit/source_file_test.rb @@ -36,5 +36,63 @@ def test_realize_file assert_equal 'i', File.new(f).read end end + + def test_calc_diff + old = SourceFile.new("foo.c", :contents => 'int i;') + new = SourceFile.new("foo.c", :contents => 'int j;') + + c_si = Ohcount::SlocInfo.new('c', :code_added => 1, :code_removed => 1) + assert_equal [c_si], old.diff(new) + end + + def test_calc_diff_2 + old = SourceFile.new("foo.html", :contents => <<-INLINE_HTML + + + + + INLINE_HTML + ) + new = SourceFile.new("foo.html", :contents => <<-INLINE_HTML + + + + + INLINE_HTML + ) + + javascript_si = Ohcount::SlocInfo.new('javascript', :code_added => 1, :code_removed => 1) + css_si = Ohcount::SlocInfo.new('css', :comments_added => 1, :comments_removed => 1) + assert_equal [javascript_si, css_si], old.diff(new) + end + + def test_calc_diff_longer + old = SourceFile.new("foo.c", :contents => <<-INLINE_C + int = 1; + int = 2; + int = 3; + int = 4; + INLINE_C + ) + new = SourceFile.new("foo.c", :contents => <<-INLINE_C + int = 1; + int = 5; + int = 6; + int = 4; + INLINE_C + ) + c_si = Ohcount::SlocInfo.new('c', :code_added => 2, :code_removed => 2) + assert_equal [c_si],old.diff(new) + end end diff --git a/vendor/gems/diff-lcs-1.1.2/ChangeLog b/vendor/gems/diff-lcs-1.1.2/ChangeLog new file mode 100644 index 0000000..08d3ee5 --- /dev/null +++ b/vendor/gems/diff-lcs-1.1.2/ChangeLog @@ -0,0 +1,46 @@ +Revision history for Ruby library Diff::LCS. Unless explicitly noted otherwise, +all changes are produced by Austin Ziegler . + +== Diff::LCS 1.1.2 +* Fixed a problem reported by Mauricio Fernandez in htmldiff. Future versions + of Diff::LCS will be removing this program. + +== Diff::LCS 1.1.1 +* Fixed bug #891: + http://rubyforge.org/tracker/?func=detail&atid=407&aid=891&group_id=84 +* Fixed a problem with callback initialisation code (it assumed that all + callbacks passed as classes can be initialised; now, it rescues + NoMethodError in the event of private :new being called). +* Modified the non-initialisable callbacks to have a private #new method. +* Moved ldiff core code to Diff::LCS::Ldiff (diff/lcs/ldiff.rb). + +== Diff::LCS 1.1.0 +* Eliminated the need for Diff::LCS::Event and removed it. +* Added a contextual diff callback, Diff::LCS::ContextDiffCallback. +* Implemented patching/unpatching for standard Diff callback output formats + with both #diff and #sdiff. +* Extensive documentation changes. + +== Diff::LCS 1.0.4 +* Fixed a problem with bin/ldiff output, especially for unified format. + Newlines that should have been present weren't. +* Changed the .tar.gz installer to generate Windows batch files if ones do not + exist already. Removed the existing batch files as they didn't work. + +== Diff::LCS 1.0.3 +* Fixed a problem with #traverse_sequences where the first difference from the + left sequence might not be appropriately captured. + +== Diff::LCS 1.0.2 +* Fixed an issue with ldiff not working because actions were changed from + symbols to strings. + +== Diff::LCS 1.0.1 +* Minor modifications to the gemspec, the README. +* Renamed the diff program to ldiff (as well as the companion batch file) so as + to not collide with the standard diff program. +* Fixed issues with RubyGEMs. Requires RubyGems > 0.6.1 or >= 0.6.1 with the + latest CVS version. + +== Diff::LCS 1.0 +* Initial release based mostly on Perl's Algorithm::Diff. diff --git a/vendor/gems/diff-lcs-1.1.2/Install b/vendor/gems/diff-lcs-1.1.2/Install new file mode 100644 index 0000000..794796e --- /dev/null +++ b/vendor/gems/diff-lcs-1.1.2/Install @@ -0,0 +1,6 @@ +Installing this package is as simple as: + +% ruby install.rb + +Alternatively, you can use the RubyGem version of Diff::LCS available as +diff-lcs-1.1.2.gem from the usual sources. diff --git a/vendor/gems/diff-lcs-1.1.2/README b/vendor/gems/diff-lcs-1.1.2/README new file mode 100644 index 0000000..5056466 --- /dev/null +++ b/vendor/gems/diff-lcs-1.1.2/README @@ -0,0 +1,76 @@ +Diff::LCS README +================ +Diff::LCS is a port of Algorithm::Diff[1] that uses the McIlroy-Hunt +longest common subsequence (LCS) algorithm to compute intelligent +differences between two sequenced enumerable containers[2]. The +implementation is based on Mario I. Wolczko's[3] Smalltalk version (1.2, +1993)[4] and Ned Konz's[5] Perl version (Algorithm::Diff)[6]. + +This release is version 1.1.2, fixing an htmldiff bug in 1.1.1. Version 1.1.0 +added new features, including the ability to #patch and #unpatch changes as +well as a new contextual diff callback, Diff::LCS::ContextDiffCallbacks, that +should improve the context sensitivity of patching. + +Using this module is quite simple. By default, Diff::LCS does not extend +objects with the Diff::LCS interface, but will be called as if it were a +function: + + require 'diff/lcs' + + seq1 = %w(a b c e h j l m n p) + seq2 = %w(b c d e f j k l m r s t) + + lcs = Diff::LCS.LCS(seq1, seq2) + diffs = Diff::LCS.diff(seq1, seq2) + sdiff = Diff::LCS.sdiff(seq1, seq2) + seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) + bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) + seq2 == Diff::LCS.patch!(seq1, diffs) + seq1 == Diff::LCS.unpatch!(seq2, diffs) + seq2 == Diff::LCS.patch!(seq1, sdiff) + seq1 == Diff::LCS.unpatch!(seq2, sdiff) + +Objects can be extended with Diff::LCS: + + seq1.extend(Diff::LCS) + lcs = seq1.lcs(seq2) + diffs = seq1.diff(seq2) + sdiff = seq1.sdiff(seq2) + seq = seq1.traverse_sequences(seq2, callback_obj) + bal = seq1.traverse_balanced(seq2, callback_obj) + seq2 == seq1.patch!(diffs) + seq1 == seq2.unpatch!(diffs) + seq2 == seq1.patch!(sdiff) + seq1 == seq2.unpatch!(sdiff) + +By requiring 'diff/lcs/array' or 'diff/lcs/string', Array or String will +be extended for use this way. + +Copyright +========= +# Copyright 2004 Austin Ziegler +# adapted from: +# Algorithm::Diff (Perl) by Ned Konz +# Smalltalk by Mario I. Wolczko +# implements McIlroy-Hunt diff algorithm +# +# This program is free software. It may be redistributed and/or modified +# under the terms of the GPL version 2 (or later), the Perl Artistic +# licence, or the Ruby licence. +# +# $Id: README,v 1.7 2004/10/17 20:31:10 austin Exp $ + +Footnotes +========= +[1] This library is called Diff::LCS because there are multiple + Ruby libraries called Algorithm::Diff maintained by other authors. +[2] By sequenced enumerable, I mean that the order of enumeration is + predictable and consistent for the same set of data. While it is + theoretically possible to generate a diff for unordereded hash, it + will only be meaningful if the enumeration of the hashes is + consistent. In general, this will mean that containers that behave + like String or Array will perform best. +[3] mario@wolczko.com +[4] ftp://st.cs.uiuc.edu/pub/Smalltalk/MANCHESTER/manchester/4.0/diff.st +[5] perl@bike-nomad.com +[6] http://search.cpan.org/~nedkonz/Algorithm-Diff-1.15/ diff --git a/vendor/gems/diff-lcs-1.1.2/Rakefile b/vendor/gems/diff-lcs-1.1.2/Rakefile new file mode 100644 index 0000000..774d435 --- /dev/null +++ b/vendor/gems/diff-lcs-1.1.2/Rakefile @@ -0,0 +1,116 @@ +#! /usr/bin/env rake +$LOAD_PATH.unshift('lib') + +require 'rubygems' +require 'rake/gempackagetask' +require 'rake/contrib/rubyforgepublisher' +require 'diff/lcs' +require 'archive/tar/minitar' +require 'zlib' + +DISTDIR = "diff-lcs-#{Diff::LCS::VERSION}" +TARDIST = "../#{DISTDIR}.tar.gz" + +DATE_RE = %r<(\d{4})[./-]?(\d{2})[./-]?(\d{2})(?:[\sT]?(\d{2})[:.]?(\d{2})[:.]?(\d{2})?)?> + +if ENV['RELEASE_DATE'] + year, month, day, hour, minute, second = DATE_RE.match(ENV['RELEASE_DATE']).captures + year ||= 0 + month ||= 0 + day ||= 0 + hour ||= 0 + minute ||= 0 + second ||= 0 + ReleaseDate = Time.mktime(year, month, day, hour, minute, second) +else + ReleaseDate = nil +end + +task :test do |t| + require 'test/unit/testsuite' + require 'test/unit/ui/console/testrunner' + + runner = Test::Unit::UI::Console::TestRunner + + $LOAD_PATH.unshift('tests') + $stderr.puts "Checking for test cases:" if t.verbose + Dir['tests/*test*.rb'].each do |testcase| + $stderr.puts "\t#{testcase}" if t.verbose + load testcase + end + + suite = Test::Unit::TestSuite.new + + ObjectSpace.each_object(Class) do |testcase| + suite << testcase.suite if testcase < Test::Unit::TestCase + end + + runner.run(suite) +end + +spec = eval(File.read("diff-lcs.gemspec")) +desc "Build the RubyGem for Diff::LCS." +task :gem => [ :test ] +Rake::GemPackageTask.new(spec) do |g| + g.need_tar = false + g.need_zip = false + g.package_dir = ".." +end + +desc "Build an Diff::LCS .tar.gz distribution." +task :tar => [ TARDIST ] +file TARDIST => [ :test ] do |t| + current = File.basename(Dir.pwd) + Dir.chdir("..") do + begin + files = Dir["#{current}/**/*"].select { |dd| dd !~ %r{(?:/CVS/?|~$)} } + files.map! do |dd| + ddnew = dd.gsub(/^#{current}/, DISTDIR) + mtime = ReleaseDate || File.stat(dd).mtime + if File.directory?(dd) + { :name => ddnew, :mode => 0755, :dir => true, :mtime => mtime } + else + if dd =~ %r{bin/} + mode = 0755 + else + mode = 0644 + end + data = File.read(dd) + { :name => ddnew, :mode => mode, :data => data, :size => data.size, + :mtime => mtime } + end + end + + ff = File.open(t.name.gsub(%r{^\.\./}o, ''), "wb") + gz = Zlib::GzipWriter.new(ff) + tw = Archive::Tar::Minitar::Writer.new(gz) + + files.each do |entry| + if entry[:dir] + tw.mkdir(entry[:name], entry) + else + tw.add_file_simple(entry[:name], entry) { |os| os.write(entry[:data]) } + end + end + ensure + tw.close if tw + gz.close if gz + end + end +end +task TARDIST => [ :test ] + +def sign(file) + sh %("C:\\Program Files\\Windows Privacy Tools\\GnuPG\\Gpg.exe" -ba #{file}) rescue nil +end + +task :signtar => [ :tar ] do + sign TARDIST +end +task :signgem => [ :gem ] do + sign "../#{DISTDIR}.gem" +end + +desc "Build everything." +task :default => [ :signtar, :signgem ] do +end diff --git a/vendor/gems/diff-lcs-1.1.2/bin/htmldiff b/vendor/gems/diff-lcs-1.1.2/bin/htmldiff new file mode 100755 index 0000000..3d4953f --- /dev/null +++ b/vendor/gems/diff-lcs-1.1.2/bin/htmldiff @@ -0,0 +1,112 @@ +#!/usr/bin/env ruby +#-- +# Copyright 2004 Austin Ziegler +# adapted from: +# Algorithm::Diff (Perl) by Ned Konz +# Smalltalk by Mario I. Wolczko +# implements McIlroy-Hunt diff algorithm +# +# This program is free software. It may be redistributed and/or modified under +# the terms of the GPL version 2 (or later), the Perl Artistic licence, or the +# Ruby licence. +# +# $Id: htmldiff,v 1.6 2004/10/17 19:33:21 austin Exp $ +#++ + +begin + require 'rubygems' + require_gem 'diff-lcs', "1.1.1" + require 'diff/lcs/string' +rescue LoadError + require 'diff/lcs' + require 'diff/lcs/string' +end + +require 'text/format' + +class HTMLDiff #:nodoc: + attr_accessor :output + + def initialize(output) + @output = output + end + + # This will be called with both lines are the same + def match(event) + @output << %Q|
#{event.old_element}
\n| + end + + # This will be called when there is a line in A that isn't in B + def discard_a(event) + @output << %Q|
#{event.old_element}
\n| + end + + # This will be called when there is a line in B that isn't in A + def discard_b(event) + @output << %Q|
#{event.new_element}
\n| + end +end + +if ARGV.size != 2 + puts "usage: #{File.basename($0)} old new > output.html" + exit 255 +end + +hd = HTMLDiff.new($stdout) +tf = Text::Format.new +tf.tabstop = 4 + +preprocess = lambda { |line| tf.expand(line.chomp) } + +a = IO.readlines(ARGV[0]).map(&preprocess) +b = IO.readlines(ARGV[1]).map(&preprocess) + +$stdout.write <<-START + + + diff #{ARGV[0]} #{ARGV[1]} + + + +

diff  + #{ARGV[0]}  + #{ARGV[1]} +

+
+START + +Diff::LCS.traverse_sequences(a, b, hd) + +$stdout.write <<-END +
+ + +END diff --git a/vendor/gems/diff-lcs-1.1.2/bin/ldiff b/vendor/gems/diff-lcs-1.1.2/bin/ldiff new file mode 100755 index 0000000..4437ba5 --- /dev/null +++ b/vendor/gems/diff-lcs-1.1.2/bin/ldiff @@ -0,0 +1,45 @@ +#!/usr/bin/env ruby +#-- +# Copyright 2004 Austin Ziegler +# adapted from: +# Algorithm::Diff (Perl) by Ned Konz +# Smalltalk by Mario I. Wolczko +# implements McIlroy-Hunt diff algorithm +# +# This program is free software. It may be redistributed and/or modified under +# the terms of the GPL version 2 (or later), the Perl Artistic licence, or the +# Ruby licence. +# +# $Id: ldiff,v 1.6 2004/09/26 01:35:57 austin Exp $ +#++ + + # 1) Try to load Ruwiki from the gem. + # 2) Try to load Ruwiki from $LOAD_PATH. + # 3) Modify $LOAD_PATH and try to load it from the modified $LOAD_PATH. + # 4) Fail hard. +load_state = 1 + begin + if 1 == load_state + require 'rubygems' + require_gem 'diff-lcs', '= 1.1.1' + else + require 'diff/lcs' + end + rescue LoadError + load_state += 1 + + case load_state + when 3 + $LOAD_PATH.unshift "#{File.dirname($0)}/../lib" + when 4 + $LOAD_PATH.shift + $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib" + when 5 + raise + end + retry + end + +require 'diff/lcs/ldiff' + +exit Diff::LCS::Ldiff.run(ARGV) diff --git a/vendor/gems/diff-lcs-1.1.2/diff-lcs.gemspec b/vendor/gems/diff-lcs-1.1.2/diff-lcs.gemspec new file mode 100644 index 0000000..ba49ed6 --- /dev/null +++ b/vendor/gems/diff-lcs-1.1.2/diff-lcs.gemspec @@ -0,0 +1,40 @@ +Gem::Specification.new do |s| + s.name = %{diff-lcs} + s.version = %{1.1.2} + s.author = %{Austin Ziegler} + s.email = %{diff-lcs@halostatue.ca} + s.homepage = %{http://rubyforge.org/projects/ruwiki/} + s.rubyforge_project = %{ruwiki} + + s.files = Dir.glob("**/*").delete_if do |item| + item.include?("CVS") or item.include?(".svn") or + item == "install.rb" or item =~ /~$/ or + item =~ /gem(?:spec)?$/ + end + + s.summary = %{Provides a list of changes that represent the difference between two sequenced collections.} + + s.required_ruby_version = %(>=1.8.1) + + s.executables = %w(ldiff htmldiff) + s.bindir = %(bin) + + s.test_files = %w{tests/00test.rb} + + s.autorequire = %{diff/lcs} + s.require_paths = %w{lib} + + description = [] + File.open("README") do |file| + file.each do |line| + line.chomp! + break if line.empty? + description << "#{line.gsub(/\[\d\]/, '')}" + end + end + s.description = description[2..-1].join(" ") + + s.has_rdoc = true + s.rdoc_options = ["--title", "Diff::LCS -- A Diff Algorithm", "--main", "README", "--line-numbers"] + s.extra_rdoc_files = %w(README ChangeLog Install) +end diff --git a/vendor/gems/diff-lcs-1.1.2/install.rb b/vendor/gems/diff-lcs-1.1.2/install.rb new file mode 100644 index 0000000..afa6cb2 --- /dev/null +++ b/vendor/gems/diff-lcs-1.1.2/install.rb @@ -0,0 +1,262 @@ +#! /usr/bin/env ruby +#-- +# Copyright 2004 Austin Ziegler +# Install utility. Based on the original installation script for rdoc by the +# Pragmatic Programmers. +# +# This program is free software. It may be redistributed and/or modified under +# the terms of the GPL version 2 (or later) or the Ruby licence. +# +# Usage +# ----- +# In most cases, if you have a typical project layout, you will need to do +# absolutely nothing to make this work for you. This layout is: +# +# bin/ # executable files -- "commands" +# lib/ # the source of the library +# tests/ # unit tests +# +# The default behaviour: +# 1) Run all unit test files (ending in .rb) found in all directories under +# tests/. +# 2) Build Rdoc documentation from all files in bin/ (excluding .bat and .cmd), +# all .rb files in lib/, ./README, ./ChangeLog, and ./Install. +# 3) Build ri documentation from all files in bin/ (excluding .bat and .cmd), +# and all .rb files in lib/. This is disabled by default on Win32. +# 4) Install commands from bin/ into the Ruby bin directory. On Windows, if a +# if a corresponding batch file (.bat or .cmd) exists in the bin directory, +# it will be copied over as well. Otherwise, a batch file (always .bat) will +# be created to run the specified command. +# 5) Install all library files ending in .rb from lib/ into Ruby's +# site_lib/version directory. +# +# $Id: install.rb,v 1.9 2004/09/22 16:13:15 austin Exp $ +#++ + +require 'rbconfig' +require 'find' +require 'fileutils' +require 'rdoc/rdoc' +require 'optparse' +require 'ostruct' + +InstallOptions = OpenStruct.new + +def glob(list) + g = list.map { |i| Dir.glob(i) } + g.flatten! + g.compact! + g.reject! { |e| e =~ /CVS/ } + g +end + + # Set these values to what you want installed. +bins = glob(%w{bin/**/*}).reject { |e| e =~ /\.(bat|cmd)$/ } +rdoc = glob(%w{bin/**/* lib/**/*.rb README ChangeLog Install}).reject { |e| e=~ /\.(bat|cmd)$/ } +ri = glob(%w(bin/**/*.rb lib/**/*.rb)).reject { |e| e=~ /\.(bat|cmd)$/ } +libs = glob(%w{lib/**/*.rb}) +tests = glob(%w{tests/**/*.rb}) + +def do_bins(bins, target, strip = 'bin/') + bins.each do |bf| + obf = bf.gsub(/#{strip}/, '') + install_binfile(bf, obf, target) + end +end + +def do_libs(libs, strip = 'lib/') + libs.each do |lf| + olf = File.join(InstallOptions.site_dir, lf.gsub(/#{strip}/, '')) + op = File.dirname(olf) + File.makedirs(op, true) + File.chmod(0755, op) + File.install(lf, olf, 0755, true) + end +end + +## +# Prepare the file installation. +# +def prepare_installation + InstallOptions.rdoc = true + if RUBY_PLATFORM == "i386-mswin32" + InstallOptions.ri = false + else + InstallOptions.ri = true + end + InstallOptions.tests = true + + ARGV.options do |opts| + opts.banner = "Usage: #{File.basename($0)} [options]" + opts.separator "" + opts.on('--[no-]rdoc', 'Prevents the creation of RDoc output.', 'Default on.') do |onrdoc| + InstallOptions.rdoc = onrdoc + end + opts.on('--[no-]ri', 'Prevents the creation of RI output.', 'Default off on mswin32.') do |onri| + InstallOptions.ri = onri + end + opts.on('--[no-]tests', 'Prevents the execution of unit tests.', 'Default on.') do |ontest| + InstallOptions.tests = ontest + end + opts.on('--quick', 'Performs a quick installation. Only the', 'installation is done.') do |quick| + InstallOptions.rdoc = false + InstallOptions.ri = false + InstallOptions.tests = false + end + opts.on('--full', 'Performs a full installation. All', 'optional installation steps are run.') do |full| + InstallOptions.rdoc = true + InstallOptions.ri = true + InstallOptions.tests = true + end + opts.separator("") + opts.on_tail('--help', "Shows this help text.") do + $stderr.puts opts + exit + end + + opts.parse! + end + + bds = [".", ENV['TMP'], ENV['TEMP']] + + version = [Config::CONFIG["MAJOR"], Config::CONFIG["MINOR"]].join(".") + ld = File.join(Config::CONFIG["libdir"], "ruby", version) + + sd = Config::CONFIG["sitelibdir"] + if sd.nil? + sd = $:.find { |x| x =~ /site_ruby/ } + if sd.nil? + sd = File.join(ld, "site_ruby") + elsif sd !~ Regexp.quote(version) + sd = File.join(sd, version) + end + end + + if (destdir = ENV['DESTDIR']) + bd = "#{destdir}#{Config::CONFIG['bindir']}" + sd = "#{destdir}#{sd}" + bds << bd + + FileUtils.makedirs(bd) + FileUtils.makedirs(sd) + else + bds << Config::CONFIG['bindir'] + end + + InstallOptions.bin_dirs = bds.compact + InstallOptions.site_dir = sd + InstallOptions.bin_dir = bd + InstallOptions.lib_dir = ld +end + +## +# Build the rdoc documentation. Also, try to build the RI documentation. +# +def build_rdoc(files) + r = RDoc::RDoc.new + r.document(["--main", "README", "--title", "Diff::LCS -- A Diff Algorithm", + "--line-numbers"] + files) + +rescue RDoc::RDocError => e + $stderr.puts e.message +rescue Exception => e + $stderr.puts "Couldn't build RDoc documentation\n#{e.message}" +end + +def build_ri(files) + ri = RDoc::RDoc.new + ri.document(["--ri-site", "--merge"] + files) +rescue RDoc::RDocError => e + $stderr.puts e.message +rescue Exception => e + $stderr.puts "Couldn't build Ri documentation\n#{e.message}" +end + +def run_tests(test_list) + require 'test/unit/ui/console/testrunner' + $:.unshift "lib" + test_list.each do |test| + next if File.directory?(test) + require test + end + + tests = Test::Unit::TestSuite.new + ObjectSpace.each_object(Class) { |o| tests << o.suite if o < Test::Unit::TestCase } + + Test::Unit::UI::Console::TestRunner.run(tests) + $:.shift +end + +## +# Install file(s) from ./bin to Config::CONFIG['bindir']. Patch it on the way +# to insert a #! line; on a Unix install, the command is named as expected +# (e.g., bin/rdoc becomes rdoc); the shebang line handles running it. Under +# windows, we add an '.rb' extension and let file associations do their stuff. +def install_binfile(from, op_file, target) + tmp_dir = nil + InstallOptions.bin_dirs.each do |t| + if File.directory?(t) and File.writable?(t) + tmp_dir = t + break + end + end + + fail "Cannot find a temporary directory" unless tmp_dir + tmp_file = File.join(tmp_dir, '_tmp') + ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) + + File.open(from) do |ip| + File.open(tmp_file, "w") do |op| + ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) + op.puts "#!#{ruby}" + op.write ip.read + end + end + + if Config::CONFIG["target_os"] =~ /win/io + installed_wrapper = false + + if File.exists?("#{from}.bat") + FileUtils.install("#{from}.bat", File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) + installed_wrapper = true + end + + if File.exists?("#{from}.cmd") + FileUtils.install("#{from}.cmd", File.join(target, "#{op_file}.cmd"), :mode => 0755, :verbose => true) + installed_wrapper = true + end + + if not installed_wrapper + tmp_file2 = File.join(tmp_dir, '_tmp_wrapper') + cwn = File.join(Config::CONFIG['bindir'], op_file) + cwv = CMD_WRAPPER.gsub('', ruby.gsub(%r{/}) { "\\" }).gsub!('', cwn.gsub(%r{/}) { "\\" } ) + + File.open(tmp_file2, "wb") { |cw| cw.puts cwv } + FileUtils.install(tmp_file2, File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) + + File.unlink(tmp_file2) + installed_wrapper = true + end + end + FileUtils.install(tmp_file, File.join(target, op_file), :mode => 0755, :verbose => true) + File.unlink(tmp_file) +end + +CMD_WRAPPER = <<-EOS +@echo off +if "%OS%"=="Windows_NT" goto WinNT + -x "" %1 %2 %3 %4 %5 %6 %7 %8 %9 +goto done +:WinNT + -x "" %* +goto done +:done +EOS + +prepare_installation + +run_tests(tests) if InstallOptions.tests +build_rdoc(rdoc) if InstallOptions.rdoc +build_ri(ri) if InstallOptions.ri +do_bins(bins, Config::CONFIG['bindir']) +do_libs(libs) diff --git a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs.rb b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs.rb new file mode 100644 index 0000000..92c22f1 --- /dev/null +++ b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs.rb @@ -0,0 +1,1106 @@ +#! /usr/env/bin ruby +#-- +# Copyright 2004 Austin Ziegler +# adapted from: +# Algorithm::Diff (Perl) by Ned Konz +# Smalltalk by Mario I. Wolczko +# implements McIlroy-Hunt diff algorithm +# +# This program is free software. It may be redistributed and/or modified +# under the terms of the GPL version 2 (or later), the Perl Artistic +# licence, or the Ruby licence. +# +# $Id: lcs.rb,v 1.9 2004/10/17 20:31:10 austin Exp $ +#++ +module LCSDiff + module Diff + # = Diff::LCS 1.1.2 + # Computes "intelligent" differences between two sequenced Enumerables. + # This is an implementation of the McIlroy-Hunt "diff" algorithm for + # Enumerable objects that include Diffable. + # + # Based on Mario I. Wolczko's Smalltalk version + # (1.2, 1993) and Ned Konz's Perl version + # (Algorithm::Diff). + # + # == Synopsis + # require 'diff/lcs' + # + # seq1 = %w(a b c e h j l m n p) + # seq2 = %w(b c d e f j k l m r s t) + # + # lcs = Diff::LCS.LCS(seq1, seq2) + # diffs = Diff::LCS.diff(seq1, seq2) + # sdiff = Diff::LCS.sdiff(seq1, seq2) + # seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) + # bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) + # seq2 == Diff::LCS.patch(seq1, diffs) + # seq2 == Diff::LCS.patch!(seq1, diffs) + # seq1 == Diff::LCS.unpatch(seq2, diffs) + # seq1 == Diff::LCS.unpatch!(seq2, diffs) + # seq2 == Diff::LCS.patch(seq1, sdiff) + # seq2 == Diff::LCS.patch!(seq1, sdiff) + # seq1 == Diff::LCS.unpatch(seq2, sdiff) + # seq1 == Diff::LCS.unpatch!(seq2, sdiff) + # + # Alternatively, objects can be extended with Diff::LCS: + # + # seq1.extend(Diff::LCS) + # lcs = seq1.lcs(seq2) + # diffs = seq1.diff(seq2) + # sdiff = seq1.sdiff(seq2) + # seq = seq1.traverse_sequences(seq2, callback_obj) + # bal = seq1.traverse_balanced(seq2, callback_obj) + # seq2 == seq1.patch(diffs) + # seq2 == seq1.patch!(diffs) + # seq1 == seq2.unpatch(diffs) + # seq1 == seq2.unpatch!(diffs) + # seq2 == seq1.patch(sdiff) + # seq2 == seq1.patch!(sdiff) + # seq1 == seq2.unpatch(sdiff) + # seq1 == seq2.unpatch!(sdiff) + # + # Default extensions are provided for Array and String objects through + # the use of 'diff/lcs/array' and 'diff/lcs/string'. + # + # == Introduction (by Mark-Jason Dominus) + # + # The following text is from the Perl documentation. The only + # changes have been to make the text appear better in Rdoc. + # + # I once read an article written by the authors of +diff+; they said + # that they hard worked very hard on the algorithm until they found the + # right one. + # + # I think what they ended up using (and I hope someone will correct me, + # because I am not very confident about this) was the `longest common + # subsequence' method. In the LCS problem, you have two sequences of + # items: + # + # a b c d f g h j q z + # a b c d e f g i j k r x y z + # + # and you want to find the longest sequence of items that is present in + # both original sequences in the same order. That is, you want to find a + # new sequence *S* which can be obtained from the first sequence by + # deleting some items, and from the second sequence by deleting other + # items. You also want *S* to be as long as possible. In this case *S* + # is: + # + # a b c d f g j z + # + # From there it's only a small step to get diff-like output: + # + # e h i k q r x y + # + - + + - + + + + # + # This module solves the LCS problem. It also includes a canned function + # to generate +diff+-like output. + # + # It might seem from the example above that the LCS of two sequences is + # always pretty obvious, but that's not always the case, especially when + # the two sequences have many repeated elements. For example, consider + # + # a x b y c z p d q + # a b c a x b y c z + # + # A naive approach might start by matching up the +a+ and +b+ that + # appear at the beginning of each sequence, like this: + # + # a x b y c z p d q + # a b c a b y c z + # + # This finds the common subsequence +a b c z+. But actually, the LCS is + # +a x b y c z+: + # + # a x b y c z p d q + # a b c a x b y c z + # + # == Author + # This version is by Austin Ziegler . + # + # It is based on the Perl Algorithm::Diff by Ned Konz + # , copyright © 2000 - 2002 and the Smalltalk + # diff version by Mario I. Wolczko , copyright © + # 1993. Documentation includes work by Mark-Jason Dominus. + # + # == Licence + # Copyright © 2004 Austin Ziegler + # This program is free software; you can redistribute it and/or modify it + # under the same terms as Ruby, or alternatively under the Perl Artistic + # licence. + # + # == Credits + # Much of the documentation is taken directly from the Perl + # Algorithm::Diff implementation and was written originally by Mark-Jason + # Dominus and later by Ned Konz. The basic Ruby + # implementation was re-ported from the Smalltalk implementation, available + # at ftp://st.cs.uiuc.edu/pub/Smalltalk/MANCHESTER/manchester/4.0/diff.st + # + # #sdiff and #traverse_balanced were written for the Perl version by Mike + # Schilli . + # + # "The algorithm is described in A Fast Algorithm for Computing Longest + # Common Subsequences, CACM, vol.20, no.5, pp.350-353, May 1977, with + # a few minor improvements to improve the speed." + module LCS + VERSION = '1.1.2' + end + end + + require 'diff/lcs/callbacks' + + module Diff::LCS + # Returns an Array containing the longest common subsequence(s) between + # +self+ and +other+. See Diff::LCS#LCS. + # + # lcs = seq1.lcs(seq2) + def lcs(other, &block) #:yields self[ii] if there are matched subsequences: + Diff::LCS.LCS(self, other, &block) + end + + # Returns the difference set between +self+ and +other+. See + # Diff::LCS#diff. + def diff(other, callbacks = nil, &block) + Diff::LCS::diff(self, other, callbacks, &block) + end + + # Returns the balanced ("side-by-side") difference set between +self+ and + # +other+. See Diff::LCS#sdiff. + def sdiff(other, callbacks = nil, &block) + Diff::LCS::sdiff(self, other, callbacks, &block) + end + + # Traverses the discovered longest common subsequences between +self+ and + # +other+. See Diff::LCS#traverse_sequences. + def traverse_sequences(other, callbacks = nil, &block) + traverse_sequences(self, other, callbacks || Diff::LCS::YieldingCallbacks, + &block) + end + + # Traverses the discovered longest common subsequences between +self+ and + # +other+ using the alternate, balanced algorithm. See + # Diff::LCS#traverse_balanced. + def traverse_balanced(other, callbacks = nil, &block) + traverse_balanced(self, other, callbacks || Diff::LCS::YieldingCallbacks, + &block) + end + + # Attempts to patch a copy of +self+ with the provided +patchset+. See + # Diff::LCS#patch. + def patch(patchset) + Diff::LCS::patch(self.dup, patchset) + end + + # Attempts to unpatch a copy of +self+ with the provided +patchset+. + # See Diff::LCS#patch. + def unpatch(patchset) + Diff::LCS::unpatch(self.dup, patchset) + end + + # Attempts to patch +self+ with the provided +patchset+. See + # Diff::LCS#patch!. Does no autodiscovery. + def patch!(patchset) + Diff::LCS::patch!(self, patchset) + end + + # Attempts to unpatch +self+ with the provided +patchset+. See + # Diff::LCS#unpatch. Does no autodiscovery. + def unpatch!(patchset) + Diff::LCS::unpatch!(self, patchset) + end + end + + module Diff::LCS + class << self + # Given two sequenced Enumerables, LCS returns an Array containing their + # longest common subsequences. + # + # lcs = Diff::LCS.LCS(seq1, seq2) + # + # This array whose contents is such that: + # + # lcs.each_with_index do |ee, ii| + # assert(ee.nil? || (seq1[ii] == seq2[ee])) + # end + # + # If a block is provided, the matching subsequences will be yielded from + # +seq1+ in turn and may be modified before they are placed into the + # returned Array of subsequences. + def LCS(seq1, seq2, &block) #:yields seq1[ii] for each matched: + matches = Diff::LCS.__lcs(seq1, seq2) + ret = [] + matches.each_with_index do |ee, ii| + unless matches[ii].nil? + if block_given? + ret << (yield seq1[ii]) + else + ret << seq1[ii] + end + end + end + ret + end + + # Diff::LCS.diff computes the smallest set of additions and deletions + # necessary to turn the first sequence into the second, and returns a + # description of these changes. + # + # See Diff::LCS::DiffCallbacks for the default behaviour. An alternate + # behaviour may be implemented with Diff::LCS::ContextDiffCallbacks. + # If a Class argument is provided for +callbacks+, #diff will attempt + # to initialise it. If the +callbacks+ object (possibly initialised) + # responds to #finish, it will be called. + def diff(seq1, seq2, callbacks = nil, &block) # :yields diff changes: + callbacks ||= Diff::LCS::DiffCallbacks + if callbacks.kind_of?(Class) + cb = callbacks.new rescue callbacks + callbacks = cb + end + traverse_sequences(seq1, seq2, callbacks) + callbacks.finish if callbacks.respond_to?(:finish) + + if block_given? + res = callbacks.diffs.map do |hunk| + if hunk.kind_of?(Array) + hunk = hunk.map { |block| yield block } + else + yield hunk + end + end + res + else + callbacks.diffs + end + end + + # Diff::LCS.sdiff computes all necessary components to show two sequences + # and their minimized differences side by side, just like the Unix + # utility sdiff does: + # + # old < - + # same same + # before | after + # - > new + # + # See Diff::LCS::SDiffCallbacks for the default behaviour. An alternate + # behaviour may be implemented with Diff::LCS::ContextDiffCallbacks. If + # a Class argument is provided for +callbacks+, #diff will attempt to + # initialise it. If the +callbacks+ object (possibly initialised) + # responds to #finish, it will be called. + def sdiff(seq1, seq2, callbacks = nil, &block) #:yields diff changes: + callbacks ||= Diff::LCS::SDiffCallbacks + if callbacks.kind_of?(Class) + cb = callbacks.new rescue callbacks + callbacks = cb + end + traverse_balanced(seq1, seq2, callbacks) + callbacks.finish if callbacks.respond_to?(:finish) + + if block_given? + res = callbacks.diffs.map do |hunk| + if hunk.kind_of?(Array) + hunk = hunk.map { |block| yield block } + else + yield hunk + end + end + res + else + callbacks.diffs + end + end + + # Diff::LCS.traverse_sequences is the most general facility provided by this + # module; +diff+ and +LCS+ are implemented as calls to it. + # + # The arguments to #traverse_sequences are the two sequences to + # traverse, and a callback object, like this: + # + # traverse_sequences(seq1, seq2, Diff::LCS::ContextDiffCallbacks.new) + # + # #diff is implemented with #traverse_sequences. + # + # == Callback Methods + # Optional callback methods are emphasized. + # + # callbacks#match:: Called when +a+ and +b+ are pointing + # to common elements in +A+ and +B+. + # callbacks#discard_a:: Called when +a+ is pointing to an + # element not in +B+. + # callbacks#discard_b:: Called when +b+ is pointing to an + # element not in +A+. + # callbacks#finished_a:: Called when +a+ has reached the end of + # sequence +A+. + # callbacks#finished_b:: Called when +b+ has reached the end of + # sequence +B+. + # + # == Algorithm + # a---+ + # v + # A = a b c e h j l m n p + # B = b c d e f j k l m r s t + # ^ + # b---+ + # + # If there are two arrows (+a+ and +b+) pointing to elements of + # sequences +A+ and +B+, the arrows will initially point to the first + # elements of their respective sequences. #traverse_sequences will + # advance the arrows through the sequences one element at a time, + # calling a method on the user-specified callback object before each + # advance. It will advance the arrows in such a way that if there are + # elements A[ii] and B[jj] which are both equal and + # part of the longest common subsequence, there will be some moment + # during the execution of #traverse_sequences when arrow +a+ is pointing + # to A[ii] and arrow +b+ is pointing to B[jj]. When + # this happens, #traverse_sequences will call callbacks#match + # and then it will advance both arrows. + # + # Otherwise, one of the arrows is pointing to an element of its sequence + # that is not part of the longest common subsequence. + # #traverse_sequences will advance that arrow and will call + # callbacks#discard_a or callbacks#discard_b, depending + # on which arrow it advanced. If both arrows point to elements that are + # not part of the longest common subsequence, then #traverse_sequences + # will advance one of them and call the appropriate callback, but it is + # not specified which it will call. + # + # The methods for callbacks#match, callbacks#discard_a, + # and callbacks#discard_b are invoked with an event comprising + # the action ("=", "+", or "-", respectively), the indicies +ii+ and + # +jj+, and the elements A[ii] and B[jj]. Return + # values are discarded by #traverse_sequences. + # + # === End of Sequences + # If arrow +a+ reaches the end of its sequence before arrow +b+ does, + # #traverse_sequence try to call callbacks#finished_a with the + # last index and element of +A+ (A[-1]) and the current index + # and element of +B+ (B[jj]). If callbacks#finished_a + # does not exist, then callbacks#discard_b will be called on + # each element of +B+ until the end of the sequence is reached (the call + # will be done with A[-1] and B[jj] for each element). + # + # If +b+ reaches the end of +B+ before +a+ reaches the end of +A+, + # callbacks#finished_b will be called with the current index + # and element of +A+ (A[ii]) and the last index and element of + # +B+ (A[-1]). Again, if callbacks#finished_b does not + # exist on the callback object, then callbacks#discard_a will + # be called on each element of +A+ until the end of the sequence is + # reached (A[ii] and B[-1]). + # + # There is a chance that one additional callbacks#discard_a or + # callbacks#discard_b will be called after the end of the + # sequence is reached, if +a+ has not yet reached the end of +A+ or +b+ + # has not yet reached the end of +B+. + def traverse_sequences(seq1, seq2, callbacks = Diff::LCS::SequenceCallbacks, &block) #:yields change events: + matches = Diff::LCS.__lcs(seq1, seq2) + + run_finished_a = run_finished_b = false + string = seq1.kind_of?(String) + + a_size = seq1.size + b_size = seq2.size + ai = bj = 0 + + (0 .. matches.size).each do |ii| + b_line = matches[ii] + + ax = string ? seq1[ii, 1] : seq1[ii] + bx = string ? seq2[bj, 1] : seq2[bj] + + if b_line.nil? + unless ax.nil? + event = Diff::LCS::ContextChange.new('-', ii, ax, bj, bx) + event = yield event if block_given? + callbacks.discard_a(event) + end + else + loop do + break unless bj < b_line + bx = string ? seq2[bj, 1] : seq2[bj] + event = Diff::LCS::ContextChange.new('+', ii, ax, bj, bx) + event = yield event if block_given? + callbacks.discard_b(event) + bj += 1 + end + bx = string ? seq2[bj, 1] : seq2[bj] + event = Diff::LCS::ContextChange.new('=', ii, ax, bj, bx) + event = yield event if block_given? + callbacks.match(event) + bj += 1 + end + ai = ii + end + ai += 1 + + # The last entry (if any) processed was a match. +ai+ and +bj+ point + # just past the last matching lines in their sequences. + while (ai < a_size) or (bj < b_size) + # last A? + if ai == a_size and bj < b_size + if callbacks.respond_to?(:finished_a) and not run_finished_a + ax = string ? seq1[-1, 1] : seq1[-1] + bx = string ? seq2[bj, 1] : seq2[bj] + event = Diff::LCS::ContextChange.new('>', (a_size - 1), ax, bj, bx) + event = yield event if block_given? + callbacks.finished_a(event) + run_finished_a = true + else + ax = string ? seq1[ai, 1] : seq1[ai] + loop do + bx = string ? seq2[bj, 1] : seq2[bj] + event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) + event = yield event if block_given? + callbacks.discard_b(event) + bj += 1 + break unless bj < b_size + end + end + end + + # last B? + if bj == b_size and ai < a_size + if callbacks.respond_to?(:finished_b) and not run_finished_b + ax = string ? seq1[ai, 1] : seq1[ai] + bx = string ? seq2[-1, 1] : seq2[-1] + event = Diff::LCS::ContextChange.new('<', ai, ax, (b_size - 1), bx) + event = yield event if block_given? + callbacks.finished_b(event) + run_finished_b = true + else + bx = string ? seq2[bj, 1] : seq2[bj] + loop do + ax = string ? seq1[ai, 1] : seq1[ai] + event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) + event = yield event if block_given? + callbacks.discard_a(event) + ai += 1 + break unless bj < b_size + end + end + end + + if ai < a_size + ax = string ? seq1[ai, 1] : seq1[ai] + bx = string ? seq2[bj, 1] : seq2[bj] + event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) + event = yield event if block_given? + callbacks.discard_a(event) + ai += 1 + end + + if bj < b_size + ax = string ? seq1[ai, 1] : seq1[ai] + bx = string ? seq2[bj, 1] : seq2[bj] + event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) + event = yield event if block_given? + callbacks.discard_b(event) + bj += 1 + end + end + end + + # #traverse_balanced is an alternative to #traverse_sequences. It + # uses a different algorithm to iterate through the entries in the + # computed longest common subsequence. Instead of viewing the changes as + # insertions or deletions from one of the sequences, #traverse_balanced + # will report changes between the sequences. To represent a + # + # The arguments to #traverse_balanced are the two sequences to traverse + # and a callback object, like this: + # + # traverse_balanced(seq1, seq2, Diff::LCS::ContextDiffCallbacks.new) + # + # #sdiff is implemented with #traverse_balanced. + # + # == Callback Methods + # Optional callback methods are emphasized. + # + # callbacks#match:: Called when +a+ and +b+ are pointing + # to common elements in +A+ and +B+. + # callbacks#discard_a:: Called when +a+ is pointing to an + # element not in +B+. + # callbacks#discard_b:: Called when +b+ is pointing to an + # element not in +A+. + # callbacks#change:: Called when +a+ and +b+ are pointing + # to the same relative position, but + # A[a] and B[b] are + # not the same; a change has + # occurred. + # + # #traverse_balanced might be a bit slower than #traverse_sequences, + # noticable only while processing huge amounts of data. + # + # The +sdiff+ function of this module is implemented as call to + # #traverse_balanced. + # + # == Algorithm + # a---+ + # v + # A = a b c e h j l m n p + # B = b c d e f j k l m r s t + # ^ + # b---+ + # + # === Matches + # If there are two arrows (+a+ and +b+) pointing to elements of + # sequences +A+ and +B+, the arrows will initially point to the first + # elements of their respective sequences. #traverse_sequences will + # advance the arrows through the sequences one element at a time, + # calling a method on the user-specified callback object before each + # advance. It will advance the arrows in such a way that if there are + # elements A[ii] and B[jj] which are both equal and + # part of the longest common subsequence, there will be some moment + # during the execution of #traverse_sequences when arrow +a+ is pointing + # to A[ii] and arrow +b+ is pointing to B[jj]. When + # this happens, #traverse_sequences will call callbacks#match + # and then it will advance both arrows. + # + # === Discards + # Otherwise, one of the arrows is pointing to an element of its sequence + # that is not part of the longest common subsequence. + # #traverse_sequences will advance that arrow and will call + # callbacks#discard_a or callbacks#discard_b, + # depending on which arrow it advanced. + # + # === Changes + # If both +a+ and +b+ point to elements that are not part of the longest + # common subsequence, then #traverse_sequences will try to call + # callbacks#change and advance both arrows. If + # callbacks#change is not implemented, then + # callbacks#discard_a and callbacks#discard_b will be + # called in turn. + # + # The methods for callbacks#match, callbacks#discard_a, + # callbacks#discard_b, and callbacks#change are + # invoked with an event comprising the action ("=", "+", "-", or "!", + # respectively), the indicies +ii+ and +jj+, and the elements + # A[ii] and B[jj]. Return values are discarded by + # #traverse_balanced. + # + # === Context + # Note that +ii+ and +jj+ may not be the same index position, even if + # +a+ and +b+ are considered to be pointing to matching or changed + # elements. + def traverse_balanced(seq1, seq2, callbacks = Diff::LCS::BalancedCallbacks) + matches = Diff::LCS.__lcs(seq1, seq2) + a_size = seq1.size + b_size = seq2.size + ai = bj = mb = 0 + ma = -1 + string = seq1.kind_of?(String) + + # Process all the lines in the match vector. + loop do + # Find next match indices +ma+ and +mb+ + loop do + ma += 1 + break unless ma < matches.size and matches[ma].nil? + end + + break if ma >= matches.size # end of matches? + mb = matches[ma] + + # Change(seq2) + while (ai < ma) or (bj < mb) + ax = string ? seq1[ai, 1] : seq1[ai] + bx = string ? seq2[bj, 1] : seq2[bj] + + case [(ai < ma), (bj < mb)] + when [true, true] + if callbacks.respond_to?(:change) + event = Diff::LCS::ContextChange.new('!', ai, ax, bj, bx) + event = yield event if block_given? + callbacks.change(event) + ai += 1 + bj += 1 + else + event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) + event = yield event if block_given? + callbacks.discard_a(event) + ai += 1 + ax = string ? seq1[ai, 1] : seq1[ai] + event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) + event = yield event if block_given? + callbacks.discard_b(event) + bj += 1 + end + when [true, false] + event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) + event = yield event if block_given? + callbacks.discard_a(event) + ai += 1 + when [false, true] + event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) + event = yield event if block_given? + callbacks.discard_b(event) + bj += 1 + end + end + + # Match + ax = string ? seq1[ai, 1] : seq1[ai] + bx = string ? seq2[bj, 1] : seq2[bj] + event = Diff::LCS::ContextChange.new('=', ai, ax, bj, bx) + event = yield event if block_given? + callbacks.match(event) + ai += 1 + bj += 1 + end + + while (ai < a_size) or (bj < b_size) + ax = string ? seq1[ai, 1] : seq1[ai] + bx = string ? seq2[bj, 1] : seq2[bj] + + case [(ai < a_size), (bj < b_size)] + when [true, true] + if callbacks.respond_to?(:change) + event = Diff::LCS::ContextChange.new('!', ai, ax, bj, bx) + event = yield event if block_given? + callbacks.change(event) + ai += 1 + bj += 1 + else + event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) + event = yield event if block_given? + callbacks.discard_a(event) + ai += 1 + ax = string ? seq1[ai, 1] : seq1[ai] + event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) + event = yield event if block_given? + callbacks.discard_b(event) + bj += 1 + end + when [true, false] + event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) + event = yield event if block_given? + callbacks.discard_a(event) + ai += 1 + when [false, true] + event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) + event = yield event if block_given? + callbacks.discard_b(event) + bj += 1 + end + end + end + + PATCH_MAP = { #:nodoc: + :patch => { '+' => '+', '-' => '-', '!' => '!', '=' => '=' }, + :unpatch => { '+' => '-', '-' => '+', '!' => '!', '=' => '=' } + } + + # Given a patchset, convert the current version to the new + # version. If +direction+ is not specified (must be + # :patch or :unpatch), then discovery of the + # direction of the patch will be attempted. + def patch(src, patchset, direction = nil) + string = src.kind_of?(String) + # Start with a new empty type of the source's class + res = src.class.new + + # Normalize the patchset. + patchset = __normalize_patchset(patchset) + + direction ||= Diff::LCS.__diff_direction(src, patchset) + direction ||= :patch + + ai = bj = 0 + + patchset.each do |change| + # Both Change and ContextChange support #action + action = PATCH_MAP[direction][change.action] + + case change + when Diff::LCS::ContextChange + case direction + when :patch + el = change.new_element + op = change.old_position + np = change.new_position + when :unpatch + el = change.old_element + op = change.new_position + np = change.old_position + end + + case action + when '-' # Remove details from the old string + while ai < op + res << (string ? src[ai, 1] : src[ai]) + ai += 1 + bj += 1 + end + ai += 1 + when '+' + while bj < np + res << (string ? src[ai, 1] : src[ai]) + ai += 1 + bj += 1 + end + + res << el + bj += 1 + when '=' + # This only appears in sdiff output with the SDiff callback. + # Therefore, we only need to worry about dealing with a single + # element. + res << el + + ai += 1 + bj += 1 + when '!' + while ai < op + res << (string ? src[ai, 1] : src[ai]) + ai += 1 + bj += 1 + end + + bj += 1 + ai += 1 + + res << el + end + when Diff::LCS::Change + case action + when '-' + while ai < change.position + res << (string ? src[ai, 1] : src[ai]) + ai += 1 + bj += 1 + end + ai += 1 + when '+' + while bj < change.position + res << (string ? src[ai, 1] : src[ai]) + ai += 1 + bj += 1 + end + + bj += 1 + + res << change.element + end + end + end + + while ai < src.size + res << (string ? src[ai, 1] : src[ai]) + ai += 1 + bj += 1 + end + + res + end + + # Given a set of patchset, convert the current version to the prior + # version. Does no auto-discovery. + def unpatch!(src, patchset) + Diff::LCS.patch(src, patchset, :unpatch) + end + + # Given a set of patchset, convert the current version to the next + # version. Does no auto-discovery. + def patch!(src, patchset) + Diff::LCS.patch(src, patchset, :patch) + end + + # private + # Compute the longest common subsequence between the sequenced Enumerables + # +a+ and +b+. The result is an array whose contents is such that + # + # result = Diff::LCS.__lcs(a, b) + # result.each_with_index do |e, ii| + # assert_equal(a[ii], b[e]) unless e.nil? + # end + def __lcs(a, b) + a_start = b_start = 0 + a_finish = a.size - 1 + b_finish = b.size - 1 + vector = [] + + # Prune off any common elements at the beginning... + while (a_start <= a_finish) and + (b_start <= b_finish) and + (a[a_start] == b[b_start]) + vector[a_start] = b_start + a_start += 1 + b_start += 1 + end + + # Now the end... + while (a_start <= a_finish) and + (b_start <= b_finish) and + (a[a_finish] == b[b_finish]) + vector[a_finish] = b_finish + a_finish -= 1 + b_finish -= 1 + end + + # Now, compute the equivalence classes of positions of elements. + b_matches = Diff::LCS.__position_hash(b, b_start .. b_finish) + + thresh = [] + links = [] + + (a_start .. a_finish).each do |ii| + ai = a.kind_of?(String) ? a[ii, 1] : a[ii] + bm = b_matches[ai] + kk = nil + bm.reverse_each do |jj| + if kk and (thresh[kk] > jj) and (thresh[kk - 1] < jj) + thresh[kk] = jj + else + kk = Diff::LCS.__replace_next_larger(thresh, jj, kk) + end + links[kk] = [ (kk > 0) ? links[kk - 1] : nil, ii, jj ] unless kk.nil? + end + end + + unless thresh.empty? + link = links[thresh.size - 1] + while not link.nil? + vector[link[1]] = link[2] + link = link[0] + end + end + + vector + end + + # Find the place at which +value+ would normally be inserted into the + # Enumerable. If that place is already occupied by +value+, do nothing + # and return +nil+. If the place does not exist (i.e., it is off the end + # of the Enumerable), add it to the end. Otherwise, replace the element + # at that point with +value+. It is assumed that the Enumerable's values + # are numeric. + # + # This operation preserves the sort order. + def __replace_next_larger(enum, value, last_index = nil) + # Off the end? + if enum.empty? or (value > enum[-1]) + enum << value + return enum.size - 1 + end + + # Binary search for the insertion point + last_index ||= enum.size + first_index = 0 + while (first_index <= last_index) + ii = (first_index + last_index) >> 1 + + found = enum[ii] + + if value == found + return nil + elsif value > found + first_index = ii + 1 + else + last_index = ii - 1 + end + end + + # The insertion point is in first_index; overwrite the next larger + # value. + enum[first_index] = value + return first_index + end + + # If +vector+ maps the matching elements of another collection onto this + # Enumerable, compute the inverse +vector+ that maps this Enumerable + # onto the collection. (Currently unused.) + def __inverse_vector(a, vector) + inverse = a.dup + (0 ... vector.size).each do |ii| + inverse[vector[ii]] = ii unless vector[ii].nil? + end + inverse + end + + # Returns a hash mapping each element of an Enumerable to the set of + # positions it occupies in the Enumerable, optionally restricted to the + # elements specified in the range of indexes specified by +interval+. + def __position_hash(enum, interval = 0 .. -1) + hash = Hash.new { |hh, kk| hh[kk] = [] } + interval.each do |ii| + kk = enum.kind_of?(String) ? enum[ii, 1] : enum[ii] + hash[kk] << ii + end + hash + end + + # Examine the patchset and the source to see in which direction the + # patch should be applied. + # + # WARNING: By default, this examines the whole patch, so this could take + # some time. This also works better with Diff::LCS::ContextChange or + # Diff::LCS::Change as its source, as an array will cause the creation + # of one of the above. + def __diff_direction(src, patchset, limit = nil) + count = left = left_miss = right = right_miss = 0 + string = src.kind_of?(String) + + patchset.each do |change| + count += 1 + + case change + when Diff::LCS::Change + # With a simplistic change, we can't tell the difference between + # the left and right on '!' actions, so we ignore those. On '=' + # actions, if there's a miss, we miss both left and right. + element = string ? src[change.position, 1] : src[change.position] + + case change.action + when '-' + if element == change.element + left += 1 + else + left_miss += 1 + end + when '+' + if element == change.element + right += 1 + else + right_miss += 1 + end + when '=' + if element != change.element + left_miss += 1 + right_miss += 1 + end + end + when Diff::LCS::ContextChange + case change.action + when '-' # Remove details from the old string + element = string ? src[change.old_position, 1] : src[change.old_position] + if element == change.old_element + left += 1 + else + left_miss += 1 + end + when '+' + element = string ? src[change.new_position, 1] : src[change.new_position] + if element == change.new_element + right += 1 + else + right_miss += 1 + end + when '=' + le = string ? src[change.old_position, 1] : src[change.old_position] + re = string ? src[change.new_position, 1] : src[change.new_position] + + left_miss += 1 if le != change.old_element + right_miss += 1 if re != change.new_element + when '!' + element = string ? src[change.old_position, 1] : src[change.old_position] + if element == change.old_element + left += 1 + else + element = string ? src[change.new_position, 1] : src[change.new_position] + if element == change.new_element + right += 1 + else + left_miss += 1 + right_miss += 1 + end + end + end + end + + break if not limit.nil? and count > limit + end + + no_left = (left == 0) and (left_miss >= 0) + no_right = (right == 0) and (right_miss >= 0) + + case [no_left, no_right] + when [false, true] + return :patch + when [true, false] + return :unpatch + else + raise "The provided patchset does not appear to apply to the provided value as either source or destination value." + end + end + + # Normalize the patchset. A patchset is always a sequence of changes, but + # how those changes are represented may vary, depending on how they were + # generated. In all cases we support, we also support the array + # representation of the changes. The formats are: + # + # [ # patchset <- Diff::LCS.diff(a, b) + # [ # one or more hunks + # Diff::LCS::Change # one or more changes + # ] ] + # + # [ # patchset, equivalent to the above + # [ # one or more hunks + # [ action, line, value ] # one or more changes + # ] ] + # + # [ # patchset <- Diff::LCS.diff(a, b, Diff::LCS::ContextDiffCallbacks) + # # OR <- Diff::LCS.sdiff(a, b, Diff::LCS::ContextDiffCallbacks) + # [ # one or more hunks + # Diff::LCS::ContextChange # one or more changes + # ] ] + # + # [ # patchset, equivalent to the above + # [ # one or more hunks + # [ action, [ old line, old value ], [ new line, new value ] ] + # # one or more changes + # ] ] + # + # [ # patchset <- Diff::LCS.sdiff(a, b) + # # OR <- Diff::LCS.diff(a, b, Diff::LCS::SDiffCallbacks) + # Diff::LCS::ContextChange # one or more changes + # ] + # + # [ # patchset, equivalent to the above + # [ action, [ old line, old value ], [ new line, new value ] ] + # # one or more changes + # ] + # + # The result of this will be either of the following. + # + # [ # patchset + # Diff::LCS::ContextChange # one or more changes + # ] + # + # [ # patchset + # Diff::LCS::Change # one or more changes + # ] + # + # If either of the above is provided, it will be returned as such. + # + def __normalize_patchset(patchset) + patchset.map do |hunk| + case hunk + when Diff::LCS::ContextChange, Diff::LCS::Change + hunk + when Array + if (not hunk[0].kind_of?(Array)) and hunk[1].kind_of?(Array) and hunk[2].kind_of?(Array) + Diff::LCS::ContextChange.from_a(hunk) + else + hunk.map do |change| + case change + when Diff::LCS::ContextChange, Diff::LCS::Change + change + when Array + # change[1] will ONLY be an array in a ContextChange#to_a call. + # In Change#to_a, it represents the line (singular). + if change[1].kind_of?(Array) + Diff::LCS::ContextChange.from_a(change) + else + Diff::LCS::Change.from_a(change) + end + end + end + end + else + raise ArgumentError, "Cannot normalise a hunk of class #{hunk.class}." + end + end.flatten + end + end + end +end diff --git a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/array.rb b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/array.rb new file mode 100644 index 0000000..dcbeebc --- /dev/null +++ b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/array.rb @@ -0,0 +1,21 @@ +#! /usr/env/bin ruby +#-- +# Copyright 2004 Austin Ziegler +# adapted from: +# Algorithm::Diff (Perl) by Ned Konz +# Smalltalk by Mario I. Wolczko +# implements McIlroy-Hunt diff algorithm +# +# This program is free software. It may be redistributed and/or modified under +# the terms of the GPL version 2 (or later), the Perl Artistic licence, or the +# Ruby licence. +# +# $Id: array.rb,v 1.3 2004/08/08 20:33:09 austin Exp $ +#++ +# Includes Diff::LCS into the Array built-in class. + +require 'diff/lcs' + +class Array + include LCSDiff::Diff::LCS +end diff --git a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/block.rb b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/block.rb new file mode 100644 index 0000000..ca791f3 --- /dev/null +++ b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/block.rb @@ -0,0 +1,51 @@ +#! /usr/env/bin ruby +#-- +# Copyright 2004 Austin Ziegler +# adapted from: +# Algorithm::Diff (Perl) by Ned Konz +# Smalltalk by Mario I. Wolczko +# implements McIlroy-Hunt diff algorithm +# +# This program is free software. It may be redistributed and/or modified under +# the terms of the GPL version 2 (or later), the Perl Artistic licence, or the +# Ruby licence. +# +# $Id: block.rb,v 1.3 2004/08/08 20:33:09 austin Exp $ +#++ +# Contains Diff::LCS::Block for bin/ldiff. + + # A block is an operation removing, adding, or changing a group of items. + # Basically, this is just a list of changes, where each change adds or + # deletes a single item. Used by bin/ldiff. +class LCSDiff::Diff::LCS::Block + attr_reader :changes, :insert, :remove + + def initialize(chunk) + @changes = [] + @insert = [] + @remove = [] + + chunk.each do |item| + @changes << item + @remove << item if item.deleting? + @insert << item if item.adding? + end + end + + def diff_size + @insert.size - @remove.size + end + + def op + case [@remove.empty?, @insert.empty?] + when [false, false] + '!' + when [false, true] + '-' + when [true, false] + '+' + else # [true, true] + '^' + end + end +end diff --git a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/callbacks.rb b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/callbacks.rb new file mode 100644 index 0000000..1c170d8 --- /dev/null +++ b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/callbacks.rb @@ -0,0 +1,322 @@ +#! /usr/env/bin ruby +#-- +# Copyright 2004 Austin Ziegler +# adapted from: +# Algorithm::Diff (Perl) by Ned Konz +# Smalltalk by Mario I. Wolczko +# implements McIlroy-Hunt diff algorithm +# +# This program is free software. It may be redistributed and/or modified under +# the terms of the GPL version 2 (or later), the Perl Artistic licence, or the +# Ruby licence. +# +# $Id: callbacks.rb,v 1.4 2004/09/14 18:51:26 austin Exp $ +#++ +# Contains definitions for all default callback objects. + +require 'diff/lcs/change' + +module LCSDiff::Diff::LCS + # This callback object implements the default set of callback events, which + # only returns the event itself. Note that #finished_a and #finished_b are + # not implemented -- I haven't yet figured out where they would be useful. + # + # Note that this is intended to be called as is, e.g., + # + # Diff::LCS.LCS(seq1, seq2, Diff::LCS::DefaultCallbacks) + class DefaultCallbacks + class << self + # Called when two items match. + def match(event) + event + end + # Called when the old value is discarded in favour of the new value. + def discard_a(event) + event + end + # Called when the new value is discarded in favour of the old value. + def discard_b(event) + event + end + # Called when both the old and new values have changed. + def change(event) + event + end + + private :new + end + end + + # An alias for DefaultCallbacks that is used in Diff::LCS#traverse_sequences. + # + # Diff::LCS.LCS(seq1, seq2, Diff::LCS::SequenceCallbacks) + SequenceCallbacks = DefaultCallbacks + # An alias for DefaultCallbacks that is used in Diff::LCS#traverse_balanced. + # + # Diff::LCS.LCS(seq1, seq2, Diff::LCS::BalancedCallbacks) + BalancedCallbacks = DefaultCallbacks +end + + # This will produce a compound array of simple diff change objects. Each + # element in the #diffs array is a +hunk+ or +hunk+ array, where each + # element in each +hunk+ array is a single Change object representing the + # addition or removal of a single element from one of the two tested + # sequences. The +hunk+ provides the full context for the changes. + # + # diffs = Diff::LCS.diff(seq1, seq2) + # # This example shows a simplified array format. + # # [ [ [ '-', 0, 'a' ] ], # 1 + # # [ [ '+', 2, 'd' ] ], # 2 + # # [ [ '-', 4, 'h' ], # 3 + # # [ '+', 4, 'f' ] ], + # # [ [ '+', 6, 'k' ] ], # 4 + # # [ [ '-', 8, 'n' ], # 5 + # # [ '-', 9, 'p' ], + # # [ '+', 9, 'r' ], + # # [ '+', 10, 's' ], + # # [ '+', 11, 't' ] ] ] + # + # There are five hunks here. The first hunk says that the +a+ at position 0 + # of the first sequence should be deleted ('-'). The second hunk + # says that the +d+ at position 2 of the second sequence should be inserted + # ('+'). The third hunk says that the +h+ at position 4 of the + # first sequence should be removed and replaced with the +f+ from position 4 + # of the second sequence. The other two hunks are described similarly. + # + # === Use + # This callback object must be initialised and is used by the Diff::LCS#diff + # method. + # + # cbo = Diff::LCS::DiffCallbacks.new + # Diff::LCS.LCS(seq1, seq2, cbo) + # cbo.finish + # + # Note that the call to #finish is absolutely necessary, or the last set of + # changes will not be visible. Alternatively, can be used as: + # + # cbo = Diff::LCS::DiffCallbacks.new { |tcbo| Diff::LCS.LCS(seq1, seq2, tcbo) } + # + # The necessary #finish call will be made. + # + # === Simplified Array Format + # The simplified array format used in the example above can be obtained + # with: + # + # require 'pp' + # pp diffs.map { |e| e.map { |f| f.to_a } } +class LCSDiff::Diff::LCS::DiffCallbacks + # Returns the difference set collected during the diff process. + attr_reader :diffs + + def initialize # :yields self: + @hunk = [] + @diffs = [] + + if block_given? + begin + yield self + ensure + self.finish + end + end + end + + # Finalizes the diff process. If an unprocessed hunk still exists, then it + # is appended to the diff list. + def finish + add_nonempty_hunk + end + + def match(event) + add_nonempty_hunk + end + + def discard_a(event) + @hunk << LCSDiff::Diff::LCS::Change.new('-', event.old_position, event.old_element) + end + + def discard_b(event) + @hunk << LCSDiff::Diff::LCS::Change.new('+', event.new_position, event.new_element) + end + +private + def add_nonempty_hunk + @diffs << @hunk unless @hunk.empty? + @hunk = [] + end +end + + # This will produce a compound array of contextual diff change objects. Each + # element in the #diffs array is a "hunk" array, where each element in each + # "hunk" array is a single change. Each change is a Diff::LCS::ContextChange + # that contains both the old index and new index values for the change. The + # "hunk" provides the full context for the changes. Both old and new objects + # will be presented for changed objects. +nil+ will be substituted for a + # discarded object. + # + # seq1 = %w(a b c e h j l m n p) + # seq2 = %w(b c d e f j k l m r s t) + # + # diffs = Diff::LCS.diff(seq1, seq2, Diff::LCS::ContextDiffCallbacks) + # # This example shows a simplified array format. + # # [ [ [ '-', [ 0, 'a' ], [ 0, nil ] ] ], # 1 + # # [ [ '+', [ 3, nil ], [ 2, 'd' ] ] ], # 2 + # # [ [ '-', [ 4, 'h' ], [ 4, nil ] ], # 3 + # # [ '+', [ 5, nil ], [ 4, 'f' ] ] ], + # # [ [ '+', [ 6, nil ], [ 6, 'k' ] ] ], # 4 + # # [ [ '-', [ 8, 'n' ], [ 9, nil ] ], # 5 + # # [ '+', [ 9, nil ], [ 9, 'r' ] ], + # # [ '-', [ 9, 'p' ], [ 10, nil ] ], + # # [ '+', [ 10, nil ], [ 10, 's' ] ], + # # [ '+', [ 10, nil ], [ 11, 't' ] ] ] ] + # + # The five hunks shown are comprised of individual changes; if there is a + # related set of changes, they are still shown individually. + # + # This callback can also be used with Diff::LCS#sdiff, which will produce + # results like: + # + # diffs = Diff::LCS.sdiff(seq1, seq2, Diff::LCS::ContextCallbacks) + # # This example shows a simplified array format. + # # [ [ [ "-", [ 0, "a" ], [ 0, nil ] ] ], # 1 + # # [ [ "+", [ 3, nil ], [ 2, "d" ] ] ], # 2 + # # [ [ "!", [ 4, "h" ], [ 4, "f" ] ] ], # 3 + # # [ [ "+", [ 6, nil ], [ 6, "k" ] ] ], # 4 + # # [ [ "!", [ 8, "n" ], [ 9, "r" ] ], # 5 + # # [ "!", [ 9, "p" ], [ 10, "s" ] ], + # # [ "+", [ 10, nil ], [ 11, "t" ] ] ] ] + # + # The five hunks are still present, but are significantly shorter in total + # presentation, because changed items are shown as changes ("!") instead of + # potentially "mismatched" pairs of additions and deletions. + # + # The result of this operation is similar to that of + # Diff::LCS::SDiffCallbacks. They may be compared as: + # + # s = Diff::LCS.sdiff(seq1, seq2).reject { |e| e.action == "=" } + # c = Diff::LCS.sdiff(seq1, seq2, Diff::LCS::ContextDiffCallbacks).flatten + # + # s == c # -> true + # + # === Use + # This callback object must be initialised and can be used by the + # Diff::LCS#diff or Diff::LCS#sdiff methods. + # + # cbo = Diff::LCS::ContextDiffCallbacks.new + # Diff::LCS.LCS(seq1, seq2, cbo) + # cbo.finish + # + # Note that the call to #finish is absolutely necessary, or the last set of + # changes will not be visible. Alternatively, can be used as: + # + # cbo = Diff::LCS::ContextDiffCallbacks.new { |tcbo| Diff::LCS.LCS(seq1, seq2, tcbo) } + # + # The necessary #finish call will be made. + # + # === Simplified Array Format + # The simplified array format used in the example above can be obtained + # with: + # + # require 'pp' + # pp diffs.map { |e| e.map { |f| f.to_a } } +class LCSDiff::Diff::LCS::ContextDiffCallbacks < LCSDiff::Diff::LCS::DiffCallbacks + def discard_a(event) + @hunk << Diff::LCS::ContextChange.simplify(event) + end + + def discard_b(event) + @hunk << Diff::LCS::ContextChange.simplify(event) + end + + def change(event) + @hunk << Diff::LCS::ContextChange.simplify(event) + end +end + + # This will produce a simple array of diff change objects. Each element in + # the #diffs array is a single ContextChange. In the set of #diffs provided + # by SDiffCallbacks, both old and new objects will be presented for both + # changed and unchanged objects. +nil+ will be substituted + # for a discarded object. + # + # The diffset produced by this callback, when provided to Diff::LCS#sdiff, + # will compute and display the necessary components to show two sequences + # and their minimized differences side by side, just like the Unix utility + # +sdiff+. + # + # same same + # before | after + # old < - + # - > new + # + # seq1 = %w(a b c e h j l m n p) + # seq2 = %w(b c d e f j k l m r s t) + # + # diffs = Diff::LCS.sdiff(seq1, seq2) + # # This example shows a simplified array format. + # # [ [ "-", [ 0, "a"], [ 0, nil ] ], + # # [ "=", [ 1, "b"], [ 0, "b" ] ], + # # [ "=", [ 2, "c"], [ 1, "c" ] ], + # # [ "+", [ 3, nil], [ 2, "d" ] ], + # # [ "=", [ 3, "e"], [ 3, "e" ] ], + # # [ "!", [ 4, "h"], [ 4, "f" ] ], + # # [ "=", [ 5, "j"], [ 5, "j" ] ], + # # [ "+", [ 6, nil], [ 6, "k" ] ], + # # [ "=", [ 6, "l"], [ 7, "l" ] ], + # # [ "=", [ 7, "m"], [ 8, "m" ] ], + # # [ "!", [ 8, "n"], [ 9, "r" ] ], + # # [ "!", [ 9, "p"], [ 10, "s" ] ], + # # [ "+", [ 10, nil], [ 11, "t" ] ] ] + # + # The result of this operation is similar to that of + # Diff::LCS::ContextDiffCallbacks. They may be compared as: + # + # s = Diff::LCS.sdiff(seq1, seq2).reject { |e| e.action == "=" } + # c = Diff::LCS.sdiff(seq1, seq2, Diff::LCS::ContextDiffCallbacks).flatten + # + # s == c # -> true + # + # === Use + # This callback object must be initialised and is used by the Diff::LCS#sdiff + # method. + # + # cbo = Diff::LCS::SDiffCallbacks.new + # Diff::LCS.LCS(seq1, seq2, cbo) + # + # As with the other initialisable callback objects, Diff::LCS::SDiffCallbacks + # can be initialised with a block. As there is no "fininishing" to be done, + # this has no effect on the state of the object. + # + # cbo = Diff::LCS::SDiffCallbacks.new { |tcbo| Diff::LCS.LCS(seq1, seq2, tcbo) } + # + # === Simplified Array Format + # The simplified array format used in the example above can be obtained + # with: + # + # require 'pp' + # pp diffs.map { |e| e.to_a } +class LCSDiff::Diff::LCS::SDiffCallbacks + # Returns the difference set collected during the diff process. + attr_reader :diffs + + def initialize #:yields self: + @diffs = [] + yield self if block_given? + end + + def match(event) + @diffs << Diff::LCS::ContextChange.simplify(event) + end + + def discard_a(event) + @diffs << Diff::LCS::ContextChange.simplify(event) + end + + def discard_b(event) + @diffs << Diff::LCS::ContextChange.simplify(event) + end + + def change(event) + @diffs << Diff::LCS::ContextChange.simplify(event) + end +end diff --git a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/change.rb b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/change.rb new file mode 100644 index 0000000..65d0eb6 --- /dev/null +++ b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/change.rb @@ -0,0 +1,172 @@ +#! /usr/env/bin ruby +#-- +# Copyright 2004 Austin Ziegler +# adapted from: +# Algorithm::Diff (Perl) by Ned Konz +# Smalltalk by Mario I. Wolczko +# implements McIlroy-Hunt diff algorithm +# +# This program is free software. It may be redistributed and/or modified under +# the terms of the GPL version 2 (or later), the Perl Artistic licence, or the +# Ruby licence. +# +# $Id: change.rb,v 1.4 2004/08/08 20:33:09 austin Exp $ +#++ +# Provides Diff::LCS::Change and Diff::LCS::ContextChange. + +module LCSDiff + + # Centralises the change test code in Diff::LCS::Change and + # Diff::LCS::ContextChange, since it's the same for both classes. + module Diff::LCS::ChangeTypeTests + def deleting? + @action == '-' + end + + def adding? + @action == '+' + end + + def unchanged? + @action == '=' + end + + def changed? + @changed == '!' + end + + def finished_a? + @changed == '>' + end + + def finished_b? + @changed == '<' + end + end + + # Represents a simplistic (non-contextual) change. Represents the removal or + # addition of an element from either the old or the new sequenced enumerable. + class Diff::LCS::Change + # Returns the action this Change represents. Can be '+' (#adding?), '-' + # (#deleting?), '=' (#unchanged?), # or '!' (#changed?). When created by + # Diff::LCS#diff or Diff::LCS#sdiff, it may also be '>' (#finished_a?) or + # '<' (#finished_b?). + attr_reader :action + attr_reader :position + attr_reader :element + + include Comparable + def ==(other) + (self.action == other.action) and + (self.position == other.position) and + (self.element == other.element) + end + + def <=>(other) + r = self.action <=> other.action + r = self.position <=> other.position if r.zero? + r = self.element <=> other.element if r.zero? + r + end + + def initialize(action, position, element) + @action = action + @position = position + @element = element + end + + # Creates a Change from an array produced by Change#to_a. + def to_a + [@action, @position, @element] + end + + def self.from_a(arr) + Diff::LCS::Change.new(arr[0], arr[1], arr[2]) + end + + include Diff::LCS::ChangeTypeTests + end + + # Represents a contextual change. Contains the position and values of the + # elements in the old and the new sequenced enumerables as well as the action + # taken. + class Diff::LCS::ContextChange + # Returns the action this Change represents. Can be '+' (#adding?), '-' + # (#deleting?), '=' (#unchanged?), # or '!' (#changed?). When + # created by Diff::LCS#diff or Diff::LCS#sdiff, it may also be '>' + # (#finished_a?) or '<' (#finished_b?). + attr_reader :action + attr_reader :old_position + attr_reader :old_element + attr_reader :new_position + attr_reader :new_element + + include Comparable + + def ==(other) + (@action == other.action) and + (@old_position == other.old_position) and + (@new_position == other.new_position) and + (@old_element == other.old_element) and + (@new_element == other.new_element) + end + + def inspect(*args) + %Q(#<#{self.class.name}:#{__id__} @action=#{action} positions=#{old_position},#{new_position} elements=#{old_element.inspect},#{new_element.inspect}>) + end + + def <=>(other) + r = @action <=> other.action + r = @old_position <=> other.old_position if r.zero? + r = @new_position <=> other.new_position if r.zero? + r = @old_element <=> other.old_element if r.zero? + r = @new_element <=> other.new_element if r.zero? + r + end + + def initialize(action, old_position, old_element, new_position, new_element) + @action = action + @old_position = old_position + @old_element = old_element + @new_position = new_position + @new_element = new_element + end + + def to_a + [@action, [@old_position, @old_element], [@new_position, @new_element]] + end + + # Creates a ContextChange from an array produced by ContextChange#to_a. + def self.from_a(arr) + if arr.size == 5 + Diff::LCS::ContextChange.new(arr[0], arr[1], arr[2], arr[3], arr[4]) + else + Diff::LCS::ContextChange.new(arr[0], arr[1][0], arr[1][1], arr[2][0], + arr[2][1]) + end + end + + # Simplifies a context change for use in some diff callbacks. '<' actions + # are converted to '-' and '>' actions are converted to '+'. + def self.simplify(event) + ea = event.to_a + + case ea[0] + when '-' + ea[2][1] = nil + when '<' + ea[0] = '-' + ea[2][1] = nil + when '+' + ea[1][1] = nil + when '>' + ea[0] = '+' + ea[1][1] = nil + end + + Diff::LCS::ContextChange.from_a(ea) + end + + include Diff::LCS::ChangeTypeTests + end +end diff --git a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/hunk.rb b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/hunk.rb new file mode 100644 index 0000000..f175a39 --- /dev/null +++ b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/hunk.rb @@ -0,0 +1,257 @@ +#! /usr/env/bin ruby +#-- +# Copyright 2004 Austin Ziegler +# adapted from: +# Algorithm::Diff (Perl) by Ned Konz +# Smalltalk by Mario I. Wolczko +# implements McIlroy-Hunt diff algorithm +# +# This program is free software. It may be redistributed and/or modified under +# the terms of the GPL version 2 (or later), the Perl Artistic licence, or the +# Ruby licence. +# +# $Id: hunk.rb,v 1.2 2004/08/08 20:33:09 austin Exp $ +#++ +# Contains Diff::LCS::Hunk for bin/ldiff. + +require 'diff/lcs/block' + + # A Hunk is a group of Blocks which overlap because of the context + # surrounding each block. (So if we're not using context, every hunk will + # contain one block.) Used in the diff program (bin/diff). +class LCSDiff::Diff::LCS::Hunk + # Create a hunk using references to both the old and new data, as well as + # the piece of data + def initialize(data_old, data_new, piece, context, file_length_difference) + # At first, a hunk will have just one Block in it + @blocks = [ Diff::LCS::Block.new(piece) ] + @data_old = data_old + @data_new = data_new + + before = after = file_length_difference + after += @blocks[0].diff_size + @file_length_difference = after # The caller must get this manually + + # Save the start & end of each array. If the array doesn't exist + # (e.g., we're only adding items in this block), then figure out the + # line number based on the line number of the other file and the + # current difference in file lengths. + if @blocks[0].remove.empty? + a1 = a2 = nil + else + a1 = @blocks[0].remove[0].position + a2 = @blocks[0].remove[-1].position + end + + if @blocks[0].insert.empty? + b1 = b2 = nil + else + b1 = @blocks[0].insert[0].position + b2 = @blocks[0].insert[-1].position + end + + @start_old = a1 || (b1 - before) + @start_new = b1 || (a1 + before) + @end_old = a2 || (b2 - after) + @end_new = b2 || (a2 + after) + + self.flag_context = context + end + + attr_reader :blocks + attr_reader :start_old, :start_new + attr_reader :end_old, :end_new + attr_reader :file_length_difference + + # Change the "start" and "end" fields to note that context should be added + # to this hunk + attr_accessor :flag_context + def flag_context=(context) #:nodoc: + return if context.nil? or context.zero? + + add_start = (context > @start_old) ? @start_old : context + @start_old -= add_start + @start_new -= add_start + + if (@end_old + context) > @data_old.size + add_end = @data_old.size - @end_old + else + add_end = context + end + @end_old += add_end + @end_new += add_end + end + + def unshift(hunk) + @start_old = hunk.start_old + @start_new = hunk.start_new + blocks.unshift(*hunk.blocks) + end + + # Is there an overlap between hunk arg0 and old hunk arg1? Note: if end + # of old hunk is one less than beginning of second, they overlap + def overlaps?(hunk = nil) + return nil if hunk.nil? + + a = (@start_old - hunk.end_old) <= 1 + b = (@start_new - hunk.end_new) <= 1 + return (a or b) + end + + def diff(format) + case format + when :old + old_diff + when :unified + unified_diff + when :context + context_diff + when :ed + self + when :reverse_ed, :ed_finish + ed_diff(format) + else + raise "Unknown diff format #{format}." + end + end + + def each_old(block) + @data_old[@start_old .. @end_old].each { |e| yield e } + end + + private + # Note that an old diff can't have any context. Therefore, we know that + # there's only one block in the hunk. + def old_diff + warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 + op_act = { "+" => 'a', "-" => 'd', "!" => "c" } + + block = @blocks[0] + + # Calculate item number range. Old diff range is just like a context + # diff range, except the ranges are on one line with the action between + # them. + s = "#{context_range(:old)}#{op_act[block.op]}#{context_range(:new)}\n" + # If removing anything, just print out all the remove lines in the hunk + # which is just all the remove lines in the block. + @data_old[@start_old .. @end_old].each { |e| s << "< #{e}\n" } unless block.remove.empty? + s << "---\n" if block.op == "!" + @data_new[@start_new .. @end_new].each { |e| s << "> #{e}\n" } unless block.insert.empty? + s + end + + def unified_diff + # Calculate item number range. + s = "@@ -#{unified_range(:old)} +#{unified_range(:new)} @@\n" + + # Outlist starts containing the hunk of the old file. Removing an item + # just means putting a '-' in front of it. Inserting an item requires + # getting it from the new file and splicing it in. We splice in + # +num_added+ items. Remove blocks use +num_added+ because splicing + # changed the length of outlist. + # + # We remove +num_removed+ items. Insert blocks use +num_removed+ + # because their item numbers -- corresponding to positions in the NEW + # file -- don't take removed items into account. + lo, hi, num_added, num_removed = @start_old, @end_old, 0, 0 + + outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } + + @blocks.each do |block| + block.remove.each do |item| + op = item.action.to_s # - + offset = item.position - lo + num_added + outlist[offset].gsub!(/^ /, op.to_s) + num_removed += 1 + end + block.insert.each do |item| + op = item.action.to_s # + + offset = item.position - @start_new + num_removed + outlist[offset, 0] = "#{op}#{@data_new[item.position]}" + num_added += 1 + end + end + + s << outlist.join("\n") + end + + def context_diff + s = "***************\n" + s << "*** #{context_range(:old)} ****\n" + r = context_range(:new) + + # Print out file 1 part for each block in context diff format if there + # are any blocks that remove items + lo, hi = @start_old, @end_old + removes = @blocks.select { |e| not e.remove.empty? } + if removes + outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } + removes.each do |block| + block.remove.each do |item| + outlist[item.position - lo].gsub!(/^ /) { block.op } # - or ! + end + end + s << outlist.join("\n") + end + + s << "\n--- #{r} ----\n" + lo, hi = @start_new, @end_new + inserts = @blocks.select { |e| not e.insert.empty? } + if inserts + outlist = @data_new[lo .. hi].collect { |e| e.gsub(/^/, ' ') } + inserts.each do |block| + block.insert.each do |item| + outlist[item.position - lo].gsub!(/^ /) { block.op } # + or ! + end + end + s << outlist.join("\n") + end + s + end + + def ed_diff(format) + op_act = { "+" => 'a', "-" => 'd', "!" => "c" } + warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 + + if format == :reverse_ed + s = "#{op_act[@blocks[0].op]}#{context_range(:old)}\n" + else + s = "#{context_range(:old).gsub(/,/, ' ')}#{op_act[@blocks[0].op]}\n" + end + + unless @blocks[0].insert.empty? + @data_new[@start_new .. @end_new].each { |e| s << "#{e}\n" } + s << ".\n" + end + s + end + + # Generate a range of item numbers to print. Only print 1 number if the + # range has only one item in it. Otherwise, it's 'start,end' + def context_range(mode) + case mode + when :old + s, e = (@start_old + 1), (@end_old + 1) + when :new + s, e = (@start_new + 1), (@end_new + 1) + end + + (s < e) ? "#{s},#{e}" : "#{e}" + end + + # Generate a range of item numbers to print for unified diff. Print + # number where block starts, followed by number of lines in the block + # (don't print number of lines if it's 1) + def unified_range(mode) + case mode + when :old + s, e = (@start_old + 1), (@end_old + 1) + when :new + s, e = (@start_new + 1), (@end_new + 1) + end + + length = e - s + 1 + first = (length < 2) ? e : s # "strange, but correct" + (length == 1) ? "#{first}" : "#{first},#{length}" + end +end diff --git a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/ldiff.rb b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/ldiff.rb new file mode 100644 index 0000000..32d4704 --- /dev/null +++ b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/ldiff.rb @@ -0,0 +1,226 @@ +#!/usr/bin/env ruby + +require 'optparse' +require 'ostruct' +require 'diff/lcs/hunk' + + # == ldiff Usage + # ldiff [options] oldfile newfile + # + # -c:: Displays a context diff with 3 lines of context. + # -C [LINES], --context [LINES]:: Displays a context diff with LINES lines of context. Default 3 lines. + # -u:: Displays a unified diff with 3 lines of context. + # -U [LINES], --unified [LINES]:: Displays a unified diff with LINES lines of context. Default 3 lines. + # -e:: Creates an 'ed' script to change oldfile to newfile. + # -f:: Creates an 'ed' script to change oldfile to newfile in reverse order. + # -a, --text:: Treats the files as text and compares them line-by-line, even if they do not seem to be text. + # --binary:: Treats the files as binary. + # -q, --brief:: Reports only whether or not the files differ, not the details. + # --help:: Shows the command-line help. + # --version:: Shows the version of Diff::LCS. + # + # By default, runs produces an "old-style" diff, with output like UNIX diff. + # + # == Copyright + # Copyright © 2004 Austin Ziegler + # + # Part of Diff::LCS + # Austin Ziegler + # + # This program is free software. It may be redistributed and/or modified under + # the terms of the GPL version 2 (or later), the Perl Artistic licence, or the + # Ruby licence. +module LCSDiff::Diff::LCS::Ldiff + BANNER = <<-COPYRIGHT +ldiff #{Diff::LCS::VERSION} + Copyright © 2004 Austin Ziegler + + Part of Diff::LCS. + http://rubyforge.org/projects/ruwiki/ + + Austin Ziegler + + This program is free software. It may be redistributed and/or modified under + the terms of the GPL version 2 (or later), the Perl Artistic licence, or the + Ruby licence. + +$Id: ldiff.rb,v 1.1 2004/09/26 01:37:49 austin Exp $ + COPYRIGHT + + class << self + attr_reader :format, :lines #:nodoc: + attr_reader :file_old, :file_new #:nodoc: + attr_reader :data_old, :data_new #:nodoc: + + def run(args, input = $stdin, output = $stdout, error = $stderr) #:nodoc: + args.options do |o| + o.banner = "Usage: #{File.basename($0)} [options] oldfile newfile" + o.separator "" + o.on('-c', + 'Displays a context diff with 3 lines of', + 'context.') do |ctx| + @format = :context + @lines = 3 + end + o.on('-C', '--context [LINES]', Numeric, + 'Displays a context diff with LINES lines', + 'of context. Default 3 lines.') do |ctx| + @format = :context + @lines = ctx || 3 + end + o.on('-u', + 'Displays a unified diff with 3 lines of', + 'context.') do |ctx| + @format = :unified + @lines = 3 + end + o.on('-U', '--unified [LINES]', Numeric, + 'Displays a unified diff with LINES lines', + 'of context. Default 3 lines.') do |ctx| + @format = :unified + @lines = ctx || 3 + end + o.on('-e', + 'Creates an \'ed\' script to change', + 'oldfile to newfile.') do |ctx| + @format = :ed + end + o.on('-f', + 'Creates an \'ed\' script to change', + 'oldfile to newfile in reverse order.') do |ctx| + @format = :reverse_ed + end + o.on('-a', '--text', + 'Treat the files as text and compare them', + 'line-by-line, even if they do not seem', + 'to be text.') do |txt| + @binary = false + end + o.on('--binary', + 'Treats the files as binary.') do |bin| + @binary = true + end + o.on('-q', '--brief', + 'Report only whether or not the files', + 'differ, not the details.') do |ctx| + @format = :report + end + o.on_tail('--help', 'Shows this text.') do + error << o + return 0 + end + o.on_tail('--version', 'Shows the version of Diff::LCS.') do + error << BANNER + return 0 + end + o.on_tail "" + o.on_tail 'By default, runs produces an "old-style" diff, with output like UNIX diff.' + o.parse! + end + + unless args.size == 2 + error << args.options + return 127 + end + + # Defaults are for old-style diff + @format ||= :old + @lines ||= 0 + + file_old, file_new = *ARGV + + case @format + when :context + char_old = '*' * 3 + char_new = '-' * 3 + when :unified + char_old = '-' * 3 + char_new = '+' * 3 + end + + # After we've read up to a certain point in each file, the number of + # items we've read from each file will differ by FLD (could be 0). + file_length_difference = 0 + + if @binary.nil? or @binary + data_old = IO::read(file_old) + data_new = IO::read(file_new) + + # Test binary status + if @binary.nil? + old_txt = data_old[0...4096].grep(/\0/).empty? + new_txt = data_new[0...4096].grep(/\0/).empty? + @binary = (not old_txt) or (not new_txt) + old_txt = new_txt = nil + end + + unless @binary + data_old = data_old.split(/\n/).map! { |e| e.chomp } + data_new = data_new.split(/\n/).map! { |e| e.chomp } + end + else + data_old = IO::readlines(file_old).map! { |e| e.chomp } + data_new = IO::readlines(file_new).map! { |e| e.chomp } + end + + # diff yields lots of pieces, each of which is basically a Block object + if @binary + diffs = (data_old == data_new) + else + diffs = Diff::LCS.diff(data_old, data_new) + diffs = nil if diffs.empty? + end + + return 0 unless diffs + + if (@format == :report) and diffs + output << "Files #{file_old} and #{file_new} differ\n" + return 1 + end + + if (@format == :unified) or (@format == :context) + ft = File.stat(file_old).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S %z') + puts "#{char_old} #{file_old}\t#{ft}" + ft = File.stat(file_new).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S %z') + puts "#{char_new} #{file_new}\t#{ft}" + end + + # Loop over hunks. If a hunk overlaps with the last hunk, join them. + # Otherwise, print out the old one. + oldhunk = hunk = nil + + if @format == :ed + real_output = output + output = [] + end + + diffs.each do |piece| + begin + hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, @lines, + file_length_difference) + file_length_difference = hunk.file_length_difference + + next unless oldhunk + + if (@lines > 0) and hunk.overlaps?(oldhunk) + hunk.unshift(oldhunk) + else + output << oldhunk.diff(@format) + end + ensure + oldhunk = hunk + output << "\n" + end + end + + output << oldhunk.diff(@format) + output << "\n" + + if @format == :ed + output.reverse_each { |e| real_output << e.diff(:ed_finish) } + end + + return 1 + end + end +end diff --git a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/string.rb b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/string.rb new file mode 100644 index 0000000..514fa5e --- /dev/null +++ b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/string.rb @@ -0,0 +1,19 @@ +#! /usr/env/bin ruby +#-- +# Copyright 2004 Austin Ziegler +# adapted from: +# Algorithm::Diff (Perl) by Ned Konz +# Smalltalk by Mario I. Wolczko +# implements McIlroy-Hunt diff algorithm +# +# This program is free software. It may be redistributed and/or modified under +# the terms of the GPL version 2 (or later), the Perl Artistic licence, or the +# Ruby licence. +# +# $Id: string.rb,v 1.3 2004/08/08 20:33:09 austin Exp $ +#++ +# Includes Diff::LCS into String. + +class String + include LCSDiff::Diff::LCS +end diff --git a/vendor/gems/diff-lcs-1.1.2/tests/00test.rb b/vendor/gems/diff-lcs-1.1.2/tests/00test.rb new file mode 100644 index 0000000..8872dfd --- /dev/null +++ b/vendor/gems/diff-lcs-1.1.2/tests/00test.rb @@ -0,0 +1,626 @@ +#! /usr/bin/env ruby +# +$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../lib") if __FILE__ == $0 + +require 'diff/lcs' +require 'test/unit' +require 'pp' +require 'diff/lcs/array' + +module Diff::LCS::Tests + def __format_diffs(diffs) + diffs.map do |e| + if e.kind_of?(Array) + e.map { |f| f.to_a.join }.join(", ") + else + e.to_a.join + end + end.join("; ") + end + + def __map_diffs(diffs, klass = Diff::LCS::ContextChange) + diffs.map do |chunks| + if klass == Diff::LCS::ContextChange + klass.from_a(chunks) + else + chunks.map { |changes| klass.from_a(changes) } + end + end + end + + def __simple_callbacks + callbacks = Object.new + class << callbacks + attr_reader :matched_a + attr_reader :matched_b + attr_reader :discards_a + attr_reader :discards_b + attr_reader :done_a + attr_reader :done_b + + def reset + @matched_a = [] + @matched_b = [] + @discards_a = [] + @discards_b = [] + @done_a = [] + @done_b = [] + end + + def match(event) + @matched_a << event.old_element + @matched_b << event.new_element + end + + def discard_b(event) + @discards_b << event.new_element + end + + def discard_a(event) + @discards_a << event.old_element + end + + def finished_a(event) + @done_a << [event.old_element, event.old_position] + end + + def finished_b(event) + @done_b << [event.new_element, event.new_position] + end + end + callbacks.reset + callbacks + end + + def __balanced_callback + cb = Object.new + class << cb + attr_reader :result + + def reset + @result = "" + end + + def match(event) + @result << "M#{event.old_position}#{event.new_position} " + end + + def discard_a(event) + @result << "DA#{event.old_position}#{event.new_position} " + end + + def discard_b(event) + @result << "DB#{event.old_position}#{event.new_position} " + end + + def change(event) + @result << "C#{event.old_position}#{event.new_position} " + end + end + cb.reset + cb + end + + def setup + @seq1 = %w(a b c e h j l m n p) + @seq2 = %w(b c d e f j k l m r s t) + + @correct_lcs = %w(b c e j l m) + + @skipped_seq1 = 'a h n p' + @skipped_seq2 = 'd f k r s t' + + correct_diff = [ + [ [ '-', 0, 'a' ] ], + [ [ '+', 2, 'd' ] ], + [ [ '-', 4, 'h' ], + [ '+', 4, 'f' ] ], + [ [ '+', 6, 'k' ] ], + [ [ '-', 8, 'n' ], + [ '-', 9, 'p' ], + [ '+', 9, 'r' ], + [ '+', 10, 's' ], + [ '+', 11, 't' ] ] ] + @correct_diff = __map_diffs(correct_diff, Diff::LCS::Change) + end +end + +class TestLCS < Test::Unit::TestCase + include Diff::LCS::Tests + + def test_lcs + res = ares = bres = nil + assert_nothing_raised { res = Diff::LCS.__lcs(@seq1, @seq2) } + # The result of the LCS (less the +nil+ values) must be as long as the + # correct result. + assert_equal(res.compact.size, @correct_lcs.size) + res.each_with_index { |ee, ii| assert(ee.nil? || (@seq1[ii] == @seq2[ee])) } + assert_nothing_raised { ares = (0...res.size).map { |ii| res[ii] ? @seq1[ii] : nil } } + assert_nothing_raised { bres = (0...res.size).map { |ii| res[ii] ? @seq2[res[ii]] : nil } } + assert_equal(@correct_lcs, ares.compact) + assert_equal(@correct_lcs, bres.compact) + assert_nothing_raised { res = Diff::LCS.LCS(@seq1, @seq2) } + assert_equal(res.compact, @correct_lcs) + end +end + +class TestSequences < Test::Unit::TestCase + include Diff::LCS::Tests + + def test_sequences + callbacks = nil + assert_nothing_raised do + callbacks = __simple_callbacks + class << callbacks + undef :finished_a + undef :finished_b + end + Diff::LCS.traverse_sequences(@seq1, @seq2, callbacks) + end + assert_equal(@correct_lcs.size, callbacks.matched_a.size) + assert_equal(@correct_lcs.size, callbacks.matched_b.size) + assert_equal(@skipped_seq1, callbacks.discards_a.join(" ")) + assert_equal(@skipped_seq2, callbacks.discards_b.join(" ")) + assert_nothing_raised do + callbacks = __simple_callbacks + Diff::LCS.traverse_sequences(@seq1, @seq2, callbacks) + end + assert_equal(@correct_lcs.size, callbacks.matched_a.size) + assert_equal(@correct_lcs.size, callbacks.matched_b.size) + assert_equal(@skipped_seq1, callbacks.discards_a.join(" ")) + assert_equal(@skipped_seq2, callbacks.discards_b.join(" ")) + assert_equal(9, callbacks.done_a[0][1]) + assert_nil(callbacks.done_b[0]) + +# seqw = %w(abcd efgh ijkl mnopqrstuvwxyz) +# assert_nothing_raised do +# callbacks = __simple_callbacks +# class << callbacks +# undef :finished_a +# undef :finished_b +# end +# Diff::LCS.traverse_sequences(seqw, [], callbacks) +# end + end + + def test_diff + diff = nil + assert_nothing_raised { diff = Diff::LCS.diff(@seq1, @seq2) } + assert_equal(__format_diffs(@correct_diff), __format_diffs(diff)) + assert_equal(@correct_diff, diff) + end + + def test_diff_empty + seqw = %w(abcd efgh ijkl mnopqrstuvwxyz) + correct_diff = [ + [ [ '-', 0, 'abcd' ], + [ '-', 1, 'efgh' ], + [ '-', 2, 'ijkl' ], + [ '-', 3, 'mnopqrstuvwxyz' ] ] ] + diff = nil + + assert_nothing_raised { diff = Diff::LCS.diff(seqw, []) } + assert_equal(__format_diffs(correct_diff), __format_diffs(diff)) + + correct_diff = [ + [ [ '+', 0, 'abcd' ], + [ '+', 1, 'efgh' ], + [ '+', 2, 'ijkl' ], + [ '+', 3, 'mnopqrstuvwxyz' ] ] ] + assert_nothing_raised { diff = Diff::LCS.diff([], seqw) } + assert_equal(__format_diffs(correct_diff), __format_diffs(diff)) + end +end + +class TestBalanced < Test::Unit::TestCase + include Diff::LCS::Tests + + def test_sdiff_a + sdiff = nil + seq1 = %w(abc def yyy xxx ghi jkl) + seq2 = %w(abc dxf xxx ghi jkl) + correct_sdiff = [ + [ '=', [ 0, 'abc' ], [ 0, 'abc' ] ], + [ '!', [ 1, 'def' ], [ 1, 'dxf' ] ], + [ '-', [ 2, 'yyy' ], [ 2, nil ] ], + [ '=', [ 3, 'xxx' ], [ 2, 'xxx' ] ], + [ '=', [ 4, 'ghi' ], [ 3, 'ghi' ] ], + [ '=', [ 5, 'jkl' ], [ 4, 'jkl' ] ] ] + correct_sdiff = __map_diffs(correct_sdiff) + assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } + assert_equal(correct_sdiff, sdiff) + end + + def test_sdiff_b + sdiff = nil + correct_sdiff = [ + [ '-', [ 0, 'a' ], [ 0, nil ] ], + [ '=', [ 1, 'b' ], [ 0, 'b' ] ], + [ '=', [ 2, 'c' ], [ 1, 'c' ] ], + [ '+', [ 3, nil ], [ 2, 'd' ] ], + [ '=', [ 3, 'e' ], [ 3, 'e' ] ], + [ '!', [ 4, 'h' ], [ 4, 'f' ] ], + [ '=', [ 5, 'j' ], [ 5, 'j' ] ], + [ '+', [ 6, nil ], [ 6, 'k' ] ], + [ '=', [ 6, 'l' ], [ 7, 'l' ] ], + [ '=', [ 7, 'm' ], [ 8, 'm' ] ], + [ '!', [ 8, 'n' ], [ 9, 'r' ] ], + [ '!', [ 9, 'p' ], [ 10, 's' ] ], + [ '+', [ 10, nil ], [ 11, 't' ] ] ] + correct_sdiff = __map_diffs(correct_sdiff) + assert_nothing_raised { sdiff = Diff::LCS.sdiff(@seq1, @seq2) } + assert_equal(correct_sdiff, sdiff) + end + + def test_sdiff_c + sdiff = nil + seq1 = %w(a b c d e) + seq2 = %w(a e) + correct_sdiff = [ + [ '=', [ 0, 'a' ], [ 0, 'a' ] ], + [ '-', [ 1, 'b' ], [ 1, nil ] ], + [ '-', [ 2, 'c' ], [ 1, nil ] ], + [ '-', [ 3, 'd' ], [ 1, nil ] ], + [ '=', [ 4, 'e' ], [ 1, 'e' ] ] ] + correct_sdiff = __map_diffs(correct_sdiff) + assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } + assert_equal(correct_sdiff, sdiff) + end + + def test_sdiff_d + sdiff = nil + seq1 = %w(a e) + seq2 = %w(a b c d e) + correct_sdiff = [ + [ '=', [ 0, 'a' ], [ 0, 'a' ] ], + [ '+', [ 1, nil ], [ 1, 'b' ] ], + [ '+', [ 1, nil ], [ 2, 'c' ] ], + [ '+', [ 1, nil ], [ 3, 'd' ] ], + [ '=', [ 1, 'e' ], [ 4, 'e' ] ] ] + correct_sdiff = __map_diffs(correct_sdiff) + assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } + assert_equal(correct_sdiff, sdiff) + end + + def test_sdiff_e + sdiff = nil + seq1 = %w(v x a e) + seq2 = %w(w y a b c d e) + correct_sdiff = [ + [ '!', [ 0, 'v' ], [ 0, 'w' ] ], + [ '!', [ 1, 'x' ], [ 1, 'y' ] ], + [ '=', [ 2, 'a' ], [ 2, 'a' ] ], + [ '+', [ 3, nil ], [ 3, 'b' ] ], + [ '+', [ 3, nil ], [ 4, 'c' ] ], + [ '+', [ 3, nil ], [ 5, 'd' ] ], + [ '=', [ 3, 'e' ], [ 6, 'e' ] ] ] + correct_sdiff = __map_diffs(correct_sdiff) + assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } + assert_equal(correct_sdiff, sdiff) + end + + def test_sdiff_f + sdiff = nil + seq1 = %w(x a e) + seq2 = %w(a b c d e) + correct_sdiff = [ + [ '-', [ 0, 'x' ], [ 0, nil ] ], + [ '=', [ 1, 'a' ], [ 0, 'a' ] ], + [ '+', [ 2, nil ], [ 1, 'b' ] ], + [ '+', [ 2, nil ], [ 2, 'c' ] ], + [ '+', [ 2, nil ], [ 3, 'd' ] ], + [ '=', [ 2, 'e' ], [ 4, 'e' ] ] ] + correct_sdiff = __map_diffs(correct_sdiff) + assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } + assert_equal(correct_sdiff, sdiff) + end + + def test_sdiff_g + sdiff = nil + seq1 = %w(a e) + seq2 = %w(x a b c d e) + correct_sdiff = [ + [ '+', [ 0, nil ], [ 0, 'x' ] ], + [ '=', [ 0, 'a' ], [ 1, 'a' ] ], + [ '+', [ 1, nil ], [ 2, 'b' ] ], + [ '+', [ 1, nil ], [ 3, 'c' ] ], + [ '+', [ 1, nil ], [ 4, 'd' ] ], + [ '=', [ 1, 'e' ], [ 5, 'e' ] ] ] + correct_sdiff = __map_diffs(correct_sdiff) + assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } + assert_equal(correct_sdiff, sdiff) + end + + def test_sdiff_h + sdiff = nil + seq1 = %w(a e v) + seq2 = %w(x a b c d e w x) + correct_sdiff = [ + [ '+', [ 0, nil ], [ 0, 'x' ] ], + [ '=', [ 0, 'a' ], [ 1, 'a' ] ], + [ '+', [ 1, nil ], [ 2, 'b' ] ], + [ '+', [ 1, nil ], [ 3, 'c' ] ], + [ '+', [ 1, nil ], [ 4, 'd' ] ], + [ '=', [ 1, 'e' ], [ 5, 'e' ] ], + [ '!', [ 2, 'v' ], [ 6, 'w' ] ], + [ '+', [ 3, nil ], [ 7, 'x' ] ] ] + correct_sdiff = __map_diffs(correct_sdiff) + assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } + assert_equal(correct_sdiff, sdiff) + end + + def test_sdiff_i + sdiff = nil + seq1 = %w() + seq2 = %w(a b c) + correct_sdiff = [ + [ '+', [ 0, nil ], [ 0, 'a' ] ], + [ '+', [ 0, nil ], [ 1, 'b' ] ], + [ '+', [ 0, nil ], [ 2, 'c' ] ] ] + correct_sdiff = __map_diffs(correct_sdiff) + assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } + assert_equal(correct_sdiff, sdiff) + end + + def test_sdiff_j + sdiff = nil + seq1 = %w(a b c) + seq2 = %w() + correct_sdiff = [ + [ '-', [ 0, 'a' ], [ 0, nil ] ], + [ '-', [ 1, 'b' ], [ 0, nil ] ], + [ '-', [ 2, 'c' ], [ 0, nil ] ] ] + correct_sdiff = __map_diffs(correct_sdiff) + assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } + assert_equal(correct_sdiff, sdiff) + end + + def test_sdiff_k + sdiff = nil + seq1 = %w(a b c) + seq2 = %w(1) + correct_sdiff = [ + [ '!', [ 0, 'a' ], [ 0, '1' ] ], + [ '-', [ 1, 'b' ], [ 1, nil ] ], + [ '-', [ 2, 'c' ], [ 1, nil ] ] ] + correct_sdiff = __map_diffs(correct_sdiff) + assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } + assert_equal(correct_sdiff, sdiff) + end + + def test_sdiff_l + sdiff = nil + seq1 = %w(a b c) + seq2 = %w(c) + correct_sdiff = [ + [ '-', [ 0, 'a' ], [ 0, nil ] ], + [ '-', [ 1, 'b' ], [ 0, nil ] ], + [ '=', [ 2, 'c' ], [ 0, 'c' ] ] + ] + correct_sdiff = __map_diffs(correct_sdiff) + assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } + assert_equal(correct_sdiff, sdiff) + end + + def test_sdiff_m + sdiff = nil + seq1 = %w(abcd efgh ijkl mnop) + seq2 = [] + correct_sdiff = [ + [ '-', [ 0, 'abcd' ], [ 0, nil ] ], + [ '-', [ 1, 'efgh' ], [ 0, nil ] ], + [ '-', [ 2, 'ijkl' ], [ 0, nil ] ], + [ '-', [ 3, 'mnop' ], [ 0, nil ] ] + ] + correct_sdiff = __map_diffs(correct_sdiff) + assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } + assert_equal(correct_sdiff, sdiff) + end + + def test_sdiff_n + sdiff = nil + seq1 = [] + seq2 = %w(abcd efgh ijkl mnop) + correct_sdiff = [ + [ '+', [ 0, nil ], [ 0, 'abcd' ] ], + [ '+', [ 0, nil ], [ 1, 'efgh' ] ], + [ '+', [ 0, nil ], [ 2, 'ijkl' ] ], + [ '+', [ 0, nil ], [ 3, 'mnop' ] ] + ] + correct_sdiff = __map_diffs(correct_sdiff) + assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } + assert_equal(correct_sdiff, sdiff) + end + + def test_balanced_a + seq1 = %w(a b c) + seq2 = %w(a x c) + callback = nil + assert_nothing_raised { callback = __balanced_callback } + assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } + assert_equal("M00 C11 M22 ", callback.result) + end + + def test_balanced_b + seq1 = %w(a b c) + seq2 = %w(a x c) + callback = nil + assert_nothing_raised do + callback = __balanced_callback + class << callback + undef change + end + end + assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } + assert_equal("M00 DA11 DB21 M22 ", callback.result) + end + + def test_balanced_c + seq1 = %w(a x y c) + seq2 = %w(a v w c) + callback = nil + assert_nothing_raised { callback = __balanced_callback } + assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } + assert_equal("M00 C11 C22 M33 ", callback.result) + end + + def test_balanced_d + seq1 = %w(x y c) + seq2 = %w(v w c) + callback = nil + assert_nothing_raised { callback = __balanced_callback } + assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } + assert_equal("C00 C11 M22 ", callback.result) + end + + def test_balanced_e + seq1 = %w(a x y z) + seq2 = %w(b v w) + callback = nil + assert_nothing_raised { callback = __balanced_callback } + assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } + assert_equal("C00 C11 C22 DA33 ", callback.result) + end + + def test_balanced_f + seq1 = %w(a z) + seq2 = %w(a) + callback = nil + assert_nothing_raised { callback = __balanced_callback } + assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } + assert_equal("M00 DA11 ", callback.result) + end + + def test_balanced_g + seq1 = %w(z a) + seq2 = %w(a) + callback = nil + assert_nothing_raised { callback = __balanced_callback } + assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } + assert_equal("DA00 M10 ", callback.result) + end + + def test_balanced_h + seq1 = %w(a b c) + seq2 = %w(x y z) + callback = nil + assert_nothing_raised { callback = __balanced_callback } + assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } + assert_equal("C00 C11 C22 ", callback.result) + end + + def test_balanced_i + seq1 = %w(abcd efgh ijkl mnopqrstuvwxyz) + seq2 = [] + callback = nil + assert_nothing_raised { callback = __balanced_callback } + assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } + assert_equal("DA00 DA10 DA20 DA30 ", callback.result) + end + + def test_balanced_j + seq1 = [] + seq2 = %w(abcd efgh ijkl mnopqrstuvwxyz) + callback = nil + assert_nothing_raised { callback = __balanced_callback } + assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } + assert_equal("DB00 DB01 DB02 DB03 ", callback.result) + end +end + +class TestPatching < Test::Unit::TestCase + include Diff::LCS::Tests + + def test_patch_diff + ps = ms1 = ms2 = ms3 = nil + assert_nothing_raised do + ps = Diff::LCS.diff(@seq1, @seq2) + ms1 = Diff::LCS.patch(@seq1, ps) + ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) + ms3 = Diff::LCS.patch(@seq2, ps) + end + assert_equal(@seq2, ms1) + assert_equal(@seq1, ms2) + assert_equal(@seq1, ms3) + assert_nothing_raised do + ps = Diff::LCS.diff(@seq1, @seq2, Diff::LCS::ContextDiffCallbacks) + ms1 = Diff::LCS.patch(@seq1, ps) + ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) + ms2 = Diff::LCS.patch(@seq2, ps) + end + assert_equal(@seq2, ms1) + assert_equal(@seq1, ms2) + assert_equal(@seq1, ms3) + assert_nothing_raised do + ps = Diff::LCS.diff(@seq1, @seq2, Diff::LCS::SDiffCallbacks) + ms1 = Diff::LCS.patch(@seq1, ps) + ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) + ms3 = Diff::LCS.patch(@seq2, ps) + end + assert_equal(@seq2, ms1) + assert_equal(@seq1, ms2) + assert_equal(@seq1, ms3) + end + + # Tests patch bug #891: + # http://rubyforge.org/tracker/?func=detail&atid=407&aid=891&group_id=84 + def test_patch_bug891 + s1 = s2 = s3 = s4 = s5 = ps = nil + assert_nothing_raised do + s1 = %w{a b c d e f g h i j k } + s2 = %w{a b c d D e f g h i j k } + ps = Diff::LCS::diff(s1, s2) + s3 = Diff::LCS.patch(s1, ps, :patch) + ps = Diff::LCS::diff(s1, s2, Diff::LCS::ContextDiffCallbacks) + s4 = Diff::LCS.patch(s1, ps, :patch) + ps = Diff::LCS::diff(s1, s2, Diff::LCS::SDiffCallbacks) + s5 = Diff::LCS.patch(s1, ps, :patch) + end + assert_equal(s2, s3) + assert_equal(s2, s4) + assert_equal(s2, s5) + + assert_nothing_raised do + ps = Diff::LCS::sdiff(s1, s2) + s3 = Diff::LCS.patch(s1, ps, :patch) + ps = Diff::LCS::diff(s1, s2, Diff::LCS::ContextDiffCallbacks) + s4 = Diff::LCS.patch(s1, ps, :patch) + ps = Diff::LCS::diff(s1, s2, Diff::LCS::DiffCallbacks) + s5 = Diff::LCS.patch(s1, ps, :patch) + end + assert_equal(s2, s3) + assert_equal(s2, s4) + assert_equal(s2, s5) + end + + def test_patch_sdiff + ps = ms1 = ms2 = ms3 = nil + assert_nothing_raised do + ps = Diff::LCS.sdiff(@seq1, @seq2) + ms1 = Diff::LCS.patch(@seq1, ps) + ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) + ms3 = Diff::LCS.patch(@seq2, ps) + end + assert_equal(@seq2, ms1) + assert_equal(@seq1, ms2) + assert_equal(@seq1, ms3) + assert_nothing_raised do + ps = Diff::LCS.sdiff(@seq1, @seq2, Diff::LCS::ContextDiffCallbacks) + ms1 = Diff::LCS.patch(@seq1, ps) + ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) + ms3 = Diff::LCS.patch(@seq2, ps) + end + assert_equal(@seq2, ms1) + assert_equal(@seq1, ms2) + assert_equal(@seq1, ms3) + assert_nothing_raised do + ps = Diff::LCS.sdiff(@seq1, @seq2, Diff::LCS::DiffCallbacks) + ms1 = Diff::LCS.patch(@seq1, ps) + ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) + ms3 = Diff::LCS.patch(@seq2, ps) + end + assert_equal(@seq2, ms1) + assert_equal(@seq1, ms2) + assert_equal(@seq1, ms3) + end +end From ccbe5c28a7a61ecd59fa59fb62c9e5025b993ce9 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Mon, 26 Jan 2009 08:27:17 -0800 Subject: [PATCH 077/387] [FIX] More binary file types, inspired by slow counting performance of KDE --- lib/ohcount/detector.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index c1f0f12..f7bafa8 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -84,9 +84,11 @@ def self.binary_filename?(filename) ".avi", ".bmp", ".cache", + ".dat", ".doc", ".gif", ".gz", + ".icns", ".jar", ".jpeg", ".jpg", @@ -97,9 +99,12 @@ def self.binary_filename?(filename) ".ogg", ".pdf", ".png", + ".pnt", ".ppt", ".qt", ".ra", + ".svg", + ".svgz", ".svn", ".swf", ".tar", @@ -111,7 +116,7 @@ def self.binary_filename?(filename) ".xlw", ".zip" ] - ignore.include?(File.extname(filename)) + ignore.include?(File.extname(filename).downcase) end # If an extension maps to a string, that string must be the name of a glot. From 2ad2bcb281d3faac82cf57d04745cfb330aef9ba Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Mon, 26 Jan 2009 21:11:18 -0800 Subject: [PATCH 078/387] [FIX] Make tests pass on Ubuntu 8.10 -- `file` returns simply "XML" when it's an XML file with a custom file extension. --- lib/ohcount/detector.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index f7bafa8..3801036 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -599,7 +599,7 @@ def self.disambiguate_nil(source_file) when "Bourne-Again" return "shell" end - when /XML( 1\.0)? document text/ + when /XML( 1\.0)? document text/, /^XML$/ return 'xml' end # dang... no dice From becb6f63eec7c0206980da9692f1eb48e830c641 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Mon, 26 Jan 2009 21:40:57 -0800 Subject: [PATCH 079/387] [FIX] Expand the 'language' column by 2 chars to fit 'structured_basic' completely. Honestly I'd rather shorten the name of the language.... --- bin/ohcount | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bin/ohcount b/bin/ohcount index 45a409d..b423221 100755 --- a/bin/ohcount +++ b/bin/ohcount @@ -162,8 +162,8 @@ HELP puts puts "Ohloh Line Count".center(76) - puts "Language Code Comment Comment % Blank Total File" - puts "-------------- --------- --------- --------- --------- --------- -----------------------------------------------" + puts "Language Code Comment Comment % Blank Total File" + puts "---------------- --------- --------- --------- --------- --------- -----------------------------------------------" source_file_list.analyze(:language) do |s| s.language_breakdowns.sort {|l1,l2| l2.name <=> l1.name}.each do |lb| @@ -173,7 +173,7 @@ HELP end def write_individual_row(file, name, code, comment, blank) - printf("%-14s",name) + printf("%-16s",name) printf(" %10d",code) printf(" %10d",comment) if comment+code > 0 @@ -203,15 +203,15 @@ HELP puts "Ohloh Line Count Summary".center(76) puts - puts "Language Files Code Comment Comment % Blank Total" - puts "-------------- ----- --------- --------- --------- --------- ---------" + puts "Language Files Code Comment Comment % Blank Total" + puts "---------------- ----- --------- --------- --------- --------- ---------" language_facts = source_file_list.language_facts language_facts.fact_map.values.sort { |a,b| b.code <=> a.code}.each do |lf| write_summary_row(lf.language, lf.filecount, lf.code, lf.comments, lf.blanks) end - puts "-------------- ----- --------- --------- --------- --------- ---------" + puts "---------------- ----- --------- --------- --------- --------- ---------" write_summary_row('Total', language_facts.filecount, language_facts.code, language_facts.comments, @@ -223,7 +223,7 @@ HELP end def write_summary_row(name, file_count, code, comment, blank) - printf("%-14s", name) + printf("%-16s", name) printf(" %6d", file_count) printf(" %10d", code) printf(" %10d", comment) From 896dd100736ab80a7da03347bd4f8477483a161c Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Wed, 28 Jan 2009 13:10:07 -0800 Subject: [PATCH 080/387] [CHANGE] Some cleanups to lib/ohcount/source_file.rb --- lib/gestalt/rules/c_header_rule.rb | 4 ++-- lib/gestalt/rules/c_keyword_rule.rb | 4 ++-- lib/gestalt/rules/java_import_rule.rb | 2 +- lib/gestalt/rules/keyword_rule.rb | 4 ++-- lib/ohcount/language_facts.rb | 2 +- lib/ohcount/source_file.rb | 33 +++++++++------------------------ log/.gitignore | 1 + test/unit/source_file_test.rb | 2 +- 8 files changed, 19 insertions(+), 33 deletions(-) create mode 100644 log/.gitignore diff --git a/lib/gestalt/rules/c_header_rule.rb b/lib/gestalt/rules/c_header_rule.rb index bcc83ee..1d49342 100644 --- a/lib/gestalt/rules/c_header_rule.rb +++ b/lib/gestalt/rules/c_header_rule.rb @@ -12,8 +12,8 @@ def initialize(*args) def trigger_file?(source_file) return false unless ['c','cpp'].include?(source_file.polyglot) - regexp.match(source_file.language_breakdowns('c').code) || - regexp.match(source_file.language_breakdowns('cpp').code) + regexp.match(source_file.language_breakdown('c').code) || + regexp.match(source_file.language_breakdown('cpp').code) end def regexp diff --git a/lib/gestalt/rules/c_keyword_rule.rb b/lib/gestalt/rules/c_keyword_rule.rb index 2827cb4..2977f43 100644 --- a/lib/gestalt/rules/c_keyword_rule.rb +++ b/lib/gestalt/rules/c_keyword_rule.rb @@ -8,8 +8,8 @@ def initialize(*keywords) def trigger_file?(source_file) return false unless ['c','cpp'].include?(source_file.polyglot) - regexp.match(source_file.language_breakdowns('c').code) || - regexp.match(source_file.language_breakdowns('cpp').code) + regexp.match(source_file.language_breakdown('c').code) || + regexp.match(source_file.language_breakdown('cpp').code) end end end diff --git a/lib/gestalt/rules/java_import_rule.rb b/lib/gestalt/rules/java_import_rule.rb index fc2ac0c..1b6ff7d 100644 --- a/lib/gestalt/rules/java_import_rule.rb +++ b/lib/gestalt/rules/java_import_rule.rb @@ -12,7 +12,7 @@ def initialize(*args) def trigger_file?(source_file) return false unless source_file.polyglot == 'java' - regexp.match(source_file.language_breakdowns('java').code) + regexp.match(source_file.language_breakdown('java').code) end def regexp diff --git a/lib/gestalt/rules/keyword_rule.rb b/lib/gestalt/rules/keyword_rule.rb index 17891dc..b9d6743 100644 --- a/lib/gestalt/rules/keyword_rule.rb +++ b/lib/gestalt/rules/keyword_rule.rb @@ -12,8 +12,8 @@ def initialize(language, *args) end def trigger_file?(source_file) - return unless source_file.language_breakdowns(language) - regexp.match(source_file.language_breakdowns(language).code) + return unless source_file.language_breakdown(language) + regexp.match(source_file.language_breakdown(language).code) end def regexp diff --git a/lib/ohcount/language_facts.rb b/lib/ohcount/language_facts.rb index 3373588..820081e 100644 --- a/lib/ohcount/language_facts.rb +++ b/lib/ohcount/language_facts.rb @@ -12,7 +12,7 @@ def initialize end def process(source_file) - return unless source_file.source_code? + return unless source_file.polyglot source_file.language_breakdowns.each do |lb| lang = lb.name lang_fact = @fact_map[lang] ||= LanguageFact.new(lang) diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb index 3175292..c4d231a 100644 --- a/lib/ohcount/source_file.rb +++ b/lib/ohcount/source_file.rb @@ -74,29 +74,16 @@ def basename File.basename(filename) end - # returns TRUE if this source_file is recognized as being - # some type of source code - def source_code? - !!polyglot - end - def parse(&block) - @language_breakdowns = [] - return unless polyglot - @language_breakdowns = Ohcount::parse(contents, polyglot, &block) + @language_breakdowns = polyglot ? Ohcount::parse(contents, polyglot, &block) : [] end - def parsed? - !(@language_breakdowns.nil?) + def language_breakdowns + @language_breakdowns ||= parse end - def language_breakdowns(language = nil) - parse unless parsed? - if language - return @language_breakdowns.find { |lb| lb.name == language.to_s } || - LanguageBreakdown.new(language.to_s) - end - @language_breakdowns + def language_breakdown(language) + language_breakdowns.find { |lb| lb.name == language.to_s } || LanguageBreakdown.new(language.to_s) end def clone_and_rename(new_name) @@ -143,15 +130,13 @@ def licenses end def raw_entities(&block) - return unless source_code? - Ohcount::parse_entities(contents, polyglot, &block) + polyglot && Ohcount::parse_entities(contents, polyglot, &block) end # returns the list of languages included in the parsed # language_breakdowns def languages - parse unless parsed? - @language_breakdowns.collect { |lb| lb.name } + language_breakdowns.collect { |lb| lb.name } end # returns a collection of sloc_infos containing @@ -161,8 +146,8 @@ def diff(new) all_languages = (self.languages + new.languages).uniq all_languages.collect do |language| si = Ohcount::SlocInfo.new(language) - lb_old = language_breakdowns(language) - lb_new = new.language_breakdowns(language) + lb_old = language_breakdown(language) + lb_new = new.language_breakdown(language) #code si.code_added, si.code_removed = calc_diff(lb_old.code, lb_new.code) diff --git a/log/.gitignore b/log/.gitignore new file mode 100644 index 0000000..397b4a7 --- /dev/null +++ b/log/.gitignore @@ -0,0 +1 @@ +*.log diff --git a/test/unit/source_file_test.rb b/test/unit/source_file_test.rb index 93a8ea7..2ae7d1d 100644 --- a/test/unit/source_file_test.rb +++ b/test/unit/source_file_test.rb @@ -17,7 +17,7 @@ def test_language_breakdowns contents = "x = 5" f = SourceFile.new("foo.rb", :contents => contents) assert_equal 'ruby', f.language_breakdowns[0].name - assert_equal contents, f.language_breakdowns('ruby').code + assert_equal contents, f.language_breakdown('ruby').code end def test_parse From 8bdc02df555108c2bb5f949fffbba60605fdedf6 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Wed, 28 Jan 2009 14:43:06 -0800 Subject: [PATCH 081/387] [NEW] General objects for keeping track of line counts and line count deltas. --- lib/ohcount.rb | 5 ++ lib/ohcount/loc.rb | 23 ++++++++ lib/ohcount/loc_delta.rb | 39 ++++++++++++++ lib/ohcount/loc_delta_list.rb | 83 +++++++++++++++++++++++++++++ lib/ohcount/loc_list.rb | 58 ++++++++++++++++++++ test/unit/loc_delta_list_test.rb | 112 +++++++++++++++++++++++++++++++++++++++ test/unit/loc_delta_test.rb | 57 ++++++++++++++++++++ test/unit/loc_list_test.rb | 80 ++++++++++++++++++++++++++++ test/unit/loc_test.rb | 38 +++++++++++++ 9 files changed, 495 insertions(+) create mode 100644 lib/ohcount/loc.rb create mode 100644 lib/ohcount/loc_delta.rb create mode 100644 lib/ohcount/loc_delta_list.rb create mode 100644 lib/ohcount/loc_list.rb create mode 100644 test/unit/loc_delta_list_test.rb create mode 100644 test/unit/loc_delta_test.rb create mode 100644 test/unit/loc_list_test.rb create mode 100644 test/unit/loc_test.rb diff --git a/lib/ohcount.rb b/lib/ohcount.rb index 84dcd74..997e9cd 100644 --- a/lib/ohcount.rb +++ b/lib/ohcount.rb @@ -13,6 +13,11 @@ module Ohcount require "lib/#{Config::CONFIG['arch']}/ohcount_native" end +require 'lib/ohcount/loc' +require 'lib/ohcount/loc_list' +require 'lib/ohcount/loc_delta' +require 'lib/ohcount/loc_delta_list' + require "lib/ohcount/scratch_dir" require "lib/ohcount/helpers" require "lib/ohcount/detector" diff --git a/lib/ohcount/loc.rb b/lib/ohcount/loc.rb new file mode 100644 index 0000000..e0a5a5d --- /dev/null +++ b/lib/ohcount/loc.rb @@ -0,0 +1,23 @@ +module Ohcount + # Tracks total lines of code, comments, and blanks for a single language + class Loc + attr_accessor :language, :code, :comments, :blanks + + def initialize(params={}) + @code = @comments = @blanks = 0 + params.each { |k,v| send(k.to_s + '=', v) if respond_to?(k.to_s + '=') } + end + + def total + @code + @comments + @blanks + end + + def +(addend) + raise ArgumentError.new("Cannot add language '#{addend.language}' to language '#{language}'") unless addend.language == language + @code += addend.code + @comments += addend.comments + @blanks += addend.blanks + self + end + end +end diff --git a/lib/ohcount/loc_delta.rb b/lib/ohcount/loc_delta.rb new file mode 100644 index 0000000..ea570e7 --- /dev/null +++ b/lib/ohcount/loc_delta.rb @@ -0,0 +1,39 @@ +module Ohcount + # Tracks change to lines of code, comments, and blanks for a single language + class LocDelta + attr_accessor :language, :code_added, :code_removed, :comments_added, :comments_removed, :blanks_added, :blanks_removed + + def initialize(params={}) + @code_added = @code_removed = @comments_added = @comments_removed = @blanks_added = @blanks_removed = 0 + params.each { |k,v| send(k.to_s + '=', v) if respond_to?(k.to_s + '=') } + end + + def net_code + @code_added - @code_removed + end + + def net_comments + @comments_added - @comments_removed + end + + def net_blanks + @blanks_added - @blanks_removed + end + + def net_total + net_code + net_comments + net_blanks + end + + def +(addend) + raise ArgumentError.new("Cannot add language '#{addend.language}' to language '#{language}'") unless addend.language == language + @code_added += addend.code_added + @code_removed += addend.code_removed + @comments_added += addend.comments_added + @comments_removed += addend.comments_removed + @blanks_added += addend.blanks_added + @blanks_removed += addend.blanks_removed + self + end + end +end + diff --git a/lib/ohcount/loc_delta_list.rb b/lib/ohcount/loc_delta_list.rb new file mode 100644 index 0000000..82c158a --- /dev/null +++ b/lib/ohcount/loc_delta_list.rb @@ -0,0 +1,83 @@ +module Ohcount + # Tracks changes to lines of code, comments, and blanks for multiple languages + class LocDeltaList + attr_accessor :loc_deltas + + def initialize(loc_deltas=[]) + @loc_deltas = loc_deltas + end + + def loc_delta(language) + @loc_deltas.find { |loc_delta| loc_delta.language == language } + end + + def languages + @loc_deltas.collect { |loc_delta| loc_delta.language } + end + + def +(addend) + case addend + when LocDelta + add_loc_delta(addend) + else + raise ArgumentError.new + end + end + + def add_loc_delta(addend) + existing = loc_delta(addend.language) + if existing + existing += addend + else + @loc_deltas << addend + end + self + end + + def code_added + @loc_deltas.inject(0) { |sum, delta| sum + delta.code_added } + end + + def code_removed + @loc_deltas.inject(0) { |sum, delta| sum + delta.code_removed } + end + + def comments_added + @loc_deltas.inject(0) { |sum, delta| sum + delta.comments_added } + end + + def comments_removed + @loc_deltas.inject(0) { |sum, delta| sum + delta.comments_removed } + end + + def blanks_added + @loc_deltas.inject(0) { |sum, delta| sum + delta.blanks_added } + end + + def blanks_removed + @loc_deltas.inject(0) { |sum, delta| sum + delta.blanks_removed } + end + + def net_code + @loc_deltas.inject(0) { |sum, delta| sum + delta.net_code } + end + + def net_comments + @loc_deltas.inject(0) { |sum, delta| sum + delta.net_comments } + end + + def net_blanks + @loc_deltas.inject(0) { |sum, delta| sum + delta.net_blanks } + end + + def net_total + @loc_deltas.inject(0) { |sum, delta| sum + delta.net_total } + end + + # Returns a new LocDeltaList excluding all languages that have 0 net changes + def compact + LocDeltaList.new(@loc_deltas.reject{ |delta| delta.net_total == 0 }) + end + + end +end diff --git a/lib/ohcount/loc_list.rb b/lib/ohcount/loc_list.rb new file mode 100644 index 0000000..f8f6d34 --- /dev/null +++ b/lib/ohcount/loc_list.rb @@ -0,0 +1,58 @@ +module Ohcount + # Tracks total lines of code, comments, and blanks for multiple languages + class LocList + attr_accessor :locs + + def initialize(locs=[]) + @locs = locs + end + + def loc(language) + @locs.find { |loc| loc.language == language } + end + + def languages + @locs.collect { |loc| loc.language } + end + + def +(addend) + case addend + when Loc + add_loc(addend) + else + raise ArgumentError.new + end + end + + def add_loc(addend) + existing = loc(addend.language) + if existing + existing += addend + else + @locs << addend + end + self + end + + def code + @locs.inject(0) { |sum, loc| sum + loc.code } + end + + def comments + @locs.inject(0) { |sum, loc| sum + loc.comments } + end + + def blanks + @locs.inject(0) { |sum, loc| sum + loc.blanks } + end + + def total + @locs.inject(0) { |sum, loc| sum + loc.total } + end + + # Returns a new loc_list excluding all languages with 0 lines + def compact + LocList.new(@locs.reject { |loc| loc.total == 0 }) + end + end +end diff --git a/test/unit/loc_delta_list_test.rb b/test/unit/loc_delta_list_test.rb new file mode 100644 index 0000000..114c606 --- /dev/null +++ b/test/unit/loc_delta_list_test.rb @@ -0,0 +1,112 @@ +require File.dirname(__FILE__) + '/../test_helper' +include Ohcount + +class LocDeltaListTest < Ohcount::Test + def test_loc_list_default + list = LocDeltaList.new + assert_equal [], list.loc_deltas + assert_equal [], list.languages + end + + def test_loc_selector + list = LocDeltaList.new + c = LocDelta.new(:language => 'c') + java = LocDelta.new(:language => 'java') + + list.loc_deltas = [c, java] + + assert_equal c, list.loc_delta('c') + assert_equal java, list.loc_delta('java') + end + + def test_first_add + list = LocDeltaList.new + loc_delta = LocDelta.new(:language => 'c', :code_added => 1, :code_removed => 10, + :comments_added => 2, :comments_removed => 20, :blanks_added => 3, :blanks_removed => 30) + list += loc_delta + + assert_equal ['c'], list.languages + assert_equal 1, list.code_added + assert_equal 10, list.code_removed + assert_equal 2, list.comments_added + assert_equal 20, list.comments_removed + assert_equal 3, list.blanks_added + assert_equal 30, list.blanks_removed + end + + def test_add_two_languages + list = LocDeltaList.new + + c = LocDelta.new(:language => 'c', :code_added => 1, :code_removed => 10, + :comments_added => 2, :comments_removed => 20, :blanks_added => 3, :blanks_removed => 30) + list += c + + java = LocDelta.new(:language => 'java', :code_added => 100, :code_removed => 1000, + :comments_added => 200, :comments_removed => 2000, :blanks_added => 300, :blanks_removed => 3000) + list += java + + assert list.loc_deltas.include?(c) + assert list.loc_deltas.include?(java) + assert list.languages.include?('c') + assert list.languages.include?('java') + + assert_equal 101, list.code_added + assert_equal 1010, list.code_removed + assert_equal 202, list.comments_added + assert_equal 2020, list.comments_removed + assert_equal 303, list.blanks_added + assert_equal 3030, list.blanks_removed + end + + def test_add_same_language_twice + list = LocDeltaList.new + + c1 = LocDelta.new(:language => 'c', :code_added => 1, :code_removed => 10, + :comments_added => 2, :comments_removed => 20, :blanks_added => 3, :blanks_removed => 30) + list += c1 + + c2 = LocDelta.new(:language => 'c', :code_added => 100, :code_removed => 1000, + :comments_added => 200, :comments_removed => 2000, :blanks_added => 300, :blanks_removed => 3000) + list += c2 + + assert_equal 1, list.loc_deltas.size + assert list.languages.include?('c') + + assert_equal 101, list.code_added + assert_equal 1010, list.code_removed + assert_equal 202, list.comments_added + assert_equal 2020, list.comments_removed + assert_equal 303, list.blanks_added + assert_equal 3030, list.blanks_removed + end + + def test_net_total + list = LocDeltaList.new + + c = LocDelta.new(:language => 'c', :code_added => 1, :code_removed => 10, + :comments_added => 2, :comments_removed => 20, :blanks_added => 3, :blanks_removed => 30) + java = LocDelta.new(:language => 'java', :code_added => 100, :code_removed => 1000, + :comments_added => 200, :comments_removed => 2000, :blanks_added => 300, :blanks_removed => 3000) + + list.loc_deltas = [c,java] + + assert_equal 1-10+100-1000, list.net_code + assert_equal 2-20+200-2000, list.net_comments + assert_equal 3-30+300-3000, list.net_blanks + assert_equal 6-60+600-6000, list.net_total + end + + def test_compact + list = LocDeltaList.new + + c = LocDelta.new(:language => 'c', :code_added => 1, :code_removed => 10, + :comments_added => 2, :comments_removed => 20, :blanks_added => 3, :blanks_removed => 30) + java = LocDelta.new(:language => 'java', :code_added => 0, :code_removed => 0, + :comments_added => 0, :comments_removed => 0, :blanks_added => 0, :blanks_removed => 0) + + list.loc_deltas = [c,java] + + assert_equal [c], list.compact.loc_deltas + end + +end diff --git a/test/unit/loc_delta_test.rb b/test/unit/loc_delta_test.rb new file mode 100644 index 0000000..cd433df --- /dev/null +++ b/test/unit/loc_delta_test.rb @@ -0,0 +1,57 @@ +require File.dirname(__FILE__) + '/../test_helper' +include Ohcount + +class LocDeltaTest < Ohcount::Test + def test_loc_delta_default + delta = LocDelta.new() + assert !delta.language + assert_equal 0, delta.code_added + assert_equal 0, delta.code_removed + assert_equal 0, delta.comments_added + assert_equal 0, delta.comments_removed + assert_equal 0, delta.blanks_added + assert_equal 0, delta.blanks_removed + end + + def test_loc_delta_initializer + delta = LocDelta.new(:language => "c", :code_added => 1, :code_removed => 10, + :comments_added => 2, :comments_removed => 20, :blanks_added => 3, :blanks_removed => 30) + assert_equal "c", delta.language + assert_equal 1, delta.code_added + assert_equal 10, delta.code_removed + assert_equal 2, delta.comments_added + assert_equal 20, delta.comments_removed + assert_equal 3, delta.blanks_added + assert_equal 30, delta.blanks_removed + end + + def test_net_total + delta = LocDelta.new(:language => "c", :code_added => 1, :code_removed => 10, + :comments_added => 2, :comments_removed => 20, :blanks_added => 3, :blanks_removed => 30) + assert_equal -9, delta.net_code + assert_equal -18, delta.net_comments + assert_equal -27, delta.net_blanks + assert_equal -54, delta.net_total + end + + def test_addition + delta = LocDelta.new(:language => "c", :code_added => 1, :code_removed => 10, + :comments_added => 2, :comments_removed => 20, :blanks_added => 3, :blanks_removed => 30) + delta += LocDelta.new(:language => "c", :code_added => 100, :code_removed => 1000, + :comments_added => 200, :comments_removed => 2000, :blanks_added => 300, :blanks_removed => 3000) + assert_equal 101, delta.code_added + assert_equal 1010, delta.code_removed + assert_equal 202, delta.comments_added + assert_equal 2020, delta.comments_removed + assert_equal 303, delta.blanks_added + assert_equal 3030, delta.blanks_removed + end + + def test_addition_requires_matching_language + delta = LocDelta.new(:language => "c") + assert_raises(ArgumentError) do + delta += LocDelta.new(:language => "java") + end + end +end + diff --git a/test/unit/loc_list_test.rb b/test/unit/loc_list_test.rb new file mode 100644 index 0000000..5680985 --- /dev/null +++ b/test/unit/loc_list_test.rb @@ -0,0 +1,80 @@ +require File.dirname(__FILE__) + '/../test_helper' +include Ohcount + +class LocListTest < Ohcount::Test + def test_loc_list_default + list = LocList.new + assert_equal [], list.locs + assert_equal [], list.languages + end + + def test_loc_selector + list = LocList.new + c = Loc.new(:language => 'c', :code => 1, :comments => 2, :blanks => 3) + java = Loc.new(:language => 'java', :code => 10, :comments => 20, :blanks => 30) + + list.locs = [c, java] + + assert_equal c, list.loc('c') + assert_equal java, list.loc('java') + end + + def test_first_add + list = LocList.new + loc = Loc.new(:language => 'c', :code => 1, :comments => 2, :blanks => 3) + list += loc + + assert_equal [loc], list.locs + assert_equal ['c'], list.languages + assert_equal 1, list.code + assert_equal 2, list.comments + assert_equal 3, list.blanks + end + + def test_add_two_languages + list = LocList.new + + c = Loc.new(:language => 'c', :code => 1, :comments => 2, :blanks => 3) + list += c + + java = Loc.new(:language => 'java', :code => 10, :comments => 20, :blanks => 30) + list += java + + assert list.locs.include?(c) + assert list.locs.include?(java) + assert list.languages.include?('c') + assert list.languages.include?('java') + + assert_equal 11, list.code + assert_equal 22, list.comments + assert_equal 33, list.blanks + assert_equal 66, list.total + end + + def test_add_same_language_twice + list = LocList.new + + c1 = Loc.new(:language => 'c', :code => 1, :comments => 2, :blanks => 3) + list += c1 + + c2 = Loc.new(:language => 'c', :code => 10, :comments => 20, :blanks => 30) + list += c2 + + assert_equal 1, list.locs.size + assert list.languages.include?('c') + + assert_equal 11, list.code + assert_equal 22, list.comments + assert_equal 33, list.blanks + assert_equal 66, list.total + end + + def test_compact + list = LocList.new + c = Loc.new(:language => 'c', :code => 1, :comments => 2, :blanks => 3) + java = Loc.new(:language => 'java', :code => 0, :comments => 0, :blanks => 0) + list.locs = [c, java] + + assert_equal [c], list.compact.locs + end +end diff --git a/test/unit/loc_test.rb b/test/unit/loc_test.rb new file mode 100644 index 0000000..109f245 --- /dev/null +++ b/test/unit/loc_test.rb @@ -0,0 +1,38 @@ +require File.dirname(__FILE__) + '/../test_helper' +include Ohcount + +class LocTest < Ohcount::Test + def test_loc_default + loc = Loc.new() + assert !loc.language + assert_equal 0, loc.code + assert_equal 0, loc.comments + assert_equal 0, loc.blanks + end + + def test_loc_initializer + loc = Loc.new(:language => "c", :code => 1, :comments => 2, :blanks => 3) + assert_equal "c", loc.language + assert_equal 1, loc.code + assert_equal 2, loc.comments + assert_equal 3, loc.blanks + assert_equal 6, loc.total + end + + def test_add + loc = Loc.new(:language => "c", :code => 1, :comments => 2, :blanks => 3) + loc += Loc.new(:language => "c", :code => 10, :comments => 20, :blanks => 30) + assert_equal 'c', loc.language + assert_equal 11, loc.code + assert_equal 22, loc.comments + assert_equal 33, loc.blanks + assert_equal 66, loc.total + end + + def test_add_requires_same_language + loc = Loc.new(:language => "c", :code => 1, :comments => 2, :blanks => 3) + assert_raises(ArgumentError) do + loc += Loc.new(:language => "java", :code => 10, :comments => 20, :blanks => 30) + end + end +end From abe42b0645751b6e5eadc19c7a1dfcf29167bb0e Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Wed, 28 Jan 2009 14:53:50 -0800 Subject: [PATCH 082/387] [FIX] Unneccessarily diff'ing every file twice. --- lib/ohcount/source_file.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb index c4d231a..b5b2c32 100644 --- a/lib/ohcount/source_file.rb +++ b/lib/ohcount/source_file.rb @@ -172,10 +172,7 @@ def diff(new) # calc_diff("a\nb", "a\nc") # [1,1] -> one added, one deleted # def calc_diff(a,b) - a = a.split("\n") - b = b.split("\n") - diffs = LCSDiff::Diff::LCS.diff(a,b) - LCSDiff::Diff::LCS.diff(a,b).flatten.inject([0,0]) do |m, change| + LCSDiff::Diff::LCS.diff(a.split("\n"),b.split("\n")).flatten.inject([0,0]) do |m, change| m[0] += 1 if change.adding? m[1] += 1 if change.deleting? m From 7d2a41d9539b938d8f743d42cea0a21557070bde Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Wed, 28 Jan 2009 16:11:29 -0800 Subject: [PATCH 083/387] [CHANGE] Begin moving Ohcount accross to new Loc classes. Rake passes. Removed SlocInfo class. --- lib/ohcount.rb | 2 +- lib/ohcount/{sloc_info.rb => language.rb} | 49 +++++---------------------- lib/ohcount/loc.rb | 4 ++- lib/ohcount/loc_delta.rb | 21 +++++++++++- lib/ohcount/loc_delta_list.rb | 14 ++++++-- lib/ohcount/loc_list.rb | 7 ++++ lib/ohcount/source_file.rb | 55 ++++++++++++++++--------------- test/unit/loc_delta_list_test.rb | 36 ++++++++++++-------- test/unit/loc_delta_test.rb | 19 ++++++----- test/unit/loc_list_test.rb | 31 ++++++++++++----- test/unit/loc_test.rb | 18 ++++++---- test/unit/source_file_test.rb | 18 +++++----- 12 files changed, 156 insertions(+), 118 deletions(-) rename lib/ohcount/{sloc_info.rb => language.rb} (78%) diff --git a/lib/ohcount.rb b/lib/ohcount.rb index 997e9cd..f8bc5b4 100644 --- a/lib/ohcount.rb +++ b/lib/ohcount.rb @@ -13,6 +13,7 @@ module Ohcount require "lib/#{Config::CONFIG['arch']}/ohcount_native" end +require 'lib/ohcount/language' require 'lib/ohcount/loc' require 'lib/ohcount/loc_list' require 'lib/ohcount/loc_delta' @@ -22,7 +23,6 @@ module Ohcount require "lib/ohcount/helpers" require "lib/ohcount/detector" require "lib/ohcount/language_breakdown" -require "lib/ohcount/sloc_info" require "lib/ohcount/source_file" require "lib/ohcount/language_facts" require "lib/ohcount/gestalt_facts" diff --git a/lib/ohcount/sloc_info.rb b/lib/ohcount/language.rb similarity index 78% rename from lib/ohcount/sloc_info.rb rename to lib/ohcount/language.rb index 410a8e2..0954f91 100644 --- a/lib/ohcount/sloc_info.rb +++ b/lib/ohcount/language.rb @@ -1,33 +1,8 @@ -# A generic data object for returning parsing results from Ohcount to Ohloh. -# -# This class has the additional job of declaring a "nice" (human readable) name -# for each language, as well as the category (procedural code vs. markup) for each -# language. These features should probably live elsewhere, and are currently -# not covered by unit tests. -class Ohcount::SlocInfo - attr_reader :language - attr_accessor :code_added, :code_removed, :comments_added, :comments_removed, :blanks_added, :blanks_removed +class Ohcount::Language + attr_reader :name - def initialize(language, counts = {}) - raise ArgumentError.new('language can not be nil') unless language - @language = language - - @code_added = counts[:code_added] || 0 - @code_removed = counts[:code_removed] || 0 - @comments_added = counts[:comments_added] || 0 - @comments_removed = counts[:comments_removed] || 0 - @blanks_added = counts[:blanks_added] || 0 - @blanks_removed = counts[:blanks_removed] || 0 - end - - def ==(b) - @language == b.language && - @code_added == b.code_added && - @code_removed == b.code_removed && - @comments_added == b.comments_added && - @comments_removed == b.comments_removed && - @blanks_added == b.blanks_added && - @blanks_removed == b.blanks_removed + def initialize(name) + raise ArgumentError.new("language name can't be nil") unless name end @@lang_map = { @@ -103,8 +78,8 @@ def ==(b) } # Returns the human readable name for a language. - def language_nice_name - @@lang_map[self.language][:nice_name] + def nice_name + @@lang_map[name][:nice_name] end # Returns the category (procedural code vs. markup) for a language. @@ -117,15 +92,7 @@ def language_nice_name # the "primary" language of an application. Using them, a C application # with a lot of supporting HTML documentation or large autoconf file will # still be successfully identified as a C application. - def language_category - @@lang_map[self.language][:category] + def category + @@lang_map[name][:category] end - - # return true if this sloc_info contains no measurable changes - def no_changes? - @code_added == 0 && @code_removed == 0 && - @comments_added == 0 && @comments_removed == 0 && - @blanks_added == 0 && @blanks_removed == 0 - end - end diff --git a/lib/ohcount/loc.rb b/lib/ohcount/loc.rb index e0a5a5d..65232a8 100644 --- a/lib/ohcount/loc.rb +++ b/lib/ohcount/loc.rb @@ -3,7 +3,9 @@ module Ohcount class Loc attr_accessor :language, :code, :comments, :blanks - def initialize(params={}) + def initialize(language, params={}) + raise ArgumentError.new("language can't be nil") unless language + @language = language @code = @comments = @blanks = 0 params.each { |k,v| send(k.to_s + '=', v) if respond_to?(k.to_s + '=') } end diff --git a/lib/ohcount/loc_delta.rb b/lib/ohcount/loc_delta.rb index ea570e7..7251ca9 100644 --- a/lib/ohcount/loc_delta.rb +++ b/lib/ohcount/loc_delta.rb @@ -3,7 +3,9 @@ module Ohcount class LocDelta attr_accessor :language, :code_added, :code_removed, :comments_added, :comments_removed, :blanks_added, :blanks_removed - def initialize(params={}) + def initialize(language, params={}) + raise ArgumentError.new("language can't be nil") unless language + @language = language @code_added = @code_removed = @comments_added = @comments_removed = @blanks_added = @blanks_removed = 0 params.each { |k,v| send(k.to_s + '=', v) if respond_to?(k.to_s + '=') } end @@ -34,6 +36,23 @@ def +(addend) @blanks_removed += addend.blanks_removed self end + + def changed? + code_added != 0 || code_removed != 0 || comments_added != 0 || comments_removed != 0 || blanks_added != 0 || blanks_removed != 0 + end + + def ==(b) + if (b) + @language == b.language && + @code_added == b.code_added && + @code_removed == b.code_removed && + @comments_added == b.comments_added && + @comments_removed == b.comments_removed && + @blanks_added == b.blanks_added && + @blanks_removed == b.blanks_removed + end + end + end end diff --git a/lib/ohcount/loc_delta_list.rb b/lib/ohcount/loc_delta_list.rb index 82c158a..225b82c 100644 --- a/lib/ohcount/loc_delta_list.rb +++ b/lib/ohcount/loc_delta_list.rb @@ -74,9 +74,19 @@ def net_total @loc_deltas.inject(0) { |sum, delta| sum + delta.net_total } end - # Returns a new LocDeltaList excluding all languages that have 0 net changes + # Returns a new LocDeltaList excluding all languages that have no changes def compact - LocDeltaList.new(@loc_deltas.reject{ |delta| delta.net_total == 0 }) + LocDeltaList.new(@loc_deltas.reject { |delta| !delta.changed? }) + end + + def ==(b) + return false unless b + return false unless languages == b.languages + + self.languages.each do |l| + return false unless self.loc_delta(l) == b.loc_delta(l) + end + true end end diff --git a/lib/ohcount/loc_list.rb b/lib/ohcount/loc_list.rb index f8f6d34..0c24efd 100644 --- a/lib/ohcount/loc_list.rb +++ b/lib/ohcount/loc_list.rb @@ -17,6 +17,8 @@ def languages def +(addend) case addend + when LocList + add_loc_list(addend) when Loc add_loc(addend) else @@ -24,6 +26,11 @@ def +(addend) end end + def add_loc_list(addend) + addend.locs.each { |loc| add_loc(loc) } + self + end + def add_loc(addend) existing = loc(addend.language) if existing diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb index b5b2c32..930c074 100644 --- a/lib/ohcount/source_file.rb +++ b/lib/ohcount/source_file.rb @@ -139,35 +139,38 @@ def languages language_breakdowns.collect { |lb| lb.name } end - # returns a collection of sloc_infos containing - # the diffs from the this current object to the - # new object - def diff(new) - all_languages = (self.languages + new.languages).uniq - all_languages.collect do |language| - si = Ohcount::SlocInfo.new(language) - lb_old = language_breakdown(language) - lb_new = new.language_breakdown(language) - - #code - si.code_added, si.code_removed = calc_diff(lb_old.code, lb_new.code) - si.comments_added, si.comments_removed = calc_diff(lb_old.comment, lb_new.comment) - si.blanks_added = lb_new.blanks - lb_old.blanks - si.blanks_removed = lb_old.blanks - lb_new.blanks - - # strip negative blank counts - si.blanks_added = 0 if si.blanks_added < 0 - si.blanks_removed = 0 if si.blanks_removed < 0 - - si - end.reject do |si| - # remove meangingless sloc_infos - si.no_changes? + # Returns a LocDeltaList reflecting the lines changed in all languages + # when comparing this source file ("before") to a new version ("after") + def diff(after) + all_languages = (self.languages + after.languages).uniq.sort + + all_languages.inject(LocDeltaList.new) do |sum, lang| + sum + calc_loc_delta(lang, after) + end.compact + end + + # Returns a LocDelta reflecting the lines changed in a single language + # when comparing this source file ("before") to a new version ("after") + def calc_loc_delta(language, after) + lb_before = self.language_breakdown(language) + lb_after = after.language_breakdown(language) + + delta = LocDelta.new(language) + + delta.code_added, delta.code_removed = calc_diff(lb_before.code, lb_after.code) + delta.comments_added, delta.comments_removed = calc_diff(lb_before.comment, lb_after.comment) + + if lb_before.blanks > lb_after.blanks + delta.blanks_removed = lb_before.blanks - lb_after.blanks + else + delta.blanks_added = lb_after.blanks - lb_before.blanks end + + delta end - # takes 2 strings and returns an array containing the count - # of added lines and deleted lines. Example + # Takes two strings and returns an array containing the count + # of added lines and deleted lines. Example: # # calc_diff("a\nb", "a\nc") # [1,1] -> one added, one deleted # diff --git a/test/unit/loc_delta_list_test.rb b/test/unit/loc_delta_list_test.rb index 114c606..10d1244 100644 --- a/test/unit/loc_delta_list_test.rb +++ b/test/unit/loc_delta_list_test.rb @@ -10,8 +10,8 @@ def test_loc_list_default def test_loc_selector list = LocDeltaList.new - c = LocDelta.new(:language => 'c') - java = LocDelta.new(:language => 'java') + c = LocDelta.new('c') + java = LocDelta.new('java') list.loc_deltas = [c, java] @@ -21,7 +21,7 @@ def test_loc_selector def test_first_add list = LocDeltaList.new - loc_delta = LocDelta.new(:language => 'c', :code_added => 1, :code_removed => 10, + loc_delta = LocDelta.new('c', :code_added => 1, :code_removed => 10, :comments_added => 2, :comments_removed => 20, :blanks_added => 3, :blanks_removed => 30) list += loc_delta @@ -37,11 +37,11 @@ def test_first_add def test_add_two_languages list = LocDeltaList.new - c = LocDelta.new(:language => 'c', :code_added => 1, :code_removed => 10, + c = LocDelta.new('c', :code_added => 1, :code_removed => 10, :comments_added => 2, :comments_removed => 20, :blanks_added => 3, :blanks_removed => 30) list += c - java = LocDelta.new(:language => 'java', :code_added => 100, :code_removed => 1000, + java = LocDelta.new('java', :code_added => 100, :code_removed => 1000, :comments_added => 200, :comments_removed => 2000, :blanks_added => 300, :blanks_removed => 3000) list += java @@ -61,11 +61,11 @@ def test_add_two_languages def test_add_same_language_twice list = LocDeltaList.new - c1 = LocDelta.new(:language => 'c', :code_added => 1, :code_removed => 10, + c1 = LocDelta.new('c', :code_added => 1, :code_removed => 10, :comments_added => 2, :comments_removed => 20, :blanks_added => 3, :blanks_removed => 30) list += c1 - c2 = LocDelta.new(:language => 'c', :code_added => 100, :code_removed => 1000, + c2 = LocDelta.new('c', :code_added => 100, :code_removed => 1000, :comments_added => 200, :comments_removed => 2000, :blanks_added => 300, :blanks_removed => 3000) list += c2 @@ -83,9 +83,9 @@ def test_add_same_language_twice def test_net_total list = LocDeltaList.new - c = LocDelta.new(:language => 'c', :code_added => 1, :code_removed => 10, + c = LocDelta.new('c', :code_added => 1, :code_removed => 10, :comments_added => 2, :comments_removed => 20, :blanks_added => 3, :blanks_removed => 30) - java = LocDelta.new(:language => 'java', :code_added => 100, :code_removed => 1000, + java = LocDelta.new('java', :code_added => 100, :code_removed => 1000, :comments_added => 200, :comments_removed => 2000, :blanks_added => 300, :blanks_removed => 3000) list.loc_deltas = [c,java] @@ -99,14 +99,24 @@ def test_net_total def test_compact list = LocDeltaList.new - c = LocDelta.new(:language => 'c', :code_added => 1, :code_removed => 10, + c = LocDelta.new('c', :code_added => 1, :code_removed => 10, :comments_added => 2, :comments_removed => 20, :blanks_added => 3, :blanks_removed => 30) - java = LocDelta.new(:language => 'java', :code_added => 0, :code_removed => 0, + ruby = LocDelta.new('ruby', :code_added => 1, :code_removed => 1, + :comments_added => 0, :comments_removed => 0, :blanks_added => 0, :blanks_removed => 0) + java = LocDelta.new('java', :code_added => 0, :code_removed => 0, :comments_added => 0, :comments_removed => 0, :blanks_added => 0, :blanks_removed => 0) - list.loc_deltas = [c,java] + list.loc_deltas = [c,ruby,java] + + assert_equal [c,ruby], list.compact.loc_deltas + end - assert_equal [c], list.compact.loc_deltas + def test_equals + c1 = LocDelta.new('c', :code_added => 1, :code_removed => 10, + :comments_added => 2, :comments_removed => 20, :blanks_added => 3, :blanks_removed => 30) + c2 = LocDelta.new('c', :code_added => 1, :code_removed => 10, + :comments_added => 2, :comments_removed => 20, :blanks_added => 3, :blanks_removed => 30) + assert_equal c1, c2 end end diff --git a/test/unit/loc_delta_test.rb b/test/unit/loc_delta_test.rb index cd433df..3c3a394 100644 --- a/test/unit/loc_delta_test.rb +++ b/test/unit/loc_delta_test.rb @@ -2,9 +2,12 @@ include Ohcount class LocDeltaTest < Ohcount::Test + def test_loc_requires_langauge + assert_raises(ArgumentError) { LocDelta.new } + end + def test_loc_delta_default - delta = LocDelta.new() - assert !delta.language + delta = LocDelta.new('c') assert_equal 0, delta.code_added assert_equal 0, delta.code_removed assert_equal 0, delta.comments_added @@ -14,7 +17,7 @@ def test_loc_delta_default end def test_loc_delta_initializer - delta = LocDelta.new(:language => "c", :code_added => 1, :code_removed => 10, + delta = LocDelta.new("c", :code_added => 1, :code_removed => 10, :comments_added => 2, :comments_removed => 20, :blanks_added => 3, :blanks_removed => 30) assert_equal "c", delta.language assert_equal 1, delta.code_added @@ -26,7 +29,7 @@ def test_loc_delta_initializer end def test_net_total - delta = LocDelta.new(:language => "c", :code_added => 1, :code_removed => 10, + delta = LocDelta.new("c", :code_added => 1, :code_removed => 10, :comments_added => 2, :comments_removed => 20, :blanks_added => 3, :blanks_removed => 30) assert_equal -9, delta.net_code assert_equal -18, delta.net_comments @@ -35,9 +38,9 @@ def test_net_total end def test_addition - delta = LocDelta.new(:language => "c", :code_added => 1, :code_removed => 10, + delta = LocDelta.new("c", :code_added => 1, :code_removed => 10, :comments_added => 2, :comments_removed => 20, :blanks_added => 3, :blanks_removed => 30) - delta += LocDelta.new(:language => "c", :code_added => 100, :code_removed => 1000, + delta += LocDelta.new("c", :code_added => 100, :code_removed => 1000, :comments_added => 200, :comments_removed => 2000, :blanks_added => 300, :blanks_removed => 3000) assert_equal 101, delta.code_added assert_equal 1010, delta.code_removed @@ -48,9 +51,9 @@ def test_addition end def test_addition_requires_matching_language - delta = LocDelta.new(:language => "c") + delta = LocDelta.new("c") assert_raises(ArgumentError) do - delta += LocDelta.new(:language => "java") + delta += LocDelta.new("java") end end end diff --git a/test/unit/loc_list_test.rb b/test/unit/loc_list_test.rb index 5680985..55ba7c6 100644 --- a/test/unit/loc_list_test.rb +++ b/test/unit/loc_list_test.rb @@ -10,8 +10,8 @@ def test_loc_list_default def test_loc_selector list = LocList.new - c = Loc.new(:language => 'c', :code => 1, :comments => 2, :blanks => 3) - java = Loc.new(:language => 'java', :code => 10, :comments => 20, :blanks => 30) + c = Loc.new('c', :code => 1, :comments => 2, :blanks => 3) + java = Loc.new('java', :code => 10, :comments => 20, :blanks => 30) list.locs = [c, java] @@ -21,7 +21,7 @@ def test_loc_selector def test_first_add list = LocList.new - loc = Loc.new(:language => 'c', :code => 1, :comments => 2, :blanks => 3) + loc = Loc.new('c', :code => 1, :comments => 2, :blanks => 3) list += loc assert_equal [loc], list.locs @@ -34,10 +34,10 @@ def test_first_add def test_add_two_languages list = LocList.new - c = Loc.new(:language => 'c', :code => 1, :comments => 2, :blanks => 3) + c = Loc.new('c', :code => 1, :comments => 2, :blanks => 3) list += c - java = Loc.new(:language => 'java', :code => 10, :comments => 20, :blanks => 30) + java = Loc.new('java', :code => 10, :comments => 20, :blanks => 30) list += java assert list.locs.include?(c) @@ -54,10 +54,10 @@ def test_add_two_languages def test_add_same_language_twice list = LocList.new - c1 = Loc.new(:language => 'c', :code => 1, :comments => 2, :blanks => 3) + c1 = Loc.new('c', :code => 1, :comments => 2, :blanks => 3) list += c1 - c2 = Loc.new(:language => 'c', :code => 10, :comments => 20, :blanks => 30) + c2 = Loc.new('c', :code => 10, :comments => 20, :blanks => 30) list += c2 assert_equal 1, list.locs.size @@ -69,10 +69,23 @@ def test_add_same_language_twice assert_equal 66, list.total end + def test_add_loc_lists + list1 = LocList.new + Loc.new('c', :code => 1) + Loc.new('java', :code => 2) + list2 = LocList.new + Loc.new('c', :code => 10) + Loc.new('ruby', :code => 3) + + sum = list1 + list2 + + assert_equal ['c','java','ruby'], sum.languages.sort + assert_equal 11, sum.loc('c').code + assert_equal 2, sum.loc('java').code + assert_equal 3, sum.loc('ruby').code + assert_equal 16, sum.code + end + def test_compact list = LocList.new - c = Loc.new(:language => 'c', :code => 1, :comments => 2, :blanks => 3) - java = Loc.new(:language => 'java', :code => 0, :comments => 0, :blanks => 0) + c = Loc.new('c', :code => 1, :comments => 2, :blanks => 3) + java = Loc.new('java', :code => 0, :comments => 0, :blanks => 0) list.locs = [c, java] assert_equal [c], list.compact.locs diff --git a/test/unit/loc_test.rb b/test/unit/loc_test.rb index 109f245..5b9c9ed 100644 --- a/test/unit/loc_test.rb +++ b/test/unit/loc_test.rb @@ -2,16 +2,20 @@ include Ohcount class LocTest < Ohcount::Test + def test_loc_requires_language + assert_raises(ArgumentError) { Loc.new } + end + def test_loc_default - loc = Loc.new() - assert !loc.language + loc = Loc.new('c') + assert_equal 'c', loc.language assert_equal 0, loc.code assert_equal 0, loc.comments assert_equal 0, loc.blanks end def test_loc_initializer - loc = Loc.new(:language => "c", :code => 1, :comments => 2, :blanks => 3) + loc = Loc.new("c", :code => 1, :comments => 2, :blanks => 3) assert_equal "c", loc.language assert_equal 1, loc.code assert_equal 2, loc.comments @@ -20,8 +24,8 @@ def test_loc_initializer end def test_add - loc = Loc.new(:language => "c", :code => 1, :comments => 2, :blanks => 3) - loc += Loc.new(:language => "c", :code => 10, :comments => 20, :blanks => 30) + loc = Loc.new("c", :code => 1, :comments => 2, :blanks => 3) + loc += Loc.new("c", :code => 10, :comments => 20, :blanks => 30) assert_equal 'c', loc.language assert_equal 11, loc.code assert_equal 22, loc.comments @@ -30,9 +34,9 @@ def test_add end def test_add_requires_same_language - loc = Loc.new(:language => "c", :code => 1, :comments => 2, :blanks => 3) + loc = Loc.new("c", :code => 1, :comments => 2, :blanks => 3) assert_raises(ArgumentError) do - loc += Loc.new(:language => "java", :code => 10, :comments => 20, :blanks => 30) + loc += Loc.new("java", :code => 10, :comments => 20, :blanks => 30) end end end diff --git a/test/unit/source_file_test.rb b/test/unit/source_file_test.rb index 2ae7d1d..d6e330e 100644 --- a/test/unit/source_file_test.rb +++ b/test/unit/source_file_test.rb @@ -37,12 +37,13 @@ def test_realize_file end end - def test_calc_diff + def test_diff old = SourceFile.new("foo.c", :contents => 'int i;') new = SourceFile.new("foo.c", :contents => 'int j;') - c_si = Ohcount::SlocInfo.new('c', :code_added => 1, :code_removed => 1) - assert_equal [c_si], old.diff(new) + delta = LocDelta.new('c', :code_added => 1, :code_removed => 1) + assert_equal delta, old.calc_loc_delta('c', new) + assert_equal LocDeltaList.new([delta]), old.diff(new) end def test_calc_diff_2 @@ -70,10 +71,10 @@ def test_calc_diff_2 INLINE_HTML ) - - javascript_si = Ohcount::SlocInfo.new('javascript', :code_added => 1, :code_removed => 1) - css_si = Ohcount::SlocInfo.new('css', :comments_added => 1, :comments_removed => 1) - assert_equal [javascript_si, css_si], old.diff(new) + loc_delta_list = old.diff(new) + assert_equal ['css', 'javascript'], loc_delta_list.languages + assert_equal LocDelta.new('css', :comments_added => 1, :comments_removed => 1), loc_delta_list.loc_delta('css') + assert_equal LocDelta.new('javascript', :code_added => 1, :code_removed => 1), loc_delta_list.loc_delta('javascript') end def test_calc_diff_longer @@ -91,8 +92,7 @@ def test_calc_diff_longer int = 4; INLINE_C ) - c_si = Ohcount::SlocInfo.new('c', :code_added => 2, :code_removed => 2) - assert_equal [c_si],old.diff(new) + assert_equal LocDelta.new('c', :code_added => 2, :code_removed => 2), old.diff(new).loc_delta('c') end end From a398b30534ef7506186116e23f41695a4db562f7 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Wed, 28 Jan 2009 17:14:52 -0800 Subject: [PATCH 084/387] [CHANGE] Move more of Ohcount to the new Loc classes. Remove LanguageFacts class. --- bin/ohcount | 14 ++++++------ lib/ohcount.rb | 5 ++-- lib/ohcount/language_facts.rb | 47 -------------------------------------- lib/ohcount/loc.rb | 5 ++-- lib/ohcount/loc_list.rb | 12 +++++++++- lib/ohcount/source_file.rb | 11 +++++++++ lib/ohcount/source_file_list.rb | 12 +++++----- test/unit/loc_list_test.rb | 19 ++++++++++++--- test/unit/loc_test.rb | 9 +++++--- test/unit/source_file_list_test.rb | 8 +++---- 10 files changed, 66 insertions(+), 76 deletions(-) delete mode 100644 lib/ohcount/language_facts.rb diff --git a/bin/ohcount b/bin/ohcount index b423221..403a2ae 100755 --- a/bin/ohcount +++ b/bin/ohcount @@ -206,16 +206,16 @@ HELP puts "Language Files Code Comment Comment % Blank Total" puts "---------------- ----- --------- --------- --------- --------- ---------" - language_facts = source_file_list.language_facts - language_facts.fact_map.values.sort { |a,b| b.code <=> a.code}.each do |lf| - write_summary_row(lf.language, lf.filecount, lf.code, lf.comments, lf.blanks) + source_file_list.loc_list.locs.sort { |a,b| b.code <=> a.code}.each do |loc| + write_summary_row(loc.language, loc.filecount, loc.code, loc.comments, loc.blanks) end puts "---------------- ----- --------- --------- --------- --------- ---------" - write_summary_row('Total', language_facts.filecount, - language_facts.code, - language_facts.comments, - language_facts.blanks) + write_summary_row('Total', + source_file_list.loc_list.filecount, + source_file_list.loc_list.code, + source_file_list.loc_list.comments, + source_file_list.loc_list.blanks) puts diff --git a/lib/ohcount.rb b/lib/ohcount.rb index f8bc5b4..c864d1d 100644 --- a/lib/ohcount.rb +++ b/lib/ohcount.rb @@ -24,14 +24,13 @@ module Ohcount require "lib/ohcount/detector" require "lib/ohcount/language_breakdown" require "lib/ohcount/source_file" -require "lib/ohcount/language_facts" -require "lib/ohcount/gestalt_facts" require "lib/ohcount/source_file_list" +require "lib/ohcount/gestalt_facts" require "lib/licenses/license_sniffer" + require "lib/gestalt/platform" require "lib/gestalt/tool" -# require the dynamic rules require 'rules/platforms' require 'rules/tools' diff --git a/lib/ohcount/language_facts.rb b/lib/ohcount/language_facts.rb deleted file mode 100644 index 820081e..0000000 --- a/lib/ohcount/language_facts.rb +++ /dev/null @@ -1,47 +0,0 @@ -module Ohcount - - # Represents language statistics for a collection of files - class LanguageFacts - attr_accessor :fact_map - attr_accessor :filecount - attr_accessor :code, :blanks, :comments - - def initialize - @fact_map = {} - @filecount = @code = @blanks = @comments = 0 - end - - def process(source_file) - return unless source_file.polyglot - source_file.language_breakdowns.each do |lb| - lang = lb.name - lang_fact = @fact_map[lang] ||= LanguageFact.new(lang) - - @code += lb.code_count - @comments += lb.comment_count - @blanks += lb.blanks - - lang_fact.code += lb.code_count - lang_fact.comments += lb.comment_count - lang_fact.blanks += lb.blanks - lang_fact.filecount += 1 - end - @filecount += 1 - end - - def method_missing(m, *args) - @fact_map[m] || @fact_map[m.to_s] || LanguageFact.new(m.to_s) - end - end - - # holds stats for an individual language - class LanguageFact - attr_reader :language - attr_accessor :filecount, :blanks, :code, :comments - - def initialize(lang) - @language = lang - @filecount = @blanks = @code = @comments = 0 - end - end -end diff --git a/lib/ohcount/loc.rb b/lib/ohcount/loc.rb index 65232a8..75c4e8a 100644 --- a/lib/ohcount/loc.rb +++ b/lib/ohcount/loc.rb @@ -1,12 +1,12 @@ module Ohcount # Tracks total lines of code, comments, and blanks for a single language class Loc - attr_accessor :language, :code, :comments, :blanks + attr_accessor :language, :code, :comments, :blanks, :filecount def initialize(language, params={}) raise ArgumentError.new("language can't be nil") unless language @language = language - @code = @comments = @blanks = 0 + @code = @comments = @blanks = @filecount = 0 params.each { |k,v| send(k.to_s + '=', v) if respond_to?(k.to_s + '=') } end @@ -19,6 +19,7 @@ def +(addend) @code += addend.code @comments += addend.comments @blanks += addend.blanks + @filecount += addend.filecount self end end diff --git a/lib/ohcount/loc_list.rb b/lib/ohcount/loc_list.rb index 0c24efd..f87aff6 100644 --- a/lib/ohcount/loc_list.rb +++ b/lib/ohcount/loc_list.rb @@ -8,7 +8,7 @@ def initialize(locs=[]) end def loc(language) - @locs.find { |loc| loc.language == language } + @locs.find { |loc| loc.language == language.to_s } end def languages @@ -24,6 +24,7 @@ def +(addend) else raise ArgumentError.new end + self end def add_loc_list(addend) @@ -57,9 +58,18 @@ def total @locs.inject(0) { |sum, loc| sum + loc.total } end + def filecount + @locs.inject(0) { |sum, loc| sum + loc.filecount } + end + # Returns a new loc_list excluding all languages with 0 lines def compact LocList.new(@locs.reject { |loc| loc.total == 0 }) end + + # Access the individual languages directly + def method_missing(m, *args) + loc(m.to_s) + end end end diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb index 930c074..164bffc 100644 --- a/lib/ohcount/source_file.rb +++ b/lib/ohcount/source_file.rb @@ -139,6 +139,17 @@ def languages language_breakdowns.collect { |lb| lb.name } end + # Returns a LocList reflecting the total lines of code in each language + def loc_list + language_breakdowns.inject(LocList.new) do |sum, lb| + sum + Loc.new(lb.name, + :code => lb.code_count, + :comments => lb.comment_count, + :blanks => lb.blanks, + :filecount => 1) + end + end + # Returns a LocDeltaList reflecting the lines changed in all languages # when comparing this source file ("before") to a new version ("after") def diff(after) diff --git a/lib/ohcount/source_file_list.rb b/lib/ohcount/source_file_list.rb index a8cff6d..17ffd07 100644 --- a/lib/ohcount/source_file_list.rb +++ b/lib/ohcount/source_file_list.rb @@ -4,10 +4,10 @@ module Ohcount # # # find out the number of Ruby lines of code in project 'foo' # sfl = SourceFileList.new(:dir => '/foo') - # sfl.language_stats(:ruby).code + # sfl.loc_list.loc(:ruby).code # class SourceFileList < Array - attr_reader :language_facts, :gestalt_facts + attr_reader :loc_list, :gestalt_facts # pass an array of filenames you want to process. # @@ -63,20 +63,20 @@ def files_from_path(path) # puts sfl.ruby.code.count # # - def analyze(what = []) + def analyze(what = [:*]) what = [what] unless what.is_a?(Array) do_gestalt = what.include?(:gestalt) || what.include?(:*) do_languages = what.include?(:language) || what.include?(:*) - @language_facts = LanguageFacts.new if do_languages - @gestalt_facts = GestaltFacts.new if do_gestalt + @loc_list = LocList.new if do_languages + @gestalt_facts = GestaltFacts.new if do_gestalt self.each do |file| # we process each file - even if its not a source_code - for # library rules sake - they sometimes want 'jar' files or something source_file = SourceFile.new(file, :filename => self) - @language_facts.process(source_file) if do_languages + @loc_list += source_file.loc_list if do_languages @gestalt_facts.process(source_file) if do_gestalt yield source_file if block_given? end diff --git a/test/unit/loc_list_test.rb b/test/unit/loc_list_test.rb index 55ba7c6..9654fdb 100644 --- a/test/unit/loc_list_test.rb +++ b/test/unit/loc_list_test.rb @@ -19,9 +19,20 @@ def test_loc_selector assert_equal java, list.loc('java') end + def test_method_missing + list = LocList.new + c = Loc.new('c', :code => 1, :comments => 2, :blanks => 3) + java = Loc.new('java', :code => 10, :comments => 20, :blanks => 30) + + list.locs = [c, java] + + assert_equal c, list.c + assert_equal java, list.java + end + def test_first_add list = LocList.new - loc = Loc.new('c', :code => 1, :comments => 2, :blanks => 3) + loc = Loc.new('c', :code => 1, :comments => 2, :blanks => 3, :filecount => 4) list += loc assert_equal [loc], list.locs @@ -29,15 +40,16 @@ def test_first_add assert_equal 1, list.code assert_equal 2, list.comments assert_equal 3, list.blanks + assert_equal 4, list.filecount end def test_add_two_languages list = LocList.new - c = Loc.new('c', :code => 1, :comments => 2, :blanks => 3) + c = Loc.new('c', :code => 1, :comments => 2, :blanks => 3, :filecount => 4) list += c - java = Loc.new('java', :code => 10, :comments => 20, :blanks => 30) + java = Loc.new('java', :code => 10, :comments => 20, :blanks => 30, :filecount => 40) list += java assert list.locs.include?(c) @@ -49,6 +61,7 @@ def test_add_two_languages assert_equal 22, list.comments assert_equal 33, list.blanks assert_equal 66, list.total + assert_equal 44, list.filecount end def test_add_same_language_twice diff --git a/test/unit/loc_test.rb b/test/unit/loc_test.rb index 5b9c9ed..a85001c 100644 --- a/test/unit/loc_test.rb +++ b/test/unit/loc_test.rb @@ -12,25 +12,28 @@ def test_loc_default assert_equal 0, loc.code assert_equal 0, loc.comments assert_equal 0, loc.blanks + assert_equal 0, loc.filecount end def test_loc_initializer - loc = Loc.new("c", :code => 1, :comments => 2, :blanks => 3) + loc = Loc.new("c", :code => 1, :comments => 2, :blanks => 3, :filecount => 4) assert_equal "c", loc.language assert_equal 1, loc.code assert_equal 2, loc.comments assert_equal 3, loc.blanks assert_equal 6, loc.total + assert_equal 4, loc.filecount end def test_add - loc = Loc.new("c", :code => 1, :comments => 2, :blanks => 3) - loc += Loc.new("c", :code => 10, :comments => 20, :blanks => 30) + loc = Loc.new("c", :code => 1, :comments => 2, :blanks => 3, :filecount => 4) + loc += Loc.new("c", :code => 10, :comments => 20, :blanks => 30, :filecount => 40) assert_equal 'c', loc.language assert_equal 11, loc.code assert_equal 22, loc.comments assert_equal 33, loc.blanks assert_equal 66, loc.total + assert_equal 44, loc.filecount end def test_add_requires_same_language diff --git a/test/unit/source_file_list_test.rb b/test/unit/source_file_list_test.rb index 7c5bda2..0e05a64 100644 --- a/test/unit/source_file_list_test.rb +++ b/test/unit/source_file_list_test.rb @@ -11,10 +11,10 @@ class SourceFileListTest < Ohcount::Test def test_language_facts sfl = SourceFileList.new(:path => test_dir('win32_enough')) sfl.analyze(:language) - assert_equal 2, sfl.language_facts.filecount - assert_equal 2, sfl.language_facts.c.code - assert_equal 2, sfl.language_facts.c.comments - assert_equal 2, sfl.language_facts.c.blanks + assert_equal 2, sfl.loc_list.filecount + assert_equal 2, sfl.loc_list.c.code + assert_equal 2, sfl.loc_list.c.comments + assert_equal 2, sfl.loc_list.c.blanks end def test_gestalt_facts From 88a5fab2996553e7f8a9e8f881a128799baffaab Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Wed, 28 Jan 2009 17:50:39 -0800 Subject: [PATCH 085/387] [FIX] No one really uses it, but clean up and test Language class --- lib/ohcount/language.rb | 16 ++++++++++++---- test/unit/language_test.rb | 13 +++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 test/unit/language_test.rb diff --git a/lib/ohcount/language.rb b/lib/ohcount/language.rb index 0954f91..10197db 100644 --- a/lib/ohcount/language.rb +++ b/lib/ohcount/language.rb @@ -3,9 +3,11 @@ class Ohcount::Language def initialize(name) raise ArgumentError.new("language name can't be nil") unless name + @name = name end - @@lang_map = { + def lang_map + { 'actionscript' => {:nice_name => 'ActionScript' , :category => 0}, 'ada' => {:nice_name => 'Ada' , :category => 0}, 'assembler' => {:nice_name => 'Assembler' , :category => 0}, @@ -75,11 +77,12 @@ def initialize(name) 'dmd' => {:nice_name => 'D' , :category => 0}, 'tex' => {:nice_name => 'TeX/LaTeX' , :category => 1}, 'haskell' => {:nice_name => 'Haskell' , :category => 0} - } + } + end # Returns the human readable name for a language. def nice_name - @@lang_map[name][:nice_name] + lang_map[@name][:nice_name] end # Returns the category (procedural code vs. markup) for a language. @@ -93,6 +96,11 @@ def nice_name # with a lot of supporting HTML documentation or large autoconf file will # still be successfully identified as a C application. def category - @@lang_map[name][:category] + lang_map[@name][:category] + end + + # Access the individual languages directly + def self.method_missing(m, *args) + Language.new(m.to_s) end end diff --git a/test/unit/language_test.rb b/test/unit/language_test.rb new file mode 100644 index 0000000..26c43aa --- /dev/null +++ b/test/unit/language_test.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../test_helper' +include Ohcount + +class Ohcount::LanguageTest < Ohcount::Test + def test_basic + assert_equal "C++", Language.new("cpp").nice_name + assert_equal 0, Language.new("cpp").category + end + + def test_method_missing + assert_equal "C++", Language.cpp.nice_name + end +end From b9f92e9e880c1abc0e65c6a9877a07bc10bc2989 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Wed, 28 Jan 2009 18:15:50 -0800 Subject: [PATCH 086/387] [CHANGE] Clean up source_file.rb -- remove the clone_and_rename() method --- lib/ohcount/detector.rb | 7 ++++--- lib/ohcount/source_file.rb | 15 +++------------ 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index 3801036..483cd2b 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -488,10 +488,11 @@ def self.php_instruction?(buffer) # Typically used for template files (eg Makefile.in, auto.c.in, etc). def self.disambiguate_in(source_file) # only if the filename has an extension prior to the .in - return nil unless source_file.filename =~ /\..*\.in$/ + return nil unless source_file.filename =~ /(.+\.(.*))\.in$/ + + undecorated_source = source_file.clone + undecorated_source.filename = $1 - undecorated_filename = source_file.filename.gsub(/\.in$/, "") - undecorated_source = source_file.clone_and_rename(undecorated_filename) detect(undecorated_source) end diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb index 164bffc..26ce018 100644 --- a/lib/ohcount/source_file.rb +++ b/lib/ohcount/source_file.rb @@ -11,7 +11,7 @@ module Ohcount # class SourceFile # The filename we're dealing with. - attr_reader :filename + attr_accessor :filename # An array of names of other files in the source tree which # may be helpful when disambiguating the language used by the target file. @@ -19,12 +19,12 @@ class SourceFile # determining the language used in a *.h header file. # This array is optional, but language identification may be less accurate # without it. - attr_reader :filenames + attr_accessor :filenames # The location on disk where the file content can currently be found. # This might not be the same as the original name of the file. # For example, file content might be stored in temporary directory. - attr_reader :file_location + attr_accessor :file_location # At a minimum, you must provide the filename. # @@ -86,15 +86,6 @@ def language_breakdown(language) language_breakdowns.find { |lb| lb.name == language.to_s } || LanguageBreakdown.new(language.to_s) end - def clone_and_rename(new_name) - attributes = { - :filenames => filenames, - :contents => contents, - :file_location => file_location || filename - } - Ohcount::SourceFile.new(new_name, attributes) - end - # will yield with the current directory set in a way that the filename # exists and contains the actual file contents. # From b0a1ed65ccd1881834076ba5a988ef18d4abdf0c Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Wed, 28 Jan 2009 18:43:18 -0800 Subject: [PATCH 087/387] [CHANGE] Some corrections to old comments. --- README | 37 ++++++++++++++------------------ lib/ohcount/source_file.rb | 53 +++++++++++++++------------------------------- 2 files changed, 33 insertions(+), 57 deletions(-) diff --git a/README b/README index 5b45bf6..9bd49b8 100644 --- a/README +++ b/README @@ -39,31 +39,31 @@ language detection features from a Ruby application. == System Requirements -Ohcount is supported on Mac OS X 10.4 and Ubuntu 6.06 LTS. Other Linux +Ohcount is supported on Mac OS X 10.5 and Ubuntu 6.06 LTS. Other Linux environments should also work, but your mileage may vary. Ohcount does not support Windows. -Ohcount targets Ruby 1.8.6. The build script targets Rake 0.7.3. You will +Ohcount targets Ruby 1.8.6. The build script targets Rake 0.8.1. You will also require a C compiler to build the native extensions. -Ohcount requires Ragel (http://research.cs.queensu.ca/~thurston/ragel/) -Unfortunately, Ragel 6.2 is not recent enough so you will need the latest -version in SVN: svn://mambo.cs.queensu.ca/ragel/trunk/. +Ohcount requires Ragel 6.3 (http://research.cs.queensu.ca/~thurston/ragel/). +Older version of Ragel are not comptible. == Download -The source code for ohcount is available as a tarball: - - http://labs.ohloh.net/download/ohcount-1.0.2.tgz - -You can also download the source code as a Git repository: +Ohcount source code is available as a Git repository: git clone http://git.ohloh.net/git/ohcount.git == Installation -Ohcount is packaged as a RubyGem. To build and install the gem (you will need +Once Rake, GCC, and Ragel 6.3 are installed, you can build Ohcount as follows: + + $ rake clean + $ rake + +Ohcount can optionally be installed as a RubyGem. To build and install the gem (you will need root priveleges for the install): $ rake install @@ -72,11 +72,6 @@ To uninstall the RubyGem: $ gem uninstall ohcount -If you do not want to install the gem, you can simply build and run it like this: - - $ rake - $ bin/ohcount - == First Steps To measure the lines of code, simply pass filenames or directory names @@ -100,14 +95,14 @@ of the languages used in a source code file. For example: == Loading ohcount from Ruby -If you have installed ohcount as a gem, you can load it like this: +If you have not installed the gem, you'll have to make sure that +ohcount is on your Ruby load path and then require: - require 'rubygems' require 'ohcount' -If you have not installed the gem, you'll have to make sure that -ohcount is on your ruby load path and then require: +If you have installed ohcount as a gem, you can load it like this: + require 'rubygems' require 'ohcount' The bin/ohcount script shows examples of calling the ohcount @@ -120,7 +115,7 @@ These are the steps required to add a new language to ohcount: * Update Ohcount::Detector to identify files that use the new language. * Update Ohcount::DetectorTest to confirm the Detector changes. * Follow the detailed instructions in PARSER_DOC. -* In Ohcount::SlocInfo, provide a "nice name" and category (procedural +* In Ohcount::Language, provide a "nice name" and category (procedural code vs. markup) for the new language. * Create a new Ohcount::Test to verify the parser. diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb index 26ce018..892f523 100644 --- a/lib/ohcount/source_file.rb +++ b/lib/ohcount/source_file.rb @@ -1,18 +1,18 @@ module Ohcount require 'diff/lcs' - # SourceFile abstracts a source code file and allows easy querying of ohcount-related - # information. - # - # It provides some abstractions to enable ohloh to call it in its own, weird, way. - # For example, in simple usage scenarios, the SimpleFileContext can simply point - # to an actual file on disk. In more complex scenarios, the context allows the - # file contents to be delivered to ohcount from a temp file or in-memory cache. + # SourceFile represents a single source code file. # + # It can be a pointer to an actual file on disk, or it may strictly + # be an in-memory buffer. class SourceFile - # The filename we're dealing with. + # Required. The original name of the file, as it appears in the source tree. attr_accessor :filename + # The location on disk where the file contents can currently be found. + # This location does not need to match the original filename. + attr_accessor :file_location + # An array of names of other files in the source tree which # may be helpful when disambiguating the language used by the target file. # For instance, the presence of an Objective-C *.m file is a clue when @@ -21,28 +21,11 @@ class SourceFile # without it. attr_accessor :filenames - # The location on disk where the file content can currently be found. - # This might not be the same as the original name of the file. - # For example, file content might be stored in temporary directory. - attr_accessor :file_location - - # At a minimum, you must provide the filename. - # - # You may also optionally pass an array of names of other files in the source tree. - # This will assist when disambiguating the language used by the source file. - # If you do not include this array, language identification may be less accurate. - # - # The SimpleFileContext must provide access to the file content. You can do this - # by one of three means, which will be probed in the following order: - # - # 1. You may optionally pass the content of the source file as string +cached_contents+. - # - # 2. You may optionally provide +file_location+ as the name of a file on disk - # which contains the content of this source file. - # - # 3. If you do neither 1 nor 2, then +filename+ will be assumed to be an actual file on - # disk which can be read. + # If you pass :contents to this initializer, then SourceFile + # works in memory and does not need to access the file on disk. # + # If you do not pass the :contents, then SourceFile will first check + # :file_location and then :filename (in that order) to get the file contents. def initialize(filename, options = {}) @filename = filename @filenames = options[:filenames] || [] @@ -63,7 +46,7 @@ def polyglot @polyglot = Ohcount::Detector.detect(self) if file? end - # returns true iff we represent a file (could be a dir) + # Returns true iff we represent a file and not a directory def file? File.exist?(@filename) && File.file?(@filename) || @file_location && File.exist?(@file_location) && File.file?(@file_location) || @@ -86,10 +69,9 @@ def language_breakdown(language) language_breakdowns.find { |lb| lb.name == language.to_s } || LanguageBreakdown.new(language.to_s) end - # will yield with the current directory set in a way that the filename - # exists and contains the actual file contents. - # - # This is useful to call when a file must absolutely be referenced on disk. + # Yields a path to a physical file on disk containing the file contents. + # This is useful when a file absolutely must be referenced on disk. + # A temporary file will be created if an existing file is not available. def realize_file raise ArgumentError.new('Missing block?') unless block_given? @@ -98,8 +80,7 @@ def realize_file elsif @file_location && File.basename(@file_location) == basename yield @file_location else - - # must recreate a directory and stuff + # No existing copy. Create a temporary file. ScratchDir.new do |d| realized_filename = File.join(d,basename) File.open(realized_filename, "w") { |io| io.write(contents) } From 618cfb011a39f6aa0c728dd47cc3a7b692df0844 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 30 Jan 2009 22:23:16 +0100 Subject: [PATCH 088/387] Don't fail the "perl -w" detector test on my openSUSE 11 box. This system's file returns "script text for ..." instead of "script text executable for ..." Michael --- lib/ohcount/detector.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index 483cd2b..10aac49 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -588,7 +588,7 @@ def self.disambiguate_nil(source_file) file_output = source_file.realize_file { |f| `file -b '#{ f }'` } case file_output - when /([\w\/]+)(?: -[\w_]+)* script text/, /script text executable for ([\w\/]+)/ + when /([\w\/]+)(?: -[\w_]+)* script text/, /script text(?: executable)? for ([\w\/]+)/ script = $1 if script =~ /\/(\w*)$/ script = $1 From ad6ef87752144e8f56630938bba95c182b1eb6dc Mon Sep 17 00:00:00 2001 From: Nicolas Pierron Date: Tue, 27 Jan 2009 01:22:05 +0100 Subject: [PATCH 089/387] [NEW] Add support for "Nix". --- ext/ohcount_native/ragel_parser.c | 2 + ext/ohcount_native/ragel_parsers/nix.rl | 175 ++++++++++++++++++++++++++++++++ lib/ohcount/detector.rb | 1 + lib/ohcount/language.rb | 7 +- test/expected_dir/nix.nix | 24 +++++ test/src_dir/nix.nix | 24 +++++ test/unit/nix_test.rb | 13 +++ 7 files changed, 243 insertions(+), 3 deletions(-) create mode 100644 ext/ohcount_native/ragel_parsers/nix.rl create mode 100644 test/expected_dir/nix.nix create mode 100644 test/src_dir/nix.nix create mode 100644 test/unit/nix_test.rb diff --git a/ext/ohcount_native/ragel_parser.c b/ext/ohcount_native/ragel_parser.c index 9d035b3..31b4205 100644 --- a/ext/ohcount_native/ragel_parser.c +++ b/ext/ohcount_native/ragel_parser.c @@ -46,6 +46,7 @@ #include "metapost_parser.h" #include "metapost_with_tex_parser.h" #include "mxml_parser.h" +#include "nix_parser.h" #include "objective_c_parser.h" #include "objective_j_parser.h" #include "ocaml_parser.h" @@ -132,6 +133,7 @@ struct language languages[] = { { "metapost", parse_metapost }, { "metapost_with_tex", parse_mptex }, { "mxml", parse_mxml }, + { "nix", parse_nix }, { "objective_c", parse_objective_c }, { "objective_j", parse_objective_j }, { "ocaml", parse_ocaml }, diff --git a/ext/ohcount_native/ragel_parsers/nix.rl b/ext/ohcount_native/ragel_parsers/nix.rl new file mode 100644 index 0000000..4be0d4b --- /dev/null +++ b/ext/ohcount_native/ragel_parsers/nix.rl @@ -0,0 +1,175 @@ +/************************* Required for every parser *************************/ +#ifndef RAGEL_NIX_PARSER +#define RAGEL_NIX_PARSER + +#include "ragel_parser_macros.h" + +// the name of the language +const char *NIX_LANG = "nix"; + +// the languages entities +const char *nix_entities[] = { + "space", "comment", "any" +}; + +// constants associated with the entities +enum { + NIX_SPACE = 0, NIX_COMMENT, NIX_ANY +}; + +/*****************************************************************************/ + +#include "shell_parser.h" + +%%{ + machine nix; + write data; + include common "common.rl"; + #EMBED(shell) + + # Line counting machine + + action nix_ccallback { + switch(entity) { + case NIX_SPACE: + ls + break; + case NIX_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(NIX_LANG) + break; + case NEWLINE: + std_newline(NIX_LANG) + break; + case CHECK_BLANK_ENTRY: + check_blank_entry(NIX_LANG) + } + } + + nix_line_comment = '#' @comment nonnewline*; + + nix_block_comment = + '/*' @comment ( + newline %{ entity = INTERNAL_NL; } %nix_ccallback + | + ws + | + (nonnewline - ws) @comment + )* :>> '*/'; + + nix_comment = nix_line_comment | nix_block_comment; + + nix_dq_shell_entry = '"' @code; + nix_dq_shell_outry = '"' @check_blank_outry @code; + nix_dq_shell_line := |* + nix_dq_shell_outry @{ p = ts; fret; }; + # TODO: Add embeded Nix between '${' and '}' + # unmodified SHELL patterns + spaces ${ entity = SHELL_SPACE; } => shell_ccallback; + shell_comment; + shell_string; + newline ${ entity = NEWLINE; } => shell_ccallback; + ^space ${ entity = SHELL_ANY; } => shell_ccallback; + *|; + + nix_dsq_shell_entry = "''" @code; + nix_dsq_shell_outry = "''" @check_blank_outry @code; + nix_dsq_shell_line := |* + nix_dsq_shell_outry @{ p = ts; fret; }; + # TODO: Add embeded Nix between '${' and '}' + # unmodified SHELL patterns + spaces ${ entity = SHELL_SPACE; } => shell_ccallback; + shell_comment; + shell_string; + newline ${ entity = NEWLINE; } => shell_ccallback; + ^space ${ entity = SHELL_ANY; } => shell_ccallback; + *|; + + nix_line := |* + nix_dq_shell_entry @{ entity = CHECK_BLANK_ENTRY; } @nix_ccallback + @{ saw(SHELL_LANG); } => { fcall nix_dq_shell_line; }; + nix_dsq_shell_entry @{ entity = CHECK_BLANK_ENTRY; } @nix_ccallback + @{ saw(SHELL_LANG); } => { fcall nix_dsq_shell_line; }; + # NIX patterns + spaces ${ entity = NIX_SPACE; } => nix_ccallback; + nix_comment; + newline ${ entity = NEWLINE; } => nix_ccallback; + ^space ${ entity = NIX_ANY; } => nix_ccallback; + *|; + + # Entity machine + + action nix_ecallback { + callback(NIX_LANG, nix_entities[entity], cint(ts), cint(te)); + } + + nix_line_comment_entity = '#' nonnewline*; + nix_block_comment_entity = '/*' any* :>> '*/'; + nix_comment_entity = nix_line_comment_entity | nix_block_comment_entity; + + + nix_dq_shell_entry_entity = '"'; + nix_dq_shell_outry_entity = '"'; + nix_dq_shell_entity := |* + nix_dq_shell_outry_entity @{ fret; }; + # TODO: Add embeded Nix between '${' and '}' + # unmodified SHELL patterns + space+ ${ entity = SHELL_SPACE; } => shell_ecallback; + shell_comment_entity ${ entity = SHELL_COMMENT; } => shell_ecallback; + # TODO: + ^space; + *|; + + nix_dsq_shell_entry_entity = "''"; + nix_dsq_shell_outry_entity = "''"; + nix_dsq_shell_entity := |* + nix_dsq_shell_outry_entity @{ fret; }; + # TODO: Add embeded Nix between '${' and '}' + # unmodified SHELL patterns + space+ ${ entity = SHELL_SPACE; } => shell_ecallback; + shell_comment_entity ${ entity = SHELL_COMMENT; } => shell_ecallback; + # TODO: + ^space; + *|; + + nix_entity := |* + nix_dq_shell_entry_entity => { fcall nix_dq_shell_entity; }; + nix_dsq_shell_entry_entity => { fcall nix_dsq_shell_entity; }; + space+ ${ entity = NIX_SPACE; } => nix_ecallback; + nix_comment_entity ${ entity = NIX_COMMENT; } => nix_ecallback; + # TODO; + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with Nix code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_nix(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int start, int end) + ) { + init + + %% write init; + cs = (count) ? nix_en_nix_line : nix_en_nix_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(NIX_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index 10aac49..bdbcc03 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -197,6 +197,7 @@ def self.binary_filename?(filename) '.mm' => "objective_c", '.mp' => 'metapost_with_tex', '.mxml' => 'mxml', + '.nix' => 'nix', '.nse' => 'lua', '.pas' => "pascal", '.pp' => "pascal", diff --git a/lib/ohcount/language.rb b/lib/ohcount/language.rb index 10197db..b914531 100644 --- a/lib/ohcount/language.rb +++ b/lib/ohcount/language.rb @@ -18,7 +18,7 @@ def lang_map 'bmx' => {:nice_name => 'BlitzMax' , :category => 0}, 'boo' => {:nice_name => 'Boo' , :category => 0}, 'c' => {:nice_name => 'C' , :category => 0}, - 'classic_basic' => {:nice_name => 'Classic Basic' , :category => 0}, + 'classic_basic' => {:nice_name => 'Classic Basic' , :category => 0}, 'cpp' => {:nice_name => 'C++' , :category => 0}, 'clearsilver' => {:nice_name => 'ClearSilver' , :category => 0}, 'csharp' => {:nice_name => 'C#' , :category => 0}, @@ -47,15 +47,16 @@ def lang_map 'metafont' => {:nice_name => 'MetaFont' , :category => 1}, 'metapost' => {:nice_name => 'MetaPost' , :category => 1}, 'mxml' => {:nice_name => 'Flex' , :category => 1}, + 'nix' => {:nice_name => 'Nix' , :category => 0}, 'objective_c' => {:nice_name => 'Objective C' , :category => 0}, - 'objective_j' => {:nice_name => 'Objective-J' , :category => 0}, + 'objective_j' => {:nice_name => 'Objective-J' , :category => 0}, 'ocaml' => {:nice_name => 'Objective Caml' , :category => 0}, 'pascal' => {:nice_name => 'Pascal' , :category => 0}, 'perl' => {:nice_name => 'Perl' , :category => 0}, 'php' => {:nice_name => 'PHP' , :category => 0}, 'pike' => {:nice_name => 'Pike' , :category => 0}, 'python' => {:nice_name => 'Python' , :category => 0}, - 'r' => {:nice_name => 'R' , :category => 0}, + 'r' => {:nice_name => 'R' , :category => 0}, 'rexx' => {:nice_name => 'rexx' , :category => 0}, 'ruby' => {:nice_name => 'Ruby' , :category => 0}, 'scheme' => {:nice_name => 'Scheme' , :category => 0}, diff --git a/test/expected_dir/nix.nix b/test/expected_dir/nix.nix new file mode 100644 index 0000000..db848ea --- /dev/null +++ b/test/expected_dir/nix.nix @@ -0,0 +1,24 @@ +nix code {pkgs,config}: +nix blank +nix comment # one line comment +nix code { +nix comment /* mulpiple line comment +nix comment foo = 21; +nix comment */ +nix code bar = " +shell comment #!/bin/sh +shell blank +shell code ls -la +shell comment # comment +shell code echo hello #comment +nix code "; +nix blank +nix code baz = '' +shell comment #!/bin/sh +shell blank +shell code ls -la +shell comment # comment +shell code echo hello #comment +nix code ''; +nix code nixHttp = [ http://nixos.org/ ]; +nix code } diff --git a/test/src_dir/nix.nix b/test/src_dir/nix.nix new file mode 100644 index 0000000..0c92adb --- /dev/null +++ b/test/src_dir/nix.nix @@ -0,0 +1,24 @@ +{pkgs,config}: + +# one line comment +{ +/* mulpiple line comment + foo = 21; +*/ + bar = " + #!/bin/sh + + ls -la + # comment + echo hello #comment + "; + + baz = '' + #!/bin/sh + + ls -la + # comment + echo hello #comment + ''; + nixHttp = [ http://nixos.org/ ]; +} diff --git a/test/unit/nix_test.rb b/test/unit/nix_test.rb new file mode 100644 index 0000000..f62ce1b --- /dev/null +++ b/test/unit/nix_test.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class Ohcount::NixTest < Ohcount::Test + def test_line_comments + lb = [Ohcount::LanguageBreakdown.new("nix", "", "# comment", 0)] + assert_equal lb, Ohcount::parse("# comment", "nix") + end + + def test_comprehensive + verify_parse("nix.nix") + end + +end From 67478a5b6aa0ef34ebda643d4b75a5cadc9e894c Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Sat, 31 Jan 2009 06:32:21 -0800 Subject: [PATCH 090/387] [FIX] Improvements to the build process: - accurate dependencies, for more reliable, efficient builds - ragel output files are kept in ragel_parsers directory - Rakefile cleanups --- Rakefile | 66 +++++++--- ext/ohcount_native/.gitignore | 3 - ext/ohcount_native/extconf.rb | 2 +- ext/ohcount_native/ragel_parser.c | 142 ++++++++++----------- ext/ohcount_native/ragel_parsers/.gitignore | 1 + .../ragel_parsers/clearsilverhtml.rl | 6 +- .../ragel_parsers/construct_embedded.rb | 26 ---- ext/ohcount_native/ragel_parsers/cs_aspx.rl | 6 +- ext/ohcount_native/ragel_parsers/haml.rl | 2 +- ext/ohcount_native/ragel_parsers/html.rl | 4 +- ext/ohcount_native/ragel_parsers/jsp.rl | 6 +- .../ragel_parsers/metapost_with_tex.rl | 5 +- ext/ohcount_native/ragel_parsers/mxml.rl | 4 +- ext/ohcount_native/ragel_parsers/nix.rl | 2 +- ext/ohcount_native/ragel_parsers/phphtml.rl | 6 +- ext/ohcount_native/ragel_parsers/rhtml.rl | 6 +- ext/ohcount_native/ragel_parsers/vb_aspx.rl | 6 +- 17 files changed, 148 insertions(+), 145 deletions(-) create mode 100644 ext/ohcount_native/ragel_parsers/.gitignore delete mode 100644 ext/ohcount_native/ragel_parsers/construct_embedded.rb diff --git a/Rakefile b/Rakefile index 3d20472..ad6b6a9 100644 --- a/Rakefile +++ b/Rakefile @@ -14,15 +14,18 @@ EXT_DL = "#{EXT_DIR}/ohcount_native.#{CONFIG['DLEXT']}" ARCH_DIR = "lib/#{::Config::CONFIG['arch']}" ARCH_DL = "#{ARCH_DIR}/ohcount_native.#{CONFIG['DLEXT']}" +RAGEL_DIR = File.join(EXT_DIR, 'ragel_parsers') + CLEAN.include FileList["#{EXT_DIR}/*.{so,bundle,#{CONFIG['DLEXT']}}"], FileList["#{EXT_DIR}/*.o"], FileList["#{EXT_DIR}/Makefile"], - (FileList["#{EXT_DIR}/*_parser.h"] - FileList["#{EXT_DIR}/ragel_parser.h"]) + FileList["#{RAGEL_DIR}/*.h"] + FileList["#{RAGEL_DIR}/*.tmp"] RDOC_OPTS = ['--quiet', '--title', 'Ohcount Reference', '--main', 'README', '--inline-source'] PKG_FILES = %w(README COPYING Rakefile lib/ohcount.rb) + - Dir.glob("ext/ohcount_native/*.{h,c,rb}") + + Dir.glob("#{EXT_DIR}/*.{h,c,rb}") + Dir.glob("lib/**/*.rb") + Dir.glob("test/*") + Dir.glob("test/**/*") + @@ -61,27 +64,54 @@ file ARCH_DL => EXT_DL do cp EXT_DL, ARCH_DIR end -file EXT_DL => FileList["#{EXT_DIR}/Makefile", "#{EXT_DIR}/*.{c,h,rb}"] do - cd EXT_DIR do - cd 'ragel_parsers' do - require 'construct_embedded' - rls = FileList['*.rl'] - rls.exclude('common.rl') - rls.each do |rl| - h = rl.scan(/^(.+)\.rl$/).flatten.first + '_parser.h' - if has_embedded?(rl) - construct_language(rl) - sh "ragel #{rl + '.tmp'} -o ../#{h}" - File.delete(rl + '.tmp') - else - sh "ragel #{rl} -o ../#{h}" - end - end +rule ".h" => ".rl" do |t| + if has_embedded_language?(t.source) + construct_language(t.source) do |constructed_file| + sh "ragel #{constructed_file} -o #{t.name}" end + else + sh "ragel #{t.source} -o #{t.name}" + end +end + +def has_embedded_language?(parser_file) + return IO.read(parser_file).include?('#EMBED') +end + +def construct_language(parser_file) + parser_text = IO.read(parser_file).gsub(/#EMBED\([\w_]+\)/) do |elang| + lang = elang.scan(/^#EMBED\(([\w_]+)\)/)[0][0] + eparser_file = File.join(RAGEL_DIR, lang + '.rl') + if File.exists?(eparser_file) + eparser = IO.read(eparser_file) + ragel = eparser.scan(/%%\{(.+?)\}%%/m)[0][0] + # eliminate machine definition, writes, and includes + ragel.gsub!(/^\s*machine[^;]+;\s+write[^;]+;\s+include[^;]+;\s+/, '') + "}%%\n%%{\n#{ragel}" + else + '' + end + end + tmp = parser_file + '.tmp' + File.open(tmp, 'w') { |f| f.write parser_text } + yield tmp + File.delete(tmp) +end + +file EXT_DL => FileList["#{EXT_DIR}/Makefile", "#{EXT_DIR}/*.{c,h,rb}", "#{RAGEL_DIR}/*.h"] do + cd EXT_DIR do sh 'make' end end +file "#{EXT_DIR}/ragel_parser.c" => FileList["#{RAGEL_DIR}/*.rl"].gsub(/\.rl/,'.h') do + # When any ragel parser changes, we need to rebuild ragel_parser.c. + # We force this by deleting the existing object file. + # We have no better option than this because C dependencies are controlled by mkmf, + # outside of the control of this Rakefile. + File.delete(File.join(EXT_DIR, 'ragel_parser.o')) if File.exist?(File.join(EXT_DIR, 'ragel_parser.o')) +end + file "#{EXT_DIR}/Makefile" => "#{EXT_DIR}/extconf.rb" do cd EXT_DIR do if ENV['DEBUG'] diff --git a/ext/ohcount_native/.gitignore b/ext/ohcount_native/.gitignore index ad54236..0c6e877 100644 --- a/ext/ohcount_native/.gitignore +++ b/ext/ohcount_native/.gitignore @@ -3,6 +3,3 @@ Makefile *.log *.so *.bundle -polyglots.c -*_parser.h -!ragel_parser.h diff --git a/ext/ohcount_native/extconf.rb b/ext/ohcount_native/extconf.rb index 229a130..7d16135 100644 --- a/ext/ohcount_native/extconf.rb +++ b/ext/ohcount_native/extconf.rb @@ -8,7 +8,7 @@ puts "BUILD_TYPE: DEBUG" else puts "BUILD_TYPE: RELEASE" - $CFLAGS = "#{$CFLAGS} -g -O2 -Wall -DNDEBUG" + $CFLAGS << " -Wall -DNDEBUG" end create_makefile('ohcount_native') diff --git a/ext/ohcount_native/ragel_parser.c b/ext/ohcount_native/ragel_parser.c index 31b4205..5e8066a 100644 --- a/ext/ohcount_native/ragel_parser.c +++ b/ext/ohcount_native/ragel_parser.c @@ -4,77 +4,77 @@ #include "common.h" // BEGIN parser includes -#include "actionscript_parser.h" -#include "ada_parser.h" -#include "assembler_parser.h" -#include "autoconf_parser.h" -#include "automake_parser.h" -#include "awk_parser.h" -#include "bat_parser.h" -#include "blitzmax_parser.h" -#include "boo_parser.h" -#include "c_parser.h" -#include "classic_basic_parser.h" -#include "clearsilver_parser.h" -#include "clearsilverhtml_parser.h" -#include "cs_aspx_parser.h" -#include "css_parser.h" -#include "d_parser.h" -#include "dcl_parser.h" -#include "dylan_parser.h" -#include "ebuild_parser.h" -#include "eiffel_parser.h" -#include "erlang_parser.h" -#include "exheres_parser.h" -#include "factor_parser.h" -#include "fortranfixed_parser.h" -#include "fortranfree_parser.h" -#include "glsl_parser.h" -#include "groovy_parser.h" -#include "haml_parser.h" -#include "haskell_parser.h" -#include "haxe_parser.h" -#include "html_parser.h" -#include "java_parser.h" -#include "javascript_parser.h" -#include "jsp_parser.h" -#include "lisp_parser.h" -#include "lua_parser.h" -#include "makefile_parser.h" -#include "matlab_parser.h" -#include "metafont_parser.h" -#include "metapost_parser.h" -#include "metapost_with_tex_parser.h" -#include "mxml_parser.h" -#include "nix_parser.h" -#include "objective_c_parser.h" -#include "objective_j_parser.h" -#include "ocaml_parser.h" -#include "pascal_parser.h" -#include "perl_parser.h" -#include "phphtml_parser.h" -#include "pike_parser.h" -#include "python_parser.h" -#include "r_parser.h" -#include "rexx_parser.h" -#include "ruby_parser.h" -#include "rhtml_parser.h" -#include "scala_parser.h" -#include "shell_parser.h" -#include "smalltalk_parser.h" -#include "stratego_parser.h" -#include "structured_basic_parser.h" -#include "sql_parser.h" -#include "tcl_parser.h" -#include "tex_parser.h" -#include "vb_aspx_parser.h" -#include "vhdl_parser.h" -#include "vim_parser.h" -#include "visual_basic_parser.h" -#include "xaml_parser.h" -#include "xml_parser.h" -#include "xslt_parser.h" -#include "xmlschema_parser.h" +#include "ragel_parsers/actionscript.h" +#include "ragel_parsers/ada.h" +#include "ragel_parsers/assembler.h" +#include "ragel_parsers/autoconf.h" +#include "ragel_parsers/automake.h" +#include "ragel_parsers/awk.h" +#include "ragel_parsers/bat.h" +#include "ragel_parsers/blitzmax.h" +#include "ragel_parsers/boo.h" +#include "ragel_parsers/c.h" +#include "ragel_parsers/classic_basic.h" +#include "ragel_parsers/clearsilver.h" +#include "ragel_parsers/clearsilverhtml.h" +#include "ragel_parsers/cs_aspx.h" +#include "ragel_parsers/css.h" +#include "ragel_parsers/d.h" +#include "ragel_parsers/dcl.h" +#include "ragel_parsers/dylan.h" +#include "ragel_parsers/ebuild.h" +#include "ragel_parsers/eiffel.h" +#include "ragel_parsers/erlang.h" +#include "ragel_parsers/exheres.h" +#include "ragel_parsers/factor.h" +#include "ragel_parsers/fortranfixed.h" +#include "ragel_parsers/fortranfree.h" +#include "ragel_parsers/glsl.h" +#include "ragel_parsers/groovy.h" +#include "ragel_parsers/haml.h" +#include "ragel_parsers/haskell.h" +#include "ragel_parsers/haxe.h" +#include "ragel_parsers/html.h" +#include "ragel_parsers/java.h" +#include "ragel_parsers/javascript.h" +#include "ragel_parsers/jsp.h" +#include "ragel_parsers/lisp.h" +#include "ragel_parsers/lua.h" +#include "ragel_parsers/makefile.h" +#include "ragel_parsers/matlab.h" +#include "ragel_parsers/metafont.h" +#include "ragel_parsers/metapost.h" +#include "ragel_parsers/metapost_with_tex.h" +#include "ragel_parsers/mxml.h" +#include "ragel_parsers/nix.h" +#include "ragel_parsers/objective_c.h" +#include "ragel_parsers/objective_j.h" +#include "ragel_parsers/ocaml.h" +#include "ragel_parsers/pascal.h" +#include "ragel_parsers/perl.h" +#include "ragel_parsers/phphtml.h" +#include "ragel_parsers/pike.h" +#include "ragel_parsers/python.h" +#include "ragel_parsers/r.h" +#include "ragel_parsers/rexx.h" +#include "ragel_parsers/ruby.h" +#include "ragel_parsers/rhtml.h" +#include "ragel_parsers/scala.h" +#include "ragel_parsers/shell.h" +#include "ragel_parsers/smalltalk.h" +#include "ragel_parsers/stratego.h" +#include "ragel_parsers/structured_basic.h" +#include "ragel_parsers/sql.h" +#include "ragel_parsers/tcl.h" +#include "ragel_parsers/tex.h" +#include "ragel_parsers/vb_aspx.h" +#include "ragel_parsers/vhdl.h" +#include "ragel_parsers/vim.h" +#include "ragel_parsers/visual_basic.h" +#include "ragel_parsers/xaml.h" +#include "ragel_parsers/xml.h" +#include "ragel_parsers/xslt.h" +#include "ragel_parsers/xmlschema.h" // END parser includes ParseResult *pr; diff --git a/ext/ohcount_native/ragel_parsers/.gitignore b/ext/ohcount_native/ragel_parsers/.gitignore new file mode 100644 index 0000000..424c745 --- /dev/null +++ b/ext/ohcount_native/ragel_parsers/.gitignore @@ -0,0 +1 @@ +*.h diff --git a/ext/ohcount_native/ragel_parsers/clearsilverhtml.rl b/ext/ohcount_native/ragel_parsers/clearsilverhtml.rl index f2b8752..41528cd 100644 --- a/ext/ohcount_native/ragel_parsers/clearsilverhtml.rl +++ b/ext/ohcount_native/ragel_parsers/clearsilverhtml.rl @@ -23,9 +23,9 @@ enum { /*****************************************************************************/ -#include "css_parser.h" -#include "javascript_parser.h" -#include "clearsilver_parser.h" +#include "css.h" +#include "javascript.h" +#include "clearsilver.h" %%{ machine cshtml; diff --git a/ext/ohcount_native/ragel_parsers/construct_embedded.rb b/ext/ohcount_native/ragel_parsers/construct_embedded.rb deleted file mode 100644 index feaa78a..0000000 --- a/ext/ohcount_native/ragel_parsers/construct_embedded.rb +++ /dev/null @@ -1,26 +0,0 @@ -=begin - construct_embedded written by Mitchell Foral. mitchellcaladbolgnet. -=end - -def has_embedded?(parser_file) - return IO.read(parser_file).include?('#EMBED') -end - -def construct_language(parser_file) - parser_text = IO.read(parser_file).gsub(/#EMBED\([\w_]+\)/) do |elang| - lang = elang.scan(/^#EMBED\(([\w_]+)\)/)[0][0] - eparser_file = lang + '.rl' - if File.exists?(eparser_file) - eparser = IO.read(eparser_file) - ragel = eparser.scan(/%%\{(.+?)\}%%/m)[0][0] - # eliminate machine definition, writes, and includes - ragel.gsub!(/^\s*machine[^;]+;\s+write[^;]+;\s+include[^;]+;\s+/, '') - "}%%\n%%{\n#{ragel}" - else - '' - end - end - f = File.new(parser_file + '.tmp', 'w') - f.write(parser_text) - f.close -end diff --git a/ext/ohcount_native/ragel_parsers/cs_aspx.rl b/ext/ohcount_native/ragel_parsers/cs_aspx.rl index 0cfb805..60997de 100644 --- a/ext/ohcount_native/ragel_parsers/cs_aspx.rl +++ b/ext/ohcount_native/ragel_parsers/cs_aspx.rl @@ -21,9 +21,9 @@ enum { /*****************************************************************************/ -#include "css_parser.h" -#include "javascript_parser.h" -#include "c_parser.h" +#include "css.h" +#include "javascript.h" +#include "c.h" %%{ machine cs_aspx; diff --git a/ext/ohcount_native/ragel_parsers/haml.rl b/ext/ohcount_native/ragel_parsers/haml.rl index b421591..ecb25a7 100644 --- a/ext/ohcount_native/ragel_parsers/haml.rl +++ b/ext/ohcount_native/ragel_parsers/haml.rl @@ -23,7 +23,7 @@ enum { /*****************************************************************************/ -#include "ruby_parser.h" +#include "ruby.h" %%{ machine haml; diff --git a/ext/ohcount_native/ragel_parsers/html.rl b/ext/ohcount_native/ragel_parsers/html.rl index 366daf3..c83490e 100644 --- a/ext/ohcount_native/ragel_parsers/html.rl +++ b/ext/ohcount_native/ragel_parsers/html.rl @@ -23,8 +23,8 @@ enum { /*****************************************************************************/ -#include "css_parser.h" -#include "javascript_parser.h" +#include "css.h" +#include "javascript.h" %%{ machine html; diff --git a/ext/ohcount_native/ragel_parsers/jsp.rl b/ext/ohcount_native/ragel_parsers/jsp.rl index dd55aa4..c5a362e 100644 --- a/ext/ohcount_native/ragel_parsers/jsp.rl +++ b/ext/ohcount_native/ragel_parsers/jsp.rl @@ -23,9 +23,9 @@ enum { /*****************************************************************************/ -#include "css_parser.h" -#include "javascript_parser.h" -#include "java_parser.h" +#include "css.h" +#include "javascript.h" +#include "java.h" %%{ machine jsp; diff --git a/ext/ohcount_native/ragel_parsers/metapost_with_tex.rl b/ext/ohcount_native/ragel_parsers/metapost_with_tex.rl index 25acd0f..b33a296 100644 --- a/ext/ohcount_native/ragel_parsers/metapost_with_tex.rl +++ b/ext/ohcount_native/ragel_parsers/metapost_with_tex.rl @@ -11,9 +11,10 @@ const char *MPTEX_LANG = "metapost"; // the languages entities const char *mptex_entities[] = { - "space", "comment", "string", "any", + "space", "comment", "string", "any" }; + // constants associated with the entities enum { MPTEX_SPACE = 0, MPTEX_COMMENT, MPTEX_STRING, MPTEX_ANY @@ -21,7 +22,7 @@ enum { /*****************************************************************************/ -#include "tex_parser.h" +#include "tex.h" %%{ machine mptex; diff --git a/ext/ohcount_native/ragel_parsers/mxml.rl b/ext/ohcount_native/ragel_parsers/mxml.rl index 8a4d9c0..820e4b8 100644 --- a/ext/ohcount_native/ragel_parsers/mxml.rl +++ b/ext/ohcount_native/ragel_parsers/mxml.rl @@ -23,8 +23,8 @@ enum { /*****************************************************************************/ -#include "css_parser.h" -#include "actionscript_parser.h" +#include "css.h" +#include "actionscript.h" %%{ machine mxml; diff --git a/ext/ohcount_native/ragel_parsers/nix.rl b/ext/ohcount_native/ragel_parsers/nix.rl index 4be0d4b..6b35eaf 100644 --- a/ext/ohcount_native/ragel_parsers/nix.rl +++ b/ext/ohcount_native/ragel_parsers/nix.rl @@ -19,7 +19,7 @@ enum { /*****************************************************************************/ -#include "shell_parser.h" +#include "shell.h" %%{ machine nix; diff --git a/ext/ohcount_native/ragel_parsers/phphtml.rl b/ext/ohcount_native/ragel_parsers/phphtml.rl index 99471fa..4c3de86 100644 --- a/ext/ohcount_native/ragel_parsers/phphtml.rl +++ b/ext/ohcount_native/ragel_parsers/phphtml.rl @@ -23,9 +23,9 @@ enum { /*****************************************************************************/ -#include "css_parser.h" -#include "javascript_parser.h" -#include "php_parser.h" +#include "css.h" +#include "javascript.h" +#include "php.h" %%{ machine phtml; diff --git a/ext/ohcount_native/ragel_parsers/rhtml.rl b/ext/ohcount_native/ragel_parsers/rhtml.rl index 35641db..b01c7f6 100644 --- a/ext/ohcount_native/ragel_parsers/rhtml.rl +++ b/ext/ohcount_native/ragel_parsers/rhtml.rl @@ -23,9 +23,9 @@ enum { /*****************************************************************************/ -#include "css_parser.h" -#include "javascript_parser.h" -#include "ruby_parser.h" +#include "css.h" +#include "javascript.h" +#include "ruby.h" %%{ machine rhtml; diff --git a/ext/ohcount_native/ragel_parsers/vb_aspx.rl b/ext/ohcount_native/ragel_parsers/vb_aspx.rl index c7eca7c..486156a 100644 --- a/ext/ohcount_native/ragel_parsers/vb_aspx.rl +++ b/ext/ohcount_native/ragel_parsers/vb_aspx.rl @@ -21,9 +21,9 @@ enum { /*****************************************************************************/ -#include "css_parser.h" -#include "javascript_parser.h" -#include "visual_basic_parser.h" +#include "css.h" +#include "javascript.h" +#include "visual_basic.h" %%{ machine vb_aspx; From f81bb8d71e7c1d20e0661aa22cb36fbfb1639c4c Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Sat, 31 Jan 2009 08:03:22 -0800 Subject: [PATCH 091/387] [FIX] Many fixes to GemSpec: - Now includes all files (was missing rules.rb, platforms.rb) - RDoc now builds properly (no missing README warnings, no duplicated files) - Removed the [always misplaced] /rules folder and put its contents into the /lib/gestalt folder. --- README | 24 +++++++++++++----------- Rakefile | 22 ++++++++++++---------- {rules => lib/gestalt}/platforms.rb | 0 {rules => lib/gestalt}/tools.rb | 0 lib/ohcount.rb | 5 ++--- 5 files changed, 27 insertions(+), 24 deletions(-) rename {rules => lib/gestalt}/platforms.rb (100%) rename {rules => lib/gestalt}/tools.rb (100%) diff --git a/README b/README index 9bd49b8..8630a0d 100644 --- a/README +++ b/README @@ -47,26 +47,28 @@ Ohcount does not support Windows. Ohcount targets Ruby 1.8.6. The build script targets Rake 0.8.1. You will also require a C compiler to build the native extensions. -Ohcount requires Ragel 6.3 (http://research.cs.queensu.ca/~thurston/ragel/). -Older version of Ragel are not comptible. - == Download Ohcount source code is available as a Git repository: git clone http://git.ohloh.net/git/ohcount.git -== Installation +== Building Ohcount + +During the build process, Ohcount requires Ragel version 6.3 or later. +Older versions of Ragel are not compatible. Visit the Ragel homepage at: + + http://research.cs.queensu.ca/~thurston/ragel/ Once Rake, GCC, and Ragel 6.3 are installed, you can build Ohcount as follows: - $ rake clean $ rake -Ohcount can optionally be installed as a RubyGem. To build and install the gem (you will need -root priveleges for the install): +Ohcount can optionally be installed as a RubyGem. To build and install the gem +(you will need root priveleges for the gem install): - $ rake install + $ rake gem + $ gem install pkg/ohcount-2.0.0 To uninstall the RubyGem: @@ -74,8 +76,8 @@ To uninstall the RubyGem: == First Steps -To measure the lines of code, simply pass filenames or directory names -to the +ohcount+ script: +To measure lines of code, simply pass file or directory names to the +ohcount+ +script, located in the +bin+ subdirectory: $ ohcount helloworld.c @@ -93,7 +95,7 @@ of the languages used in a source code file. For example: $ ohcount --annotate ./test/src_dir/php1.php -== Loading ohcount from Ruby +== Loading Ohcount From Ruby If you have not installed the gem, you'll have to make sure that ohcount is on your Ruby load path and then require: diff --git a/Rakefile b/Rakefile index ad6b6a9..117c644 100644 --- a/Rakefile +++ b/Rakefile @@ -24,11 +24,17 @@ CLEAN.include FileList["#{EXT_DIR}/*.{so,bundle,#{CONFIG['DLEXT']}}"], RDOC_OPTS = ['--quiet', '--title', 'Ohcount Reference', '--main', 'README', '--inline-source'] +Rake::RDocTask.new do |rdoc| + rdoc.rdoc_dir = 'doc' + rdoc.options += RDOC_OPTS + rdoc.rdoc_files.add ['README' ,'COPYING', 'lib/**/*.rb', 'ext/**/*.rb', 'ext/**/*.c', 'test/test_helper.rb', 'test/unit/detector_test.rb'] +end + PKG_FILES = %w(README COPYING Rakefile lib/ohcount.rb) + Dir.glob("#{EXT_DIR}/*.{h,c,rb}") + + Dir.glob("#{RAGEL_DIR}/*.h") + + Dir.glob("#{RAGEL_DIR}/*.rl") + Dir.glob("lib/**/*.rb") + - Dir.glob("test/*") + - Dir.glob("test/**/*") + Dir.glob("bin/*") SPEC = @@ -38,16 +44,18 @@ SPEC = s.platform = Gem::Platform::RUBY s.has_rdoc = true s.rdoc_options = RDOC_OPTS + s.extra_rdoc_files = ['README'] s.summary = "The Ohloh source code line counter" s.description = s.summary s.author = "Ohloh Corporation" s.email = "info@ohloh.net" s.homepage = "http://labs.ohloh.net/ohcount" - s.files = PKG_FILES - s.require_paths << 'lib' + s.files = PKG_FILES.to_a + s.require_paths = ['lib'] s.extensions << 'ext/ohcount_native/extconf.rb' s.bindir = 'bin' s.executables = ['ohcount'] + s.add_dependency 'diff-lcs' end Rake::GemPackageTask.new(SPEC) do |p| @@ -122,12 +130,6 @@ file "#{EXT_DIR}/Makefile" => "#{EXT_DIR}/extconf.rb" do end end -Rake::RDocTask.new do |rdoc| - rdoc.rdoc_dir = 'doc' - rdoc.options += RDOC_OPTS - rdoc.rdoc_files.add ['README' ,'COPYING', 'lib/**/*.rb', 'ext/**/*.rb', 'ext/**/*.c', 'test/test_helper.rb', 'test/unit/detector_test.rb'] -end - Rake::TestTask.new :ohcount_unit_tests => ARCH_DL do |t| # puts File.dirname(__FILE__) + '/test/unit/*_test.rb' t.test_files = FileList[File.dirname(__FILE__) + '/test/unit/**/*_test.rb'] diff --git a/rules/platforms.rb b/lib/gestalt/platforms.rb similarity index 100% rename from rules/platforms.rb rename to lib/gestalt/platforms.rb diff --git a/rules/tools.rb b/lib/gestalt/tools.rb similarity index 100% rename from rules/tools.rb rename to lib/gestalt/tools.rb diff --git a/lib/ohcount.rb b/lib/ohcount.rb index c864d1d..ccd1a9e 100644 --- a/lib/ohcount.rb +++ b/lib/ohcount.rb @@ -30,7 +30,6 @@ module Ohcount require "lib/licenses/license_sniffer" require "lib/gestalt/platform" +require "lib/gestalt/platforms" require "lib/gestalt/tool" - -require 'rules/platforms' -require 'rules/tools' +require "lib/gestalt/tools" From 5122d664dcf1eef9de526f2fcc86e146796e6c55 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Wed, 18 Feb 2009 15:44:36 -0800 Subject: [PATCH 092/387] [NEW] Implement LocList += LocDelta and LocList += LocDeltaList This lets us use LocList to keep a running total of LocDeltas --- lib/ohcount/loc_list.rb | 24 ++++++++++++++++++++++-- test/unit/loc_list_test.rb | 45 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/lib/ohcount/loc_list.rb b/lib/ohcount/loc_list.rb index f87aff6..3c66923 100644 --- a/lib/ohcount/loc_list.rb +++ b/lib/ohcount/loc_list.rb @@ -17,10 +17,14 @@ def languages def +(addend) case addend - when LocList - add_loc_list(addend) when Loc add_loc(addend) + when LocList + add_loc_list(addend) + when LocDelta + add_loc_delta(addend) + when LocDeltaList + add_loc_delta_list(addend) else raise ArgumentError.new end @@ -42,6 +46,22 @@ def add_loc(addend) self end + def add_loc_delta(addend) + l = loc(addend.language) + unless l + l = Loc.new(addend.language) + @locs << l + end + l.code += addend.code_added - addend.code_removed + l.comments += addend.comments_added - addend.comments_removed + l.blanks += addend.blanks_added - addend.blanks_removed + self + end + + def add_loc_delta_list(addend) + addend.loc_deltas.each { |d| add_loc_delta(d) } + end + def code @locs.inject(0) { |sum, loc| sum + loc.code } end diff --git a/test/unit/loc_list_test.rb b/test/unit/loc_list_test.rb index 9654fdb..9a85823 100644 --- a/test/unit/loc_list_test.rb +++ b/test/unit/loc_list_test.rb @@ -68,7 +68,7 @@ def test_add_same_language_twice list = LocList.new c1 = Loc.new('c', :code => 1, :comments => 2, :blanks => 3) - list += c1 + list += c1 c2 = Loc.new('c', :code => 10, :comments => 20, :blanks => 30) list += c2 @@ -95,6 +95,49 @@ def test_add_loc_lists assert_equal 16, sum.code end + def test_add_loc_delta + list = LocList.new + + delta = LocDelta.new('c', :code_added => 1, :code_removed => 0, + :comments_added => 2, :comments_removed => 0, + :blanks_added => 3, :blanks_removed => 0) + list += delta + + assert_equal 1, list.locs.size + assert_equal 1, list.loc('c').code + assert_equal 2, list.loc('c').comments + assert_equal 3, list.loc('c').blanks + + delta = LocDelta.new('c', :code_added => 10, :code_removed => 3, + :comments_added => 20, :comments_removed => 6, + :blanks_added => 30, :blanks_removed => 9) + list += delta + + assert_equal 1, list.locs.size + assert_equal 8, list.loc('c').code + assert_equal 16, list.loc('c').comments + assert_equal 24, list.loc('c').blanks + end + + def test_add_loc_delta_list + list = LocList.new + + c = LocDelta.new('c', :code_added => 10, :code_removed => 1, :comments_added => 20, :comments_removed => 2) + java = LocDelta.new('java', :code_added => 30, :code_removed => 3, :comments_added => 40, :comments_removed => 4) + + delta_list = LocDeltaList.new + c + java + + list += delta_list + + assert_equal 2, list.locs.size + + assert_equal 9, list.loc('c').code + assert_equal 18, list.loc('c').comments + + assert_equal 27, list.loc('java').code + assert_equal 36, list.loc('java').comments + end + def test_compact list = LocList.new c = Loc.new('c', :code => 1, :comments => 2, :blanks => 3) From 9f3a0e4b7be90d0a9d86f9362ea6b5fa692f8f74 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 19 Feb 2009 15:06:39 -0800 Subject: [PATCH 093/387] [NEW] Version 2.0.1 - Internal support for LOC delta between two source files --- Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 117c644..adf96d5 100644 --- a/Rakefile +++ b/Rakefile @@ -7,7 +7,7 @@ require 'rbconfig' include Config NAME = 'ohcount' -VERS = '2.0.0' +VERS = '2.0.1' EXT_DIR = "ext/ohcount_native" EXT_DL = "#{EXT_DIR}/ohcount_native.#{CONFIG['DLEXT']}" From e8c81e169f757d962edabcb596fe5a5e333dc1a7 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Sat, 21 Feb 2009 15:03:56 +0100 Subject: [PATCH 094/387] [FIX] license listing failed due to missing namespace --- bin/ohcount | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/ohcount b/bin/ohcount index 403a2ae..e5b6ff4 100755 --- a/bin/ohcount +++ b/bin/ohcount @@ -54,7 +54,7 @@ class OhcountCommandLine def licenses source_file_list.each_source_file do |s| next unless s.licenses.any? - symbols = s.licenses.collect { |l| LicenseSniffer::LicenseMap.instance.map[l].symbol }.join(",") + symbols = s.licenses.collect { |l| Ohcount::LicenseSniffer::LicenseMap.instance.map[l].symbol }.join(",") puts "#{symbols}\t#{s.filename}" end end From 04705507fe2118f37083bb9909a0e2f4d5fa8270 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Wed, 25 Feb 2009 14:17:05 -0800 Subject: [PATCH 095/387] [NEW] LocDeltaList + LocDeltaList => LocDeltaList --- lib/ohcount/loc_delta_list.rb | 9 +++++++++ test/unit/loc_delta_list_test.rb | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/lib/ohcount/loc_delta_list.rb b/lib/ohcount/loc_delta_list.rb index 225b82c..7516f44 100644 --- a/lib/ohcount/loc_delta_list.rb +++ b/lib/ohcount/loc_delta_list.rb @@ -19,6 +19,8 @@ def +(addend) case addend when LocDelta add_loc_delta(addend) + when LocDeltaList + add_loc_delta_list(addend) else raise ArgumentError.new end @@ -34,6 +36,13 @@ def add_loc_delta(addend) self end + def add_loc_delta_list(addend) + addend.loc_deltas.each do |loc_delta| + add_loc_delta(loc_delta) + end + self + end + def code_added @loc_deltas.inject(0) { |sum, delta| sum + delta.code_added } end diff --git a/test/unit/loc_delta_list_test.rb b/test/unit/loc_delta_list_test.rb index 10d1244..87dd1ca 100644 --- a/test/unit/loc_delta_list_test.rb +++ b/test/unit/loc_delta_list_test.rb @@ -80,6 +80,10 @@ def test_add_same_language_twice assert_equal 3030, list.blanks_removed end + def test_add_two_lists + assert (LocDeltaList.new + LocDeltaList.new).is_a?(LocDeltaList) + end + def test_net_total list = LocDeltaList.new From 376eb353ce14e7b5aa746afe3c35084a0e02a02f Mon Sep 17 00:00:00 2001 From: Jason Riedy Date: Mon, 2 Mar 2009 17:02:56 -0500 Subject: [PATCH 096/387] Differentiate between Matlab(TM) and GNU Octave in the detector. GNU Octave is a sufficiently different language that it's work checking directly. Also, GNU Octave files may not run in Matlab; GNU Octave extends the syntax. One caveat is that the detector does not detect use of GNU Octave's doubly quoted strings, "foo". Some files may be mis-identified if "foo" is the only Octave-ism. Signed-off-by: Jason Riedy --- lib/ohcount/detector.rb | 51 +++++++++++++++++++++++++++++------------- lib/ohcount/language.rb | 1 + test/detect_files/foo_octave.m | 3 +++ test/unit/detector_test.rb | 1 + 4 files changed, 40 insertions(+), 16 deletions(-) create mode 100644 test/detect_files/foo_octave.m diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index bdbcc03..bf00c64 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -6,11 +6,12 @@ module Ohcount #:nodoc: # # The hash EXTENSION_MAP maps a filename extension to the name of a parser. # - # If a filename extension is not enough to determine the correct parser (for - # instance, the *.m extension can indicate either a Matlab or Objective-C file), - # then the EXTENSION_MAP hash will contain a symbol identifying a Ruby method - # which will be invoked. This Ruby method can examine the file - # contents and return the name of the correct parser. + # If a filename extension is not enough to determine the correct parser + # (for instance, the *.m extension can indicate either a Matlab(TM), + # Octave, or Objective-C file), then the EXTENSION_MAP hash will contain + # a symbol identifying a Ruby method which will be invoked. This Ruby + # method can examine the file contents and return the name of the + # correct parser. # # Many source files do not have an extension. The method +disambiguate_nil+ # is called in these cases. The +file+ command line tool is used to determine @@ -189,7 +190,7 @@ def self.binary_filename?(filename) '.lua' => "lua", '.lsp' => "lisp", '.lisp' => "lisp", - '.m' => :matlab_or_objective_c, + '.m' => :matlab_octave_or_objective_c, '.mf' => 'metafont', '.mk' => 'make', '.ml' => "ocaml", @@ -273,30 +274,48 @@ def self.lines_matching(buffer, re) buffer.inject(0) { |total, line| line =~ re ? total+1 : total } end - # For *.m files, differentiates Matlab from Objective-C. + # For *.m files, differentiates between Matlab(TM), Octave, and Objective-C. # # This is done with a weighted heuristic that # scans the *.m file contents for keywords, # and also checks for the presence of matching *.h files. - def self.matlab_or_objective_c(source_file) + def self.matlab_octave_or_objective_c(source_file) buffer = source_file.contents - # if there are .h files in same directory, this probably isn't matlab + # if there are .h files in same directory and no C or C++ source files, + # this probably isn't Matlab(TM) or Octave. Both allow compiled extensions + # that often live in the same directory, so checking .h alone does not suffice. + has_headers = source_file.filenames.select { |a| a =~ /\.h$/ }.any? + has_c_cpp = !source_file.filenames.select { |a| a =~ /\.(c|cpp|C|c\+\+|cxx|cc)$/ }.any? h_headers = 0.0 - h_headers = -0.5 if source_file.filenames.select { |a| a =~ /\.h$/ }.any? + h_headers = -0.5 if has_headers && !has_c_cpp - # if the contents contain 'function (' on a single line - very likely to be matlab - # if the contents contain lines starting with '%', its probably matlab comments - matlab_signatures = /(^\s*function\s*)|(^\s*%)/ + # if the contents contain 'function (' on a single line - very likely to be Octave + # or Matlab(TM). + # if the contents contain lines starting with '%' or '#', they likely are comments + # in Octave or Matlab(TM) + matlab_signatures = /(^\s*function\s*)|(^\s*%)|(^\s*\#)/ matlab_sig_score = 0.1 * lines_matching(buffer, matlab_signatures) - # if the contents contains '//' or '/*', likely objective_c - objective_c_signatures = /(^\s*\/\/\s*)|(^\s*\/\*)|(^[+-])/ + # if the contents contains '//', '/*', '@interface', or '@implementation', + # likely objective_c + objective_c_signatures = /(^\s*\/\/\s*)|(^\s*\/\*)|(^[+-])|(@interface)|(@implementation)/ obj_c_sig_score = -0.1 * lines_matching(buffer, objective_c_signatures) matlab = h_headers + matlab_sig_score + obj_c_sig_score - matlab > 0 ? 'matlab' : 'objective_c' + if matlab > 0 + # Octave-specific keywords: endfunction, endwhile, end_try_catch, end_unwind_protect + # Also, # is only an Octave comment character. + oct_specific_sigs = /(\bend(function|while|_try_catch|unwind_protect))|(^\s*\#)/ + if lines_matching(buffer, oct_specific_sigs) > 0 + return 'octave' + else + return 'matlab' + end + else + return 'objective_c' + end end # For *.h files, differentiates C, C++ and Objective-C. diff --git a/lib/ohcount/language.rb b/lib/ohcount/language.rb index b914531..5f2643c 100644 --- a/lib/ohcount/language.rb +++ b/lib/ohcount/language.rb @@ -48,6 +48,7 @@ def lang_map 'metapost' => {:nice_name => 'MetaPost' , :category => 1}, 'mxml' => {:nice_name => 'Flex' , :category => 1}, 'nix' => {:nice_name => 'Nix' , :category => 0}, + 'octave' => {:nice_name => 'GNU Octave' , :category => 0}, 'objective_c' => {:nice_name => 'Objective C' , :category => 0}, 'objective_j' => {:nice_name => 'Objective-J' , :category => 0}, 'ocaml' => {:nice_name => 'Objective Caml' , :category => 0}, diff --git a/test/detect_files/foo_octave.m b/test/detect_files/foo_octave.m new file mode 100644 index 0000000..8e604e9 --- /dev/null +++ b/test/detect_files/foo_octave.m @@ -0,0 +1,3 @@ +function foo + ## a comment +endfunction diff --git a/test/unit/detector_test.rb b/test/unit/detector_test.rb index 036cd21..398ce4d 100644 --- a/test/unit/detector_test.rb +++ b/test/unit/detector_test.rb @@ -66,6 +66,7 @@ def test_detect_polyglot assert_equal "ruby", do_detect("foo.rb") assert_equal "make", do_detect("foo.mk") assert_equal "matlab", do_detect("foo_matlab.m", ["foo_matlab.m", "bar.m", "README"]) + assert_equal "octave", do_detect("foo_octave.m", ["foo_octave.m", "foo_matlab.m", "bar.m", "README"]) assert_equal "objective_c", do_detect("foo_objective_c.m", ["foo_objective_c.m", "bar.h", "README"]) assert_equal "objective_c", do_detect("foo_objective_c.h", ["foo_objective_c.h, different_than_foo.m"]) assert_equal "php", do_detect("upper_case_php") From 17538c7932151cd90dc804bdd126dc8a08e9a724 Mon Sep 17 00:00:00 2001 From: Jason Riedy Date: Mon, 2 Mar 2009 17:35:57 -0500 Subject: [PATCH 097/387] A few Matlab(TM) parser modifications. There is a very old style of commenting that hides the comment beyond the line continuation sequence '...'. Also, the next patch adds an GNU Octave-specific parser, so remove GNU Octave features. The double quotes are not detected by the detector, so keep those. Signed-off-by: Jason Riedy --- ext/ohcount_native/ragel_parsers/matlab.rl | 8 +++++--- test/expected_dir/matlab1.m | 2 ++ test/src_dir/matlab1.m | 2 ++ test/unit/parsers/matlab_test.rb | 8 ++++---- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/ext/ohcount_native/ragel_parsers/matlab.rl b/ext/ohcount_native/ragel_parsers/matlab.rl index 0b8e1bb..9c2cbaa 100644 --- a/ext/ohcount_native/ragel_parsers/matlab.rl +++ b/ext/ohcount_native/ragel_parsers/matlab.rl @@ -44,8 +44,8 @@ enum { } } - # note: the '#' comment is for GNU Octave - matlab_line_comment = ('%' [^{] @{ fhold; } | '#') @comment nonnewline*; + # Matlab(TM) comments also may begin with the line-continuing sequence ... + matlab_line_comment = (('%' | '...') [^{] @{ fhold; }) @comment nonnewline*; matlab_block_comment = '%{' @comment ( newline %{ entity = INTERNAL_NL; } %matlab_ccallback @@ -56,6 +56,8 @@ enum { )* :>> '%}'; matlab_comment = matlab_line_comment | matlab_block_comment; + # The detector is not smart enough to detect GNU Octave's double + # quotes around strings, so accept it here. matlab_sq_str = '\'' @code ([^\r\n\f'\\] | '\\' nonnewline)* '\''; matlab_dq_str = '"' @code ([^\r\n\f"\\] | '\\' nonnewline)* '"'; matlab_string = matlab_sq_str | matlab_dq_str; @@ -74,7 +76,7 @@ enum { callback(MATLAB_LANG, matlab_entities[entity], cint(ts), cint(te)); } - matlab_line_comment_entity = ('%' [^{] @{ fhold; } | '#') nonnewline*; + matlab_line_comment_entity = (('%' | '...') [^{] @{ fhold; }) nonnewline*; matlab_block_comment_entity = '%{' any* :>> '%}'; matlab_comment_entity = matlab_line_comment_entity | matlab_block_comment_entity; diff --git a/test/expected_dir/matlab1.m b/test/expected_dir/matlab1.m index 6499b80..9c20b77 100644 --- a/test/expected_dir/matlab1.m +++ b/test/expected_dir/matlab1.m @@ -52,3 +52,5 @@ matlab code plot([0:tmax],ProbExtinct) matlab comment % [T,true] = ode45(@logistic,[0,20],Nc,Options,r,K,theta); matlab comment % subplot(1,2,2) matlab comment % plot([1:tmax],P,'r.-',T,true,'g.-') +matlab blank +matlab comment ... This is a seriously old-school comment. \ No newline at end of file diff --git a/test/src_dir/matlab1.m b/test/src_dir/matlab1.m index dbb07b2..3e66995 100644 --- a/test/src_dir/matlab1.m +++ b/test/src_dir/matlab1.m @@ -52,3 +52,5 @@ % [T,true] = ode45(@logistic,[0,20],Nc,Options,r,K,theta); % subplot(1,2,2) % plot([1:tmax],P,'r.-',T,true,'g.-') + + ... This is a seriously old-school comment. \ No newline at end of file diff --git a/test/unit/parsers/matlab_test.rb b/test/unit/parsers/matlab_test.rb index dbbe9a0..7ff78fc 100644 --- a/test/unit/parsers/matlab_test.rb +++ b/test/unit/parsers/matlab_test.rb @@ -7,9 +7,9 @@ def test_line_comment_1 assert_equal lb, Ohcount::parse(" %comment", "matlab") end - def test_octave_syntax_comment - lb = [Ohcount::LanguageBreakdown.new("matlab", "", "#comment", 0)] - assert_equal lb, Ohcount::parse(" #comment", "matlab") + def test_ancient_syntax_comment + lb = [Ohcount::LanguageBreakdown.new("matlab", "", "... comment", 0)] + assert_equal lb, Ohcount::parse(" ... comment", "matlab") end def test_false_line_comment @@ -23,7 +23,7 @@ def test_comprehensive def test_comment_entities assert_equal('%comment', entities_array(" %comment", 'matlab', :comment).first) - assert_equal('#comment', entities_array(" #comment", 'matlab', :comment).first) + assert_equal('... comment', entities_array(" ... comment", 'matlab', :comment).first) assert_equal('%{comment%}', entities_array(" %{comment%}", 'matlab', :comment).first) end From 2977e8ce0020ed203567b5363b2c7d96296d7f54 Mon Sep 17 00:00:00 2001 From: Jason Riedy Date: Mon, 2 Mar 2009 17:36:40 -0500 Subject: [PATCH 098/387] PARSER_DOC should mention that ragel_parsers.c must be modified. Adding new parsers is not entirely automatic. Signed-off-by: Jason Riedy --- PARSER_DOC | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/PARSER_DOC b/PARSER_DOC index 510513c..94bf652 100644 --- a/PARSER_DOC +++ b/PARSER_DOC @@ -19,7 +19,10 @@ Writing a Parser: First create your parser in ext/ohcount_native/ragel_parsers/. Its name should be the language you are parsing with a '.rl' extension. You will not have to manually compile any parsers, as the Rakefile does this automatically - for you. Every parser must have the following at the top: + for you. However, you do need to add appropriate clauses manually to + ext/ohcount_native/ragel_parser.c to find your new parser. + + Every parser must have the following at the top: /************************* Required for every parser *************************/ #ifndef RAGEL_C_PARSER From f3fe4b5e041fa7107e7dfd7ee3b9267fdd6ff68a Mon Sep 17 00:00:00 2001 From: Jason Riedy Date: Mon, 2 Mar 2009 17:38:33 -0500 Subject: [PATCH 099/387] Add parsing support for GNU Octave. This likely should use the Matlab(TM) parser machine, but I'm not skilled enough with Ragel. This parser also allows Matlab(TM)'s block comments, although those are not currently supported by GNU Octave. It'd be nice to separate documentation comment blocks and test comment blocks, but not necessary yet. Signed-off-by: Jason Riedy --- ext/ohcount_native/ragel_parser.c | 2 + ext/ohcount_native/ragel_parsers/octave.rl | 120 ++++++++++++ test/expected_dir/octave1.m | 301 +++++++++++++++++++++++++++++ test/src_dir/octave1.m | 301 +++++++++++++++++++++++++++++ test/unit/parsers/octave_test.rb | 30 +++ 5 files changed, 754 insertions(+) create mode 100644 ext/ohcount_native/ragel_parsers/octave.rl create mode 100644 test/expected_dir/octave1.m create mode 100644 test/src_dir/octave1.m create mode 100644 test/unit/parsers/octave_test.rb diff --git a/ext/ohcount_native/ragel_parser.c b/ext/ohcount_native/ragel_parser.c index 5e8066a..42efe78 100644 --- a/ext/ohcount_native/ragel_parser.c +++ b/ext/ohcount_native/ragel_parser.c @@ -50,6 +50,7 @@ #include "ragel_parsers/objective_c.h" #include "ragel_parsers/objective_j.h" #include "ragel_parsers/ocaml.h" +#include "ragel_parsers/octave.h" #include "ragel_parsers/pascal.h" #include "ragel_parsers/perl.h" #include "ragel_parsers/phphtml.h" @@ -137,6 +138,7 @@ struct language languages[] = { { "objective_c", parse_objective_c }, { "objective_j", parse_objective_j }, { "ocaml", parse_ocaml }, + { "octave", parse_octave }, { "pascal", parse_pascal }, { "perl", parse_perl }, { "php", parse_phtml }, diff --git a/ext/ohcount_native/ragel_parsers/octave.rl b/ext/ohcount_native/ragel_parsers/octave.rl new file mode 100644 index 0000000..894b5d0 --- /dev/null +++ b/ext/ohcount_native/ragel_parsers/octave.rl @@ -0,0 +1,120 @@ +// octave.rl based on Mitchell Foral's matlab.rl, modified my Jason Riedy + +/************************* Required for every parser *************************/ +#ifndef RAGEL_OCTAVE_PARSER +#define RAGEL_OCTAVE_PARSER + +#include "ragel_parser_macros.h" + +// the name of the language +const char *OCTAVE_LANG = "octave"; + +// the languages entities +const char *octave_entities[] = { + "space", "comment", "string", "any", +}; + +// constants associated with the entities +enum { + OCTAVE_SPACE = 0, OCTAVE_COMMENT, OCTAVE_STRING, OCTAVE_ANY +}; + +/*****************************************************************************/ + +%%{ + machine octave; + write data; + include common "common.rl"; + + # Line counting machine + + action octave_ccallback { + switch(entity) { + case OCTAVE_SPACE: + ls + break; + case OCTAVE_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(OCTAVE_LANG) + break; + case NEWLINE: + std_newline(OCTAVE_LANG) + } + } + + # note: GNU Octave accepts % as well as #, but not '...' at the moment. We + # accept it anyways, as that may change. Also, GNU Octave does not currently + # support block comments but likely will someday. + octave_line_comment = (('%' | '...') [^{] @{ fhold; } | '#') @comment nonnewline*; + octave_block_comment = + '%{' @comment ( + newline %{ entity = INTERNAL_NL; } %octave_ccallback + | + ws + | + (nonnewline - ws) @code + )* :>> '%}'; + octave_comment = octave_line_comment | octave_block_comment; + + octave_sq_str = '\'' @code ([^\r\n\f'\\] | '\\' nonnewline)* '\''; + octave_dq_str = '"' @code ([^\r\n\f"\\] | '\\' nonnewline)* '"'; + octave_string = octave_sq_str | octave_dq_str; + + octave_line := |* + spaces ${ entity = OCTAVE_SPACE; } => octave_ccallback; + octave_comment; + octave_string; + newline ${ entity = NEWLINE; } => octave_ccallback; + ^space ${ entity = OCTAVE_ANY; } => octave_ccallback; + *|; + + # Entity machine + + action octave_ecallback { + callback(OCTAVE_LANG, octave_entities[entity], cint(ts), cint(te)); + } + + octave_line_comment_entity = (('%' | '...') [^{] @{ fhold; } | '#') nonnewline*; + octave_block_comment_entity = '%{' any* :>> '%}'; + octave_comment_entity = + octave_line_comment_entity | octave_block_comment_entity; + + octave_entity := |* + space+ ${ entity = OCTAVE_SPACE; } => octave_ecallback; + octave_comment_entity ${ entity = OCTAVE_COMMENT; } => octave_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with OCTAVE code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_octave(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int start, int end) + ) { + init + + %% write init; + cs = (count) ? octave_en_octave_line : octave_en_octave_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(OCTAVE_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/test/expected_dir/octave1.m b/test/expected_dir/octave1.m new file mode 100644 index 0000000..311ca33 --- /dev/null +++ b/test/expected_dir/octave1.m @@ -0,0 +1,301 @@ +octave comment ## Copyright (C) 2006, Regents of the University of California -*- mode: octave; -*- +octave comment ## +octave comment ## This program is free software distributed under the "modified" or +octave comment ## 3-clause BSD license appended to this file. +octave blank +octave code function varargout = toledolu(LU) +octave comment ## -*- texinfo -*- +octave comment ## @deftypefn{Function File} {[@var{L}, @var{U}, @var{P}]} = toledolu(@var{A}) +octave comment ## @deftypefnx{Function File} {[@var{L}, @var{U}]} = toledolu(@var{A}) +octave comment ## @deftypefnx{Function File} {@var{LUP}} = toledolu(@var{A}) +octave comment ## +octave comment ## Note: This returns a vector of indices for @var{P} and not a permutation +octave comment ## matrix. +octave comment ## +octave comment ## Factors @var{P}*@var{A}=@var{L}*@var{U} by Sivan Toledo's recursive factorization algorithm +octave comment ## with partial pivoting. While not as fast as the built-in LU, this +octave comment ## is significantly faster than the standard, unblocked algorithm +octave comment ## while remaining relatively easy to modify. +octave comment ## +octave comment ## See the help for lu for details about the other calling forms. +octave comment ## +octave comment ## For the algorithm, see +octave comment ## @itemize +octave comment ## @item +octave comment ## Toledo, Sivan. "Locality of reference in LU decomposition with +octave comment ## partial pivoting," SIAM J. of Matrix Analysis and Applications, +octave comment ## v18, n4, 1997. DOI: 10.1137/S0895479896297744 +octave comment ## @end itemize +octave comment ## +octave comment ## @seealso{lu} +octave comment ## +octave comment ## @end deftypefn +octave blank +octave comment ## Author: Jason Riedy +octave comment ## Keywords: linear-algebra, LU, factorization +octave comment ## Version: 0.2 +octave blank +octave comment ## This version isn't *quite* the same as Toledo's algorithm. I use a +octave comment ## doubling approach rather than using recursion. So non-power-of-2 +octave comment ## columns likely will be slightly different, but that shouldn't +octave comment ## affect the 'optimality' by more than a small constant factor. +octave blank +octave comment ## Also, I don't handle ncol > nrow optimally. The code factors the +octave comment ## first nrow columns and then updates the remaining ncol-nrow columns +octave comment ## with L. +octave blank +octave comment ## Might be worth eating the memory cost and tracking L separately. +octave comment ## The eye(n)+tril(LU,-1) could be expensive. +octave blank +octave code switch (nargout) +octave code case 0 +octave code return; +octave code case {1,2,3} +octave code otherwise +octave code usage ("[L,U,P] = lu(A), [P\\L, U] = lu(A), or (P\\L-I+U) = lu(A)"); +octave code endswitch +octave blank +octave code [nrow, ncol] = size(LU); +octave code nstep = min(nrow, ncol); +octave blank +octave code Pswap = zeros(nstep, 1); +octave blank +octave code for j=1:nstep, +octave code [pval, pind] = max(abs(LU(j:nrow, j))); +octave code pind = pind + j - 1; +octave code Pswap(j) = pind; +octave blank +octave code kahead = bitand(j, 1+bitcmp(j)); # last 1 bit in j +octave code kstart = j+1-kahead; +octave code kcols = min(kahead, nstep-j); +octave blank +octave code inds = kstart : j; +octave code Ucol = j+1 : j+kcols; +octave code Lrow = j+1 : nrow; +octave blank +octave comment ## permute just this column +octave code if (pind != j) +octave code tmp = LU(pind, j); +octave code LU(pind, j) = LU(j,j); +octave code LU(j,j) = tmp; +octave code endif +octave comment ## apply pending permutations to L +octave code n_to_piv = 1; +octave code ipivstart = j; +octave code jpivstart = j - n_to_piv; +octave code while (n_to_piv < kahead) +octave code pivcols = jpivstart : jpivstart+n_to_piv-1; +octave code for ipiv = ipivstart:j, +octave code pind = Pswap(ipiv); +octave code if (pind != ipiv) +octave code tmp = LU(pind, pivcols); +octave code LU(pind, pivcols) = LU(ipiv, pivcols); +octave code LU(ipiv, pivcols) = tmp; +octave code endif +octave code endfor +octave code ipivstart -= n_to_piv; +octave code n_to_piv *= 2; +octave code jpivstart -= n_to_piv; +octave code endwhile +octave blank +octave code if (LU(j,j) != 0.0 && !isnan(LU(j,j))), +octave code LU(j+1:nrow,j) /= LU(j,j); +octave code endif +octave blank +octave code if 0 == kcols, break; endif +octave blank +octave comment ## permute U to match perm already applied to L +octave code for k = inds, +octave code tmp = LU(Pswap(k), Ucol); +octave code LU(Pswap(k), Ucol) = LU(k, Ucol); +octave code LU(k, Ucol) = tmp; +octave code endfor +octave blank +octave code LU(inds, Ucol) = (eye(kahead) + tril(LU(inds, inds),-1)) \ LU(inds, Ucol); +octave code LU(Lrow, Ucol) -= LU(Lrow, inds) * LU(inds, Ucol); +octave code endfor +octave blank +octave comment ## handle pivot permutations in L out from the last step +octave code npived = bitand(nstep, 1+bitcmp(nstep)); +octave code j = nstep-npived; +octave code while (j > 0) +octave code n_to_piv = bitand(j, 1+bitcmp(j)); +octave blank +octave code pivcols = j-n_to_piv+1 : j; +octave code for ipiv = j+1:nstep, +octave code pind = Pswap(ipiv); +octave code if (pind != ipiv) +octave code tmp = LU(pind, pivcols); +octave code LU(pind, pivcols) = LU(ipiv, pivcols); +octave code LU(ipiv, pivcols) = tmp; +octave code endif +octave code endfor +octave blank +octave code j -= n_to_piv; +octave code endwhile +octave blank +octave code if (nrow < ncol), +octave code Ucol = nrow+1 : ncol; +octave code inds = 1:nrow; +octave code for k = inds, +octave code tmp = LU(Pswap(k), Ucol); +octave code LU(Pswap(k), Ucol) = LU(k, Ucol); +octave code LU(k, Ucol) = tmp; +octave code endfor +octave code LU(inds, Ucol) = (eye(nrow) + tril(LU(inds, inds),-1)) \ LU(inds, Ucol); +octave code endif +octave blank +octave code if (nargout == 1) +octave code varargout{1} = LU; +octave code return; +octave code endif +octave blank +octave code if nrow == ncol, +octave code L = eye(nrow) + tril(LU, -1); +octave code varargout{2} = triu(LU); +octave code elseif nrow < ncol, +octave code L = eye(nrow) + tril(LU, -1)(:,1:nrow); +octave code varargout{2} = triu(LU); +octave code else # nrow > ncol +octave code L = tril(LU, -1); +octave code for k=1:ncol, +octave code L(k,k) = 1; +octave code endfor +octave code varargout{2} = triu(LU)(1:ncol,:); +octave code endif +octave blank +octave code if (nargout == 2) +octave code for j = 1:nstep, +octave code pind = Pswap(j); +octave code tmp = L(pind,:); +octave code L(pind,:) = L(j,:); +octave code L(j,:) = tmp; +octave code endfor +octave code else # nargout == 3 +octave code P = 1:nrow; +octave code for j = 1:nstep, +octave code tmp = P(j); +octave code P(j) = P(Pswap(j)); +octave code P(Pswap(j)) = tmp; +octave code endfor +octave code varargout{3} = P; +octave code endif +octave code varargout{1} = L; +octave blank +octave code endfunction +octave blank +octave comment %!test +octave comment %! M = 15; +octave comment %! N = 15; +octave comment %! A = rand(M,N); +octave comment %! [L,U,P] = toledolu(A); +octave comment %! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) +octave blank +octave comment %!test +octave comment %! M = 16; +octave comment %! N = 16; +octave comment %! A = rand(M,N); +octave comment %! [L,U,P] = toledolu(A); +octave comment %! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) +octave blank +octave comment %!test +octave comment %! M = 17; +octave comment %! N = 17; +octave comment %! A = rand(M,N); +octave comment %! [L,U,P] = toledolu(A); +octave comment %! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) +octave blank +octave comment %!test +octave comment %! M = 8; +octave comment %! N = 17; +octave comment %! A = rand(M,N); +octave comment %! [L,U,P] = toledolu(A); +octave comment %! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) +octave blank +octave comment %!test +octave comment %! M = 8; +octave comment %! N = 15; +octave comment %! A = rand(M,N); +octave comment %! [L,U,P] = toledolu(A); +octave comment %! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) +octave blank +octave comment %!test +octave comment %! M = 7; +octave comment %! N = 17; +octave comment %! A = rand(M,N); +octave comment %! [L,U,P] = toledolu(A); +octave comment %! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) +octave blank +octave comment %!test +octave comment %! M = 7; +octave comment %! N = 15; +octave comment %! A = rand(M,N); +octave comment %! [L,U,P] = toledolu(A); +octave comment %! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) +octave blank +octave comment %!test +octave comment %! M = 17; +octave comment %! N = 8; +octave comment %! A = rand(M,N); +octave comment %! [L,U,P] = toledolu(A); +octave comment %! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) +octave blank +octave comment %!test +octave comment %! M = 15; +octave comment %! N = 8; +octave comment %! A = rand(M,N); +octave comment %! [L,U,P] = toledolu(A); +octave comment %! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) +octave blank +octave comment %!test +octave comment %! M = 17; +octave comment %! N = 7; +octave comment %! A = rand(M,N); +octave comment %! [L,U,P] = toledolu(A); +octave comment %! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) +octave blank +octave comment %!test +octave comment %! M = 15; +octave comment %! N = 7; +octave comment %! A = rand(M,N); +octave comment %! [L,U,P] = toledolu(A); +octave comment %! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) +octave blank +octave comment %!test +octave comment %! M = 31; +octave comment %! N = 17; +octave comment %! A = rand(M,N); +octave comment %! [L,U,P] = toledolu(A); +octave comment %! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) +octave blank +octave comment %!test +octave comment %! M = 11; +octave comment %! N = 29; +octave comment %! A = rand(M,N); +octave comment %! [L,U,P] = toledolu(A); +octave comment %! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) +octave blank +octave comment ## Copyright (c) 2006, Regents of the University of California +octave comment ## All rights reserved. +octave comment ## Redistribution and use in source and binary forms, with or without +octave comment ## modification, are permitted provided that the following conditions are met: +octave comment ## +octave comment ## * Redistributions of source code must retain the above copyright +octave comment ## notice, this list of conditions and the following disclaimer. +octave comment ## * Redistributions in binary form must reproduce the above copyright +octave comment ## notice, this list of conditions and the following disclaimer in the +octave comment ## documentation and/or other materials provided with the distribution. +octave comment ## * Neither the name of the University of California, Berkeley nor the +octave comment ## names of its contributors may be used to endorse or promote products +octave comment ## derived from this software without specific prior written permission. +octave comment ## +octave comment ## THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY +octave comment ## EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +octave comment ## WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +octave comment ## DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY +octave comment ## DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +octave comment ## (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +octave comment ## LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +octave comment ## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +octave comment ## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +octave comment ## SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/test/src_dir/octave1.m b/test/src_dir/octave1.m new file mode 100644 index 0000000..d72372d --- /dev/null +++ b/test/src_dir/octave1.m @@ -0,0 +1,301 @@ +## Copyright (C) 2006, Regents of the University of California -*- mode: octave; -*- +## +## This program is free software distributed under the "modified" or +## 3-clause BSD license appended to this file. + +function varargout = toledolu(LU) + ## -*- texinfo -*- + ## @deftypefn{Function File} {[@var{L}, @var{U}, @var{P}]} = toledolu(@var{A}) + ## @deftypefnx{Function File} {[@var{L}, @var{U}]} = toledolu(@var{A}) + ## @deftypefnx{Function File} {@var{LUP}} = toledolu(@var{A}) + ## + ## Note: This returns a vector of indices for @var{P} and not a permutation + ## matrix. + ## + ## Factors @var{P}*@var{A}=@var{L}*@var{U} by Sivan Toledo's recursive factorization algorithm + ## with partial pivoting. While not as fast as the built-in LU, this + ## is significantly faster than the standard, unblocked algorithm + ## while remaining relatively easy to modify. + ## + ## See the help for lu for details about the other calling forms. + ## + ## For the algorithm, see + ## @itemize + ## @item + ## Toledo, Sivan. "Locality of reference in LU decomposition with + ## partial pivoting," SIAM J. of Matrix Analysis and Applications, + ## v18, n4, 1997. DOI: 10.1137/S0895479896297744 + ## @end itemize + ## + ## @seealso{lu} + ## + ## @end deftypefn + + ## Author: Jason Riedy + ## Keywords: linear-algebra, LU, factorization + ## Version: 0.2 + + ## This version isn't *quite* the same as Toledo's algorithm. I use a + ## doubling approach rather than using recursion. So non-power-of-2 + ## columns likely will be slightly different, but that shouldn't + ## affect the 'optimality' by more than a small constant factor. + + ## Also, I don't handle ncol > nrow optimally. The code factors the + ## first nrow columns and then updates the remaining ncol-nrow columns + ## with L. + + ## Might be worth eating the memory cost and tracking L separately. + ## The eye(n)+tril(LU,-1) could be expensive. + + switch (nargout) + case 0 + return; + case {1,2,3} + otherwise + usage ("[L,U,P] = lu(A), [P\\L, U] = lu(A), or (P\\L-I+U) = lu(A)"); + endswitch + + [nrow, ncol] = size(LU); + nstep = min(nrow, ncol); + + Pswap = zeros(nstep, 1); + + for j=1:nstep, + [pval, pind] = max(abs(LU(j:nrow, j))); + pind = pind + j - 1; + Pswap(j) = pind; + + kahead = bitand(j, 1+bitcmp(j)); # last 1 bit in j + kstart = j+1-kahead; + kcols = min(kahead, nstep-j); + + inds = kstart : j; + Ucol = j+1 : j+kcols; + Lrow = j+1 : nrow; + + ## permute just this column + if (pind != j) + tmp = LU(pind, j); + LU(pind, j) = LU(j,j); + LU(j,j) = tmp; + endif + ## apply pending permutations to L + n_to_piv = 1; + ipivstart = j; + jpivstart = j - n_to_piv; + while (n_to_piv < kahead) + pivcols = jpivstart : jpivstart+n_to_piv-1; + for ipiv = ipivstart:j, + pind = Pswap(ipiv); + if (pind != ipiv) + tmp = LU(pind, pivcols); + LU(pind, pivcols) = LU(ipiv, pivcols); + LU(ipiv, pivcols) = tmp; + endif + endfor + ipivstart -= n_to_piv; + n_to_piv *= 2; + jpivstart -= n_to_piv; + endwhile + + if (LU(j,j) != 0.0 && !isnan(LU(j,j))), + LU(j+1:nrow,j) /= LU(j,j); + endif + + if 0 == kcols, break; endif + + ## permute U to match perm already applied to L + for k = inds, + tmp = LU(Pswap(k), Ucol); + LU(Pswap(k), Ucol) = LU(k, Ucol); + LU(k, Ucol) = tmp; + endfor + + LU(inds, Ucol) = (eye(kahead) + tril(LU(inds, inds),-1)) \ LU(inds, Ucol); + LU(Lrow, Ucol) -= LU(Lrow, inds) * LU(inds, Ucol); + endfor + + ## handle pivot permutations in L out from the last step + npived = bitand(nstep, 1+bitcmp(nstep)); + j = nstep-npived; + while (j > 0) + n_to_piv = bitand(j, 1+bitcmp(j)); + + pivcols = j-n_to_piv+1 : j; + for ipiv = j+1:nstep, + pind = Pswap(ipiv); + if (pind != ipiv) + tmp = LU(pind, pivcols); + LU(pind, pivcols) = LU(ipiv, pivcols); + LU(ipiv, pivcols) = tmp; + endif + endfor + + j -= n_to_piv; + endwhile + + if (nrow < ncol), + Ucol = nrow+1 : ncol; + inds = 1:nrow; + for k = inds, + tmp = LU(Pswap(k), Ucol); + LU(Pswap(k), Ucol) = LU(k, Ucol); + LU(k, Ucol) = tmp; + endfor + LU(inds, Ucol) = (eye(nrow) + tril(LU(inds, inds),-1)) \ LU(inds, Ucol); + endif + + if (nargout == 1) + varargout{1} = LU; + return; + endif + + if nrow == ncol, + L = eye(nrow) + tril(LU, -1); + varargout{2} = triu(LU); + elseif nrow < ncol, + L = eye(nrow) + tril(LU, -1)(:,1:nrow); + varargout{2} = triu(LU); + else # nrow > ncol + L = tril(LU, -1); + for k=1:ncol, + L(k,k) = 1; + endfor + varargout{2} = triu(LU)(1:ncol,:); + endif + + if (nargout == 2) + for j = 1:nstep, + pind = Pswap(j); + tmp = L(pind,:); + L(pind,:) = L(j,:); + L(j,:) = tmp; + endfor + else # nargout == 3 + P = 1:nrow; + for j = 1:nstep, + tmp = P(j); + P(j) = P(Pswap(j)); + P(Pswap(j)) = tmp; + endfor + varargout{3} = P; + endif + varargout{1} = L; + +endfunction + +%!test +%! M = 15; +%! N = 15; +%! A = rand(M,N); +%! [L,U,P] = toledolu(A); +%! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) + +%!test +%! M = 16; +%! N = 16; +%! A = rand(M,N); +%! [L,U,P] = toledolu(A); +%! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) + +%!test +%! M = 17; +%! N = 17; +%! A = rand(M,N); +%! [L,U,P] = toledolu(A); +%! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) + +%!test +%! M = 8; +%! N = 17; +%! A = rand(M,N); +%! [L,U,P] = toledolu(A); +%! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) + +%!test +%! M = 8; +%! N = 15; +%! A = rand(M,N); +%! [L,U,P] = toledolu(A); +%! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) + +%!test +%! M = 7; +%! N = 17; +%! A = rand(M,N); +%! [L,U,P] = toledolu(A); +%! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) + +%!test +%! M = 7; +%! N = 15; +%! A = rand(M,N); +%! [L,U,P] = toledolu(A); +%! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) + +%!test +%! M = 17; +%! N = 8; +%! A = rand(M,N); +%! [L,U,P] = toledolu(A); +%! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) + +%!test +%! M = 15; +%! N = 8; +%! A = rand(M,N); +%! [L,U,P] = toledolu(A); +%! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) + +%!test +%! M = 17; +%! N = 7; +%! A = rand(M,N); +%! [L,U,P] = toledolu(A); +%! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) + +%!test +%! M = 15; +%! N = 7; +%! A = rand(M,N); +%! [L,U,P] = toledolu(A); +%! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) + +%!test +%! M = 31; +%! N = 17; +%! A = rand(M,N); +%! [L,U,P] = toledolu(A); +%! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) + +%!test +%! M = 11; +%! N = 29; +%! A = rand(M,N); +%! [L,U,P] = toledolu(A); +%! assert(norm(L*U-A(P,:),inf), 0, M**2*N*eps) + +## Copyright (c) 2006, Regents of the University of California +## All rights reserved. +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are met: +## +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in the +## documentation and/or other materials provided with the distribution. +## * Neither the name of the University of California, Berkeley nor the +## names of its contributors may be used to endorse or promote products +## derived from this software without specific prior written permission. +## +## THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY +## EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +## WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +## DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY +## DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +## (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +## LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +## SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/test/unit/parsers/octave_test.rb b/test/unit/parsers/octave_test.rb new file mode 100644 index 0000000..98eb88d --- /dev/null +++ b/test/unit/parsers/octave_test.rb @@ -0,0 +1,30 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::OctaveTest < Ohcount::Test + + def test_line_comment_1 + lb = [Ohcount::LanguageBreakdown.new("octave", "", "%comment", 0)] + assert_equal lb, Ohcount::parse(" %comment", "octave") + end + + def test_octave_syntax_comment + lb = [Ohcount::LanguageBreakdown.new("octave", "", "# comment", 0)] + assert_equal lb, Ohcount::parse(" # comment", "octave") + end + + # Note: GNU Octave doesn't support block comments *yet*, but it might in the future. + def test_false_line_comment + lb = [Ohcount::LanguageBreakdown.new("octave", "%{block%} code", "", 0)] + assert_equal lb, Ohcount::parse(" %{block%} code", "octave") + end + + def test_comprehensive + verify_parse("octave1.m", 'octave') + end + + def test_comment_entities + assert_equal('%comment', entities_array(" %comment", 'octave', :comment).first) + assert_equal('# comment', entities_array(" # comment", 'octave', :comment).first) + end + +end From af7e88da75fe4e96e118afe62b4e82bede4da549 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Mon, 9 Mar 2009 10:33:17 -0700 Subject: [PATCH 100/387] [FIX] License detection didn't work in cases with trailing whitespace --- lib/ohcount/source_file.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb index 892f523..ee31399 100644 --- a/lib/ohcount/source_file.rb +++ b/lib/ohcount/source_file.rb @@ -94,8 +94,8 @@ def licenses comments = '' parse do |language, semantic, line| next unless semantic == :comment - # Strip leading punctuation. - comments << ' ' + $1 if line =~ /^[\s[:punct:]]*(.*?)$/ + # Strip leading and trailing punctuation/whitespace. + comments << ' ' + $1 if line =~ /^[\s[:punct:]]*(.*?)\s*$/ end LicenseSniffer.sniff(comments) end From e0bed1080fbcbbf917a6961af753a0c6ea90222f Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 10 Mar 2009 09:41:48 -0700 Subject: [PATCH 101/387] [FIX] Removing trailing whitespace through regex is far too slow. Use strip(). --- lib/ohcount/source_file.rb | 2 +- test/expected_licenses/avr-drv | 1 + test/src_licenses/avr-drv.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 test/expected_licenses/avr-drv create mode 100644 test/src_licenses/avr-drv.c diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb index ee31399..98e7424 100644 --- a/lib/ohcount/source_file.rb +++ b/lib/ohcount/source_file.rb @@ -95,7 +95,7 @@ def licenses parse do |language, semantic, line| next unless semantic == :comment # Strip leading and trailing punctuation/whitespace. - comments << ' ' + $1 if line =~ /^[\s[:punct:]]*(.*?)\s*$/ + comments << ' ' + $1 if line.strip =~ /^[\s[:punct:]]*(.*?)$/ end LicenseSniffer.sniff(comments) end diff --git a/test/expected_licenses/avr-drv b/test/expected_licenses/avr-drv new file mode 100644 index 0000000..a7fe7c3 --- /dev/null +++ b/test/expected_licenses/avr-drv @@ -0,0 +1 @@ +bsd_2clause_ish diff --git a/test/src_licenses/avr-drv.c b/test/src_licenses/avr-drv.c new file mode 100644 index 0000000..ae96bcd --- /dev/null +++ b/test/src_licenses/avr-drv.c @@ -0,0 +1,30 @@ +/* Copyright (c) 2008, Sample Code + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided + that the following conditions are met: + + 1.Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + 2.Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3.Neither the name of the AVR-DRV nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ From 5986f69fe507d989c4a2ec42340e4eba38839875 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 10 Mar 2009 12:11:23 -0700 Subject: [PATCH 102/387] [FIX] BSD license detection was completely fubar. Many fixes: 1. If we match both 2-clause and 3-clause, choose 3-clause. Previously, we were doing the reverse. 2. Test case test/src_licenses/bsd_2clause_ish_t2 was obviously a 3-clause license but the test was checking for 2-clause. This has been changed. Note that the online descriptions of the various BSD licenses on Ohloh have been edited by the community and now do not match the definitions used in Ohcount. This will have to be fixed. --- lib/licenses/license_map.rb | 4 ++-- test/expected_licenses/avr-drv | 2 +- test/expected_licenses/bsd_2clause_ish_t2 | 1 - test/expected_licenses/bsd_ish_t3 | 1 + test/src_licenses/{bsd_2clause_ish_t2.c => bsd_ish_t3.c} | 0 5 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 test/expected_licenses/bsd_2clause_ish_t2 create mode 100644 test/expected_licenses/bsd_ish_t3 rename test/src_licenses/{bsd_2clause_ish_t2.c => bsd_ish_t3.c} (100%) diff --git a/lib/licenses/license_map.rb b/lib/licenses/license_map.rb index e8bf5a8..7aa465a 100644 --- a/lib/licenses/license_map.rb +++ b/lib/licenses/license_map.rb @@ -344,7 +344,7 @@ def initialize() "", "BSD-ish (2 clause) License", /Copyright\s.{1,60}All rights reserved.{1,40}Redistribution and use in source and binary forms, with or without.{0,20}modification, are permitted provided that the following conditions.{0,20}\sare met.{0,20}\s{1,20}.{0,20}Redistributions of source code must retain the above copyright\s+.*notice, this list of conditions and the following disclaimer.\s+.*Redistributions in binary form must reproduce the above copyright\s+.*notice, this list of conditions and the following disclaimer in the\s+.*documentation and\/or other materials provided with the distribution\.\s+.*HOWEVER CAUSED AND ON ANY.*THEORY OF LIABILITY, WHETHER IN CONTRACT/m, - /(The Regents of the University of California)|(may not be used to endorse or promote\s+.*products\s+.*prior\s+.*written\s+.*permission\.)/m), + /(The Regents of the University of California)|(used to endorse or promote\s+.*products\s+.*prior\s+.*written\s+.*permission\.)/m), ].each do |l| @licenses << l @map[l.symbol] = l @@ -353,7 +353,7 @@ def initialize() @license_overrides = { :gpl => [ :gpl3, :gpl3_or_later], :gpl3 => [ :gpl3_or_later], - :bsd_ish => [:bsd_2clause_ish] + :bsd_2clause_ish => [:bsd_ish] } end end diff --git a/test/expected_licenses/avr-drv b/test/expected_licenses/avr-drv index a7fe7c3..2758ff2 100644 --- a/test/expected_licenses/avr-drv +++ b/test/expected_licenses/avr-drv @@ -1 +1 @@ -bsd_2clause_ish +bsd_ish diff --git a/test/expected_licenses/bsd_2clause_ish_t2 b/test/expected_licenses/bsd_2clause_ish_t2 deleted file mode 100644 index a7fe7c3..0000000 --- a/test/expected_licenses/bsd_2clause_ish_t2 +++ /dev/null @@ -1 +0,0 @@ -bsd_2clause_ish diff --git a/test/expected_licenses/bsd_ish_t3 b/test/expected_licenses/bsd_ish_t3 new file mode 100644 index 0000000..2758ff2 --- /dev/null +++ b/test/expected_licenses/bsd_ish_t3 @@ -0,0 +1 @@ +bsd_ish diff --git a/test/src_licenses/bsd_2clause_ish_t2.c b/test/src_licenses/bsd_ish_t3.c similarity index 100% rename from test/src_licenses/bsd_2clause_ish_t2.c rename to test/src_licenses/bsd_ish_t3.c From 7b2c11f42aab976a63fc7036fe1d78f64f371ae8 Mon Sep 17 00:00:00 2001 From: Olly Betts Date: Mon, 9 Mar 2009 17:18:56 +1300 Subject: [PATCH 103/387] Check contents of .st files actually looks like Smalltalk. --- lib/ohcount/detector.rb | 13 ++++++++++- test/detect_files/english.st | 6 +++++ test/detect_files/example.st | 45 +++++++++++++++++++++++++++++++++++++ test/expected_dir/english.st | 0 test/src_dir/english.st | 6 +++++ test/unit/detector_test.rb | 1 + test/unit/parsers/smalltalk_test.rb | 1 + 7 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 test/detect_files/english.st create mode 100644 test/expected_dir/english.st create mode 100644 test/src_dir/english.st diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index bf00c64..c407da5 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -231,7 +231,7 @@ def self.binary_filename?(filename) '.ss' => "scheme", '.sh' => "shell", '.sql' => "sql", - '.st' => "smalltalk", + '.st' => :disambiguate_smalltalk, '.str' => "stratego", '.tcl' => "tcl", '.tpl' => "html", @@ -661,5 +661,16 @@ def self.disambiguate_using_emacs_mode(source_file) nil end end + + # Check if a file looks like it's really smalltalk rather than just + # happening to have a ".st" extension. + def self.disambiguate_smalltalk(source_file) + buffer = source_file.contents + if buffer =~ /:=/ && buffer =~ /: *\[/ && buffer =~ /\]\./ + return 'smalltalk' + end + nil + end + end end diff --git a/test/detect_files/english.st b/test/detect_files/english.st new file mode 100644 index 0000000..205b8a0 --- /dev/null +++ b/test/detect_files/english.st @@ -0,0 +1,6 @@ +a +aa +aardvark +abacus +apple +zebra diff --git a/test/detect_files/example.st b/test/detect_files/example.st index e69de29..ff78098 100644 --- a/test/detect_files/example.st +++ b/test/detect_files/example.st @@ -0,0 +1,45 @@ +"====================================================================== +| +| Benchmark for floats +| +| + ======================================================================" + + +"====================================================================== +| +| Copyright (C) 2003 Free Software Foundation. +| Written by Paolo Bonzini +| +| This file is part of GNU Smalltalk. +| +| GNU Smalltalk is free software; you can redistribute it and/or modify it +| under the terms of the GNU General Public License as published by the Free +| Software Foundation; either version 2, or (at your option) any later version. +| +| GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT +| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +| FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +| details. +| +| You should have received a copy of the GNU General Public License along with +| GNU Smalltalk; see the file COPYING. If not, write to the Free Software +| Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +| + ======================================================================" + +Smalltalk at: #Last put: 42! + +!Number methodsFor: 'testing'! + +nextRandom + Last := Last * 3877 + 29573 rem: 139968. + ^self * Last asFloatD / 139968d! ! + +| n | +n := Smalltalk arguments isEmpty + ifTrue: [ 1000 ] + ifFalse: [ 1 max: Smalltalk arguments first asInteger ]. + +n timesRepeat: [ 100d nextRandom ]. +((100d nextRandom + 0.5d-9) printString copyFrom: 1 to: 11) displayNl! diff --git a/test/expected_dir/english.st b/test/expected_dir/english.st new file mode 100644 index 0000000..e69de29 diff --git a/test/src_dir/english.st b/test/src_dir/english.st new file mode 100644 index 0000000..205b8a0 --- /dev/null +++ b/test/src_dir/english.st @@ -0,0 +1,6 @@ +a +aa +aardvark +abacus +apple +zebra diff --git a/test/unit/detector_test.rb b/test/unit/detector_test.rb index 398ce4d..7093b9f 100644 --- a/test/unit/detector_test.rb +++ b/test/unit/detector_test.rb @@ -45,6 +45,7 @@ def do_detect_with_siblings(filename) def test_smalltalk assert_equal "smalltalk", do_detect("example.st") + assert_equal nil, do_detect("english.st") end def test_matlab_or_objective_c diff --git a/test/unit/parsers/smalltalk_test.rb b/test/unit/parsers/smalltalk_test.rb index 13e624a..280b77f 100644 --- a/test/unit/parsers/smalltalk_test.rb +++ b/test/unit/parsers/smalltalk_test.rb @@ -9,6 +9,7 @@ def test_comment def test_comprehensive verify_parse("smalltalk1.st") + verify_parse("english.st") end def test_comment_entities From 86383f96a21ac7ca93ddac1a48937d4931ab53ff Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Fri, 20 Mar 2009 08:31:15 -0700 Subject: [PATCH 104/387] [FIX] Alternate diff implementation for very large files. Our in-memory split and call to LCS::Diff could take literally days to complete for large files. We now put the buffers into temp files, and shell out to the console to let the `diff` program handle it whenever a buffer exceeds 100K. --- lib/ohcount/source_file.rb | 30 ++++++++++++++++++++++++++++-- test/unit/source_file_test.rb | 26 +++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb index 98e7424..12e3c7e 100644 --- a/lib/ohcount/source_file.rb +++ b/lib/ohcount/source_file.rb @@ -26,7 +26,7 @@ class SourceFile # # If you do not pass the :contents, then SourceFile will first check # :file_location and then :filename (in that order) to get the file contents. - def initialize(filename, options = {}) + def initialize(filename='', options = {}) @filename = filename @filenames = options[:filenames] || [] @contents = options[:contents] @@ -115,7 +115,7 @@ def languages def loc_list language_breakdowns.inject(LocList.new) do |sum, lb| sum + Loc.new(lb.name, - :code => lb.code_count, + :code => lb.code_count, :comments => lb.comment_count, :blanks => lb.blanks, :filecount => 1) @@ -158,11 +158,37 @@ def calc_loc_delta(language, after) # calc_diff("a\nb", "a\nc") # [1,1] -> one added, one deleted # def calc_diff(a,b) + # Based on buffer size, choose a diff implementation. + # The break-even point seems to be around 100K on my develpment machine. + if a.length > 100000 or b.length > 100000 + calc_large_diff(a,b) + else + calc_small_diff(a,b) + end + end + + # As above, for small files + def calc_small_diff(a,b) LCSDiff::Diff::LCS.diff(a.split("\n"),b.split("\n")).flatten.inject([0,0]) do |m, change| m[0] += 1 if change.adding? m[1] += 1 if change.deleting? m end end + + # As above, but for very large files + def calc_large_diff(a,b) + added = removed = 0 + ScratchDir.new do |dir| + File.open(dir + "/a", "w") { |f| f.write a } + File.open(dir + "/b", "w") { |f| f.write b } + cmd = "diff -d --normal --suppress-common-lines --new-file '#{dir}/a' '#{dir}/b' | grep '^>' | wc -l" + added = `#{cmd}`.to_i + cmd = "diff -d --normal --suppress-common-lines --new-file '#{dir}/a' '#{dir}/b' | grep '^<' | wc -l" + removed = `#{cmd}`.to_i + end + [added, removed] + end + end end diff --git a/test/unit/source_file_test.rb b/test/unit/source_file_test.rb index d6e330e..24d227d 100644 --- a/test/unit/source_file_test.rb +++ b/test/unit/source_file_test.rb @@ -94,5 +94,29 @@ def test_calc_diff_longer ) assert_equal LocDelta.new('c', :code_added => 2, :code_removed => 2), old.diff(new).loc_delta('c') end -end + def test_calc_small_diff + assert_equal [0,0], SourceFile.new.calc_small_diff("","") + assert_equal [0,0], SourceFile.new.calc_small_diff("a","a") + assert_equal [0,0], SourceFile.new.calc_small_diff("a\n","a\n") + assert_equal [1,0], SourceFile.new.calc_small_diff("","a\n") + assert_equal [0,1], SourceFile.new.calc_small_diff("a\n","") + assert_equal [1,1], SourceFile.new.calc_small_diff("a\n","b\n") + assert_equal [1,1], SourceFile.new.calc_small_diff("a\nb\nc\n","a\nc\nd\n") + end + + def test_calc_large_diff + assert_equal [0,0], SourceFile.new.calc_large_diff("","") + assert_equal [0,0], SourceFile.new.calc_large_diff("a","a") + assert_equal [0,0], SourceFile.new.calc_large_diff("a\n","a\n") + assert_equal [1,0], SourceFile.new.calc_large_diff("","a\n") + assert_equal [0,1], SourceFile.new.calc_large_diff("a\n","") + assert_equal [1,1], SourceFile.new.calc_large_diff("a\n","b\n") + assert_equal [1,1], SourceFile.new.calc_large_diff("a\nb\nc\n","a\nc\nd\n") + end + + def test_calc_diff + assert_equal [1,0], SourceFile.new.calc_diff("Hello, World!\n" * 10, "Hello, World!\n" * 11) + assert_equal [1,0], SourceFile.new.calc_diff("Hello, World!\n" * 10000, "Hello, World!\n" * 10001) + end +end From 0793209295c8f8645b64e9216e356c075331b7fb Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Sat, 21 Mar 2009 16:10:20 +0100 Subject: [PATCH 105/387] [FIX] Parse diff output ourselves instead of computing it twice --- lib/ohcount/source_file.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb index 12e3c7e..a54ebd3 100644 --- a/lib/ohcount/source_file.rb +++ b/lib/ohcount/source_file.rb @@ -182,10 +182,12 @@ def calc_large_diff(a,b) ScratchDir.new do |dir| File.open(dir + "/a", "w") { |f| f.write a } File.open(dir + "/b", "w") { |f| f.write b } - cmd = "diff -d --normal --suppress-common-lines --new-file '#{dir}/a' '#{dir}/b' | grep '^>' | wc -l" - added = `#{cmd}`.to_i - cmd = "diff -d --normal --suppress-common-lines --new-file '#{dir}/a' '#{dir}/b' | grep '^<' | wc -l" - removed = `#{cmd}`.to_i + IO.popen("diff -d --normal --suppress-common-lines --new-file '#{dir}/a' '#{dir}/b'") do |f| + f.each do |line| + added += 1 if line =~ /^>/ + removed += 1 if line =~ /^ Date: Thu, 26 Mar 2009 16:39:38 -0700 Subject: [PATCH 106/387] [NEW] New platforms for detecting various Java application servers --- lib/gestalt/platform.rb | 1 + lib/gestalt/platforms.rb | 46 +++++++++++++++++++++++++++++++++- lib/gestalt/rules/java_package_rule.rb | 27 ++++++++++++++++++++ lib/gestalt/rules/logical_rule.rb | 4 +++ lib/gestalt/tools.rb | 4 +-- 5 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 lib/gestalt/rules/java_package_rule.rb diff --git a/lib/gestalt/platform.rb b/lib/gestalt/platform.rb index 940e0fe..33d821c 100644 --- a/lib/gestalt/platform.rb +++ b/lib/gestalt/platform.rb @@ -10,6 +10,7 @@ require 'lib/gestalt/rules/c_keyword_rule' require 'lib/gestalt/rules/platform_rule' require 'lib/gestalt/rules/java_import_rule' +require 'lib/gestalt/rules/java_package_rule' module Ohcount module Gestalt diff --git a/lib/gestalt/platforms.rb b/lib/gestalt/platforms.rb index 9bf0250..5ba4f32 100644 --- a/lib/gestalt/platforms.rb +++ b/lib/gestalt/platforms.rb @@ -182,13 +182,57 @@ class Drupal < Platform ) end - class MSDos < Platform + class MSDOS < Platform c_keywords '__MSDOS__', 'MSDOS', :min => 2 end class EclipsePlatform < Platform java_import 'org.eclipse.' end + + class ApacheCommons < Platform + java_import 'org.apache.commons' + end + + class ApacheTomcat < Platform + java_import 'org.apache.tomcat' + end + + class ApacheGeronimo < Platform + java_import 'org.apache.geronimo' + end + + class ApacheMaven < Platform + java_import 'org.apache.maven' + filenames 'pom.xml' + end + + class JBoss < Platform + java_import 'org.jboss.' + end + + class GlassFish < Platform + _or( + java_import('org.glassfish.'), + java_package('org.glassfish.') + ) + end + + class NetBeans < Platform + java_import 'org.netbeans.' + end + + class SunEnterprise < Platform + _or( + java_import('com.sun.enterprise'), + java_package('com.sun.enterprise') + ) + end + + class GoogleWebToolkit < Platform + java_import 'com.google.gwt.' + end + end end diff --git a/lib/gestalt/rules/java_package_rule.rb b/lib/gestalt/rules/java_package_rule.rb new file mode 100644 index 0000000..2713685 --- /dev/null +++ b/lib/gestalt/rules/java_package_rule.rb @@ -0,0 +1,27 @@ +module Ohcount + module Gestalt + # Triggers if the code implements a java package matching the given regex + class JavaPackageRule < FileRule + attr_reader :packages + + def initialize(*args) + options = args.pop if args.last.is_a?(Hash) + @packages = args + super(options) + end + + def trigger_file?(source_file) + return false unless source_file.polyglot == 'java' + regexp.match(source_file.language_breakdown('java').code) + end + + def regexp + @regexp ||= begin + packages_term = "(" + packages.join("|") + ")" + Regexp.new("package\s+#{ packages_term }") + end + end + end + end +end + diff --git a/lib/gestalt/rules/logical_rule.rb b/lib/gestalt/rules/logical_rule.rb index af1ba8f..1c0adc7 100644 --- a/lib/gestalt/rules/logical_rule.rb +++ b/lib/gestalt/rules/logical_rule.rb @@ -52,6 +52,10 @@ def java_import(*args) new_rule JavaImportRule, *args end + def java_package(*args) + new_rule JavaPackageRule, *args + end + def method_missing(m,*args) if /(.*)_keywords$/ =~ m.to_s language = $1 diff --git a/lib/gestalt/tools.rb b/lib/gestalt/tools.rb index e1073d2..d9db316 100644 --- a/lib/gestalt/tools.rb +++ b/lib/gestalt/tools.rb @@ -6,11 +6,11 @@ class VisualStudio < Tool filenames '\.(sln|vcproj|vsproj|csproj|vbproj|vbp)$' end - class Eclipse < Tool + class EclipseIDE < Tool filenames '\.(project|classpath)$' end - class NetBeans < Tool + class NetBeansIDE < Tool filenames '\bnbplatform\b' filenames '\.nbm$' end From 69f0c95cd02ddba4cbd19493494c602234396a9c Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 7 Apr 2009 20:11:11 +0200 Subject: [PATCH 107/387] Manage Scilab language --- ext/ohcount_native/ragel_parser.c | 2 + ext/ohcount_native/ragel_parsers/scilab.rl | 107 +++++++++++++++++++++++++++++ lib/ohcount/detector.rb | 2 + test/detect_files/foo.sci | 33 +++++++++ test/expected_dir/scilab.sci | 35 ++++++++++ test/src_dir/scilab.sci | 35 ++++++++++ test/unit/parsers/scilab_test.rb | 18 +++++ 7 files changed, 232 insertions(+) create mode 100644 ext/ohcount_native/ragel_parsers/scilab.rl create mode 100644 test/detect_files/foo.sci create mode 100644 test/expected_dir/scilab.sci create mode 100644 test/src_dir/scilab.sci create mode 100644 test/unit/parsers/scilab_test.rb diff --git a/ext/ohcount_native/ragel_parser.c b/ext/ohcount_native/ragel_parser.c index 42efe78..e6060a9 100644 --- a/ext/ohcount_native/ragel_parser.c +++ b/ext/ohcount_native/ragel_parser.c @@ -61,6 +61,7 @@ #include "ragel_parsers/ruby.h" #include "ragel_parsers/rhtml.h" #include "ragel_parsers/scala.h" +#include "ragel_parsers/scilab.h" #include "ragel_parsers/shell.h" #include "ragel_parsers/smalltalk.h" #include "ragel_parsers/stratego.h" @@ -149,6 +150,7 @@ struct language languages[] = { { "rhtml", parse_rhtml }, { "ruby", parse_ruby }, { "scala", parse_scala }, + { "scilab", parse_scilab }, { "scheme", parse_scheme }, { "shell", parse_shell }, { "smalltalk", parse_smalltalk }, diff --git a/ext/ohcount_native/ragel_parsers/scilab.rl b/ext/ohcount_native/ragel_parsers/scilab.rl new file mode 100644 index 0000000..915c693 --- /dev/null +++ b/ext/ohcount_native/ragel_parsers/scilab.rl @@ -0,0 +1,107 @@ +// scilab.rl written by Sylvestre Ledru based on matlab Mitchell Foral. mitchellcaladbolgnet. + +/************************* Required for every parser *************************/ +#ifndef RAGEL_SCILAB_PARSER +#define RAGEL_SCILAB_PARSER + +#include "ragel_parser_macros.h" + +// the name of the language +const char *SCILAB_LANG = "scilab"; + +// the languages entities +const char *scilab_entities[] = { + "space", "comment", "string", "any", +}; + +// constants associated with the entities +enum { + SCILAB_SPACE = 0, SCILAB_COMMENT, SCILAB_STRING, SCILAB_ANY +}; + +/*****************************************************************************/ + +%%{ + machine scilab; + write data; + include common "common.rl"; + + # Line counting machine + + action scilab_ccallback { + switch(entity) { + case SCILAB_SPACE: + ls + break; + case SCILAB_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(SCILAB_LANG) + break; + case NEWLINE: + std_newline(SCILAB_LANG) + } + } + + scilab_comment = ('//') @comment nonnewline*; + + # The detector is not smart enough to detect GNU Octave's double + # quotes around strings, so accept it here. + scilab_sq_str = '\'' @code ([^\r\n\f'\\] | '\\' nonnewline)* '\''; + scilab_dq_str = '"' @code ([^\r\n\f"\\] | '\\' nonnewline)* '"'; + scilab_string = scilab_sq_str | scilab_dq_str; + + scilab_line := |* + spaces ${ entity = SCILAB_SPACE; } => scilab_ccallback; + scilab_comment; + scilab_string; + newline ${ entity = NEWLINE; } => scilab_ccallback; + ^space ${ entity = SCILAB_ANY; } => scilab_ccallback; + *|; + + # Entity machine + + action scilab_ecallback { + callback(SCILAB_LANG, scilab_entities[entity], cint(ts), cint(te)); + } + + scilab_comment_entity = ('//') @comment nonnewline*; + + scilab_entity := |* + space+ ${ entity = SCILAB_SPACE; } => scilab_ecallback; + scilab_comment_entity ${ entity = SCILAB_COMMENT; } => scilab_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with SCILAB code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_scilab(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int start, int end) + ) { + init + + %% write init; + cs = (count) ? scilab_en_scilab_line : scilab_en_scilab_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(SCILAB_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index c407da5..553f740 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -225,6 +225,8 @@ def self.binary_filename?(filename) '.s' => "assembler", '.sc' => "scheme", '.scala' => "scala", + '.sci' => "scilab", + '.sce' => "scilab", '.scm' => "scheme", '.sps' => "scheme", '.sls' => "scheme", diff --git a/test/detect_files/foo.sci b/test/detect_files/foo.sci new file mode 100644 index 0000000..fe531bf --- /dev/null +++ b/test/detect_files/foo.sci @@ -0,0 +1,33 @@ +// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab +// Copyright (C) INRIA - Farid BELAHCENE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt + +function y=factorial(n) + + // This function returns the factorial n. If n is a vector, matrix or hypermatrix it returns the element wise factorial + // Input : n, a scalar/vector/matrix/hypermat of positives integers. + // Output : y, a scalar/vector/matrix/hypermat + + rhs = argn(2); + + if rhs <> 1 then + error(msprintf(gettext("%s: Wrong number of input argument(s): %d expected.\n"),"factorial",1)); + end + + if (type(n) <> 1 & (typeof(n)<>"hypermat" | type(n.entries)<>1)) | (~isempty(n) & (or((n-floor(n)<>0)) | or(n<0))) then + error(msprintf(gettext("%s: Wrong value for input argument #%d: Scalar/vector/matrix/hypermatrix of positive integers expected.\n"),"factorial",1)); + elseif isempty(n) + y=n + return + else + n(n==0)=1 + ntemp=cumprod(1:max(n)) + y=matrix(ntemp(n(:)),size(n)) + end + +endfunction diff --git a/test/expected_dir/scilab.sci b/test/expected_dir/scilab.sci new file mode 100644 index 0000000..16fb951 --- /dev/null +++ b/test/expected_dir/scilab.sci @@ -0,0 +1,35 @@ +scilab comment // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab +scilab comment // Copyright (C) INRIA - Serge STEER +scilab comment // +scilab comment // This file must be used under the terms of the CeCILL. +scilab comment // This source file is licensed as described in the file COPYING, which +scilab comment // you should have received as part of this distribution. The terms +scilab comment // are also available at +scilab comment // http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +scilab blank +scilab code function I=sub2ind(dims,varargin) +scilab comment //sub2ind is used to determine the equivalent single index +scilab comment //corresponding to a given set of subscript values. +scilab blank +scilab comment //I = sub2ind(dims,i1,i2,..) returns the linear index equivalent to the +scilab comment //row, column, ... subscripts in the arrays i1,i2,.. for an matrix of +scilab comment //size dims. +scilab blank +scilab comment //I = sub2ind(dims,Mi) returns the linear index +scilab comment //equivalent to the n subscripts in the columns of the matrix Mi for a matrix +scilab comment //of size dims. +scilab blank +scilab code d=[1;cumprod(matrix(dims(1:$-1),-1,1))] +scilab code for i=1:size(varargin) +scilab code if varargin(i)==[] then I=[],return,end +scilab code end +scilab blank +scilab code if size(varargin)==1 then //subindices are the columns of the argument +scilab code I=(varargin(1)-1)*d+1 +scilab code else //subindices are given as separated arguments +scilab code I=1 +scilab code for i=1:size(varargin) +scilab code I=I+(varargin(i)-1)*d(i) +scilab code end +scilab code end +scilab code endfunction diff --git a/test/src_dir/scilab.sci b/test/src_dir/scilab.sci new file mode 100644 index 0000000..a01e1a6 --- /dev/null +++ b/test/src_dir/scilab.sci @@ -0,0 +1,35 @@ +// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab +// Copyright (C) INRIA - Serge STEER +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt + +function I=sub2ind(dims,varargin) +//sub2ind is used to determine the equivalent single index +//corresponding to a given set of subscript values. + +//I = sub2ind(dims,i1,i2,..) returns the linear index equivalent to the +//row, column, ... subscripts in the arrays i1,i2,.. for an matrix of +//size dims. + +//I = sub2ind(dims,Mi) returns the linear index +//equivalent to the n subscripts in the columns of the matrix Mi for a matrix +//of size dims. + + d=[1;cumprod(matrix(dims(1:$-1),-1,1))] + for i=1:size(varargin) + if varargin(i)==[] then I=[],return,end + end + + if size(varargin)==1 then //subindices are the columns of the argument + I=(varargin(1)-1)*d+1 + else //subindices are given as separated arguments + I=1 + for i=1:size(varargin) + I=I+(varargin(i)-1)*d(i) + end + end +endfunction diff --git a/test/unit/parsers/scilab_test.rb b/test/unit/parsers/scilab_test.rb new file mode 100644 index 0000000..3920cae --- /dev/null +++ b/test/unit/parsers/scilab_test.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::ScilabTest < Ohcount::Test + + def test_line_comment_1 + lb = [Ohcount::LanguageBreakdown.new("scilab", "", "//comment", 0)] + assert_equal lb, Ohcount::parse(" //comment", "scilab") + end + + def test_comprehensive + verify_parse("scilab.sci", 'scilab') + end + + def test_comment_entities + assert_equal('//comment', entities_array(" //comment", 'scilab', :comment).first) + end + +end From 0c537057d3d231f9329f1c7f6ed871635f642bf2 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 7 Apr 2009 22:16:15 +0200 Subject: [PATCH 108/387] Scilab added --- lib/ohcount/language.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ohcount/language.rb b/lib/ohcount/language.rb index 5f2643c..4f9b501 100644 --- a/lib/ohcount/language.rb +++ b/lib/ohcount/language.rb @@ -62,6 +62,7 @@ def lang_map 'ruby' => {:nice_name => 'Ruby' , :category => 0}, 'scheme' => {:nice_name => 'Scheme' , :category => 0}, 'scala' => {:nice_name => 'Scala' , :category => 0}, + 'scilab' => {:nice_name => 'Scilab' , :category => 0}, 'shell' => {:nice_name => 'shell script' , :category => 0}, 'smalltalk' => {:nice_name => 'Smalltalk' , :category => 0}, 'stratego' => {:nice_name => 'Stratego' , :category => 0}, From f79aed335f0a7ee9b9d54319db04dfff89d61781 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 7 Apr 2009 20:11:29 +0200 Subject: [PATCH 109/387] Handle cecill licenses --- lib/licenses/license_map.rb | 15 +++++++++++++++ test/src_licenses/cecill-b.c | 1 + test/src_licenses/cecill-c.c | 1 + test/src_licenses/cecill.c | 1 + 4 files changed, 18 insertions(+) create mode 100644 test/src_licenses/cecill-b.c create mode 100644 test/src_licenses/cecill-c.c create mode 100644 test/src_licenses/cecill.c diff --git a/lib/licenses/license_map.rb b/lib/licenses/license_map.rb index 7aa465a..e5c9c22 100644 --- a/lib/licenses/license_map.rb +++ b/lib/licenses/license_map.rb @@ -58,6 +58,21 @@ def initialize() "New BSD license", /(\bbsd\s*license\b)|(The Regents of the University of California)/i ), + SoftwareLicense.new(:cecill, + "http://www.cecill.info/licences/Licence_CeCILL_V2-en.html", + "CeCILL license", + /\bcecill\b/i ), + + SoftwareLicense.new(:cecill_b, + "http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html", + "CeCILL-B license", + /\bcecill-b\b/i ), + + SoftwareLicense.new(:cecill_c, + "http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html", + "CeCILL-C license", + /\bcecill-c\b/i ), + SoftwareLicense.new(:computer_associates_trusted, "http://www.opensource.org/licenses/ca-tosl1.1.php", "Computer Associates Trusted Open Source License 1.1", diff --git a/test/src_licenses/cecill-b.c b/test/src_licenses/cecill-b.c new file mode 100644 index 0000000..b22dfe6 --- /dev/null +++ b/test/src_licenses/cecill-b.c @@ -0,0 +1 @@ +// terms of the CeCILL-B diff --git a/test/src_licenses/cecill-c.c b/test/src_licenses/cecill-c.c new file mode 100644 index 0000000..7388236 --- /dev/null +++ b/test/src_licenses/cecill-c.c @@ -0,0 +1 @@ +// terms of the CeCILL-C diff --git a/test/src_licenses/cecill.c b/test/src_licenses/cecill.c new file mode 100644 index 0000000..959651d --- /dev/null +++ b/test/src_licenses/cecill.c @@ -0,0 +1 @@ +// terms of the CeCILL From b6c617146c77704a155eeba3ca8efb8d57162e18 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 7 Apr 2009 20:15:55 +0200 Subject: [PATCH 110/387] Test for cecill license --- test/expected_licenses/cecill | 1 + test/expected_licenses/cecill-b | 1 + test/expected_licenses/cecill-c | 1 + 3 files changed, 3 insertions(+) create mode 100644 test/expected_licenses/cecill create mode 100644 test/expected_licenses/cecill-b create mode 100644 test/expected_licenses/cecill-c diff --git a/test/expected_licenses/cecill b/test/expected_licenses/cecill new file mode 100644 index 0000000..1e5183e --- /dev/null +++ b/test/expected_licenses/cecill @@ -0,0 +1 @@ +cecill diff --git a/test/expected_licenses/cecill-b b/test/expected_licenses/cecill-b new file mode 100644 index 0000000..3621136 --- /dev/null +++ b/test/expected_licenses/cecill-b @@ -0,0 +1 @@ +cecill_b diff --git a/test/expected_licenses/cecill-c b/test/expected_licenses/cecill-c new file mode 100644 index 0000000..a380ed5 --- /dev/null +++ b/test/expected_licenses/cecill-c @@ -0,0 +1 @@ +cecill_c From 3bdcfbd4106ef8ce1ec2845e8ab4578c73c975ab Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Mon, 13 Apr 2009 17:32:02 -0700 Subject: [PATCH 111/387] [FIX] Names of some platforms and tools have changed --- test/unit/gestalt/platform_test.rb | 2 +- test/unit/gestalt/tool_test.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb index 9f2c875..41cf6c0 100644 --- a/test/unit/gestalt/platform_test.rb +++ b/test/unit/gestalt/platform_test.rb @@ -98,7 +98,7 @@ def test_kde end def test_msdos - assert_platform('msdos', MSDos) + assert_platform('msdos', MSDOS) end def test_gtk diff --git a/test/unit/gestalt/tool_test.rb b/test/unit/gestalt/tool_test.rb index 2abc941..7753a83 100644 --- a/test/unit/gestalt/tool_test.rb +++ b/test/unit/gestalt/tool_test.rb @@ -10,11 +10,11 @@ def test_vs_1 end def test_eclipse - assert_tool('eclipse', Eclipse) + assert_tool('eclipse', EclipseIDE) end def test_netbeans - assert_tool('netbeans', NetBeans) + assert_tool('netbeans', NetBeansIDE) end protected From 3cb0553a9fd55efda0638834a7ccb9f740af6184 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 14 Apr 2009 11:30:13 -0700 Subject: [PATCH 112/387] [FIX] Cleanup the progress reporting for bin/ohcount -g --- bin/ohcount | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/bin/ohcount b/bin/ohcount index e5b6ff4..ee1e54a 100755 --- a/bin/ohcount +++ b/bin/ohcount @@ -60,6 +60,7 @@ class OhcountCommandLine end def analyze_with_progress(what) + STDOUT.write "Examining #{source_file_list.size} file(s)" count = 0 source_file_list.analyze(what) do |s| if count % 100 == 0 @@ -186,17 +187,7 @@ HELP printf(" %s\n", file) end - def memoryleak - puts "Parsing one file repeatedly. Watch your RAM vanish...." - s = Ohcount::SourceCode.new(files.first, :filenames => files) - while true - s.parse {} - end - end - def summary - STDOUT.write "Examining #{source_file_list.size} file(s)" - analyze_with_progress(:*) puts From 2ff6d93e7116e6020a2c32a3049074ab4261facb Mon Sep 17 00:00:00 2001 From: Tyson Key Date: Thu, 16 Apr 2009 19:07:16 +0100 Subject: [PATCH 113/387] Update license_map.rb to add i9 License --- lib/licenses/ohcount-license_map.rb.diff | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 lib/licenses/ohcount-license_map.rb.diff diff --git a/lib/licenses/ohcount-license_map.rb.diff b/lib/licenses/ohcount-license_map.rb.diff new file mode 100644 index 0000000..8bcd98d --- /dev/null +++ b/lib/licenses/ohcount-license_map.rb.diff @@ -0,0 +1,15 @@ +--- license_map.rb 2008-09-09 18:11:02.000000000 +0100 ++++ license_map-i9.rb 2009-04-16 15:05:46.000000000 +0100 +@@ -143,6 +143,11 @@ + "Historical Permission Notice and Disclaimer", + /\bhistorical\s*permission\s*notice\s*and\s*disclaimer\b/i ), + ++ SoftwareLicense.new(:i9_license, ++ "http://i9os.googlecode.com/svn/trunk/Documentation/Licenses/i9_License", ++ "i9 License", ++ /\bi9\s*\s*license\b/i ), ++ + SoftwareLicense.new(:ibm_public, + "http://www.opensource.org/licenses/ibmpl.php", + "IBM Public License", + From 631bbd0790820945769a32a4bd89f7b7c4fa0162 Mon Sep 17 00:00:00 2001 From: Tyson Key Date: Thu, 16 Apr 2009 19:11:30 +0100 Subject: [PATCH 114/387] Add a sample file containing the i9 License header --- test/src_licenses/i9_license.sh | 43 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100755 test/src_licenses/i9_license.sh diff --git a/test/src_licenses/i9_license.sh b/test/src_licenses/i9_license.sh new file mode 100755 index 0000000..7780903 --- /dev/null +++ b/test/src_licenses/i9_license.sh @@ -0,0 +1,43 @@ +# +# +# Copyright (C) 2008, 2009 i9 Project Contributors(1) +# All Rights Reserved. +# +# You may only modify and redistribute this under the terms of any of the +# following licenses(2): i9 License, MIT License +# +# +# (1) i9 Project Contributors are listed in the AUTHORS file and at +# http://i9os.googlecode.com/svn/trunk/Documentation/AUTHORS - please extend this file, +# not this notice. +# (2) Reproduced in the files in /Documentation/Licenses, and at: +# http://i9os.googlecode.com/svn/trunk/Documentation/Licenses +# +# As per the above licenses, removal of this notice is prohibited. +# +# ------------------------------------------------------------------------- +# + +cd Utilities +make -C ../BuildMk clean + +make -C ../Microkernel/user/serv/sigma0 clean + +make -C ../Microkernel/user/lib clean + +make -C ../Microkernel/user/serv/kickstart clean + +make -C ../Microkernel/user/apps/l4test clean + +cd ../Microkernel/user && make clean + +cd ../BuildMk && make clean +cd ../BuildL4UL && make clean + +cd ../Personalities/GenodeKit/build.pistachio_x86 && make clean + +cd .. + +rm *~ Documentation/*~ Documentation/*/*~ */*~ */*/~ + + From a7e8810774852d2be44cd313d4d7492e4bbdc1c1 Mon Sep 17 00:00:00 2001 From: Tyson Key Date: Thu, 16 Apr 2009 19:15:12 +0100 Subject: [PATCH 115/387] Sync the tree. Hopefully adding the i9 License changes works this time. --- lib/licenses/license_map.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/licenses/license_map.rb b/lib/licenses/license_map.rb index e5c9c22..d081206 100644 --- a/lib/licenses/license_map.rb +++ b/lib/licenses/license_map.rb @@ -164,6 +164,11 @@ def initialize() "Historical Permission Notice and Disclaimer", /\bhistorical\s*permission\s*notice\s*and\s*disclaimer\b/i ), + SoftwareLicense.new(:i9_license, + "http://i9os.googlecode.com/svn/trunk/Documentation/Licenses/i9_License", + "i9 License", + /\bi9\s*\s*license\b/i ), + SoftwareLicense.new(:ibm_public, "http://www.opensource.org/licenses/ibmpl.php", "IBM Public License", From ae1b6b1fddd66cf015454d922df48c7c4f5dddba Mon Sep 17 00:00:00 2001 From: Tyson Key Date: Thu, 16 Apr 2009 19:40:09 +0100 Subject: [PATCH 116/387] Really, really add the test cases this time. I hate Git. :( --- test/expected_licenses/i9_license_t1 | 1 + test/expected_licenses/i9_license_t2 | 1 + .../{i9_license.sh => i9_license_t1.sh} | 0 test/src_licenses/i9_license_t2.sh | 43 ++++++++++++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 test/expected_licenses/i9_license_t1 create mode 100644 test/expected_licenses/i9_license_t2 rename test/src_licenses/{i9_license.sh => i9_license_t1.sh} (100%) create mode 100755 test/src_licenses/i9_license_t2.sh diff --git a/test/expected_licenses/i9_license_t1 b/test/expected_licenses/i9_license_t1 new file mode 100644 index 0000000..740b253 --- /dev/null +++ b/test/expected_licenses/i9_license_t1 @@ -0,0 +1 @@ +i9_license mit diff --git a/test/expected_licenses/i9_license_t2 b/test/expected_licenses/i9_license_t2 new file mode 100644 index 0000000..7fa8801 --- /dev/null +++ b/test/expected_licenses/i9_license_t2 @@ -0,0 +1 @@ +i9_license diff --git a/test/src_licenses/i9_license.sh b/test/src_licenses/i9_license_t1.sh similarity index 100% rename from test/src_licenses/i9_license.sh rename to test/src_licenses/i9_license_t1.sh diff --git a/test/src_licenses/i9_license_t2.sh b/test/src_licenses/i9_license_t2.sh new file mode 100755 index 0000000..31e720f --- /dev/null +++ b/test/src_licenses/i9_license_t2.sh @@ -0,0 +1,43 @@ +# +# +# Copyright (C) 2008, 2009 i9 Project Contributors(1) +# All Rights Reserved. +# +# You may only modify and redistribute this under the terms of any of the +# following licenses(2): i9 License +# +# +# (1) i9 Project Contributors are listed in the AUTHORS file and at +# http://i9os.googlecode.com/svn/trunk/Documentation/AUTHORS - please extend this file, +# not this notice. +# (2) Reproduced in the files in /Documentation/Licenses, and at: +# http://i9os.googlecode.com/svn/trunk/Documentation/Licenses +# +# As per the above licenses, removal of this notice is prohibited. +# +# ------------------------------------------------------------------------- +# + +cd Utilities +make -C ../BuildMk clean + +make -C ../Microkernel/user/serv/sigma0 clean + +make -C ../Microkernel/user/lib clean + +make -C ../Microkernel/user/serv/kickstart clean + +make -C ../Microkernel/user/apps/l4test clean + +cd ../Microkernel/user && make clean + +cd ../BuildMk && make clean +cd ../BuildL4UL && make clean + +cd ../Personalities/GenodeKit/build.pistachio_x86 && make clean + +cd .. + +rm *~ Documentation/*~ Documentation/*/*~ */*~ */*/~ + + From 194065bf7a8a791cf3dd994b16585f2829b73f18 Mon Sep 17 00:00:00 2001 From: jason Date: Thu, 7 May 2009 14:23:20 -0700 Subject: [PATCH 117/387] [CHANGE] Gestalt redesign. --- bin/ohcount | 33 +++- lib/gestalt/base.rb | 32 ++++ lib/gestalt/definition.rb | 72 +++++++++ lib/gestalt/definitions.rb | 207 ++++++++++++++++++++++++++ lib/gestalt/gestalt_engine.rb | 129 ++++++++++++++++ lib/gestalt/gestalt_facts.rb | 82 ++++++++++ lib/gestalt/platform.rb | 1 - lib/gestalt/platforms.rb | 46 +----- lib/gestalt/rules/and_rule.rb | 7 +- lib/gestalt/rules/c_header_rule.rb | 14 +- lib/gestalt/rules/c_keyword_rule.rb | 12 +- lib/gestalt/rules/file_rule.rb | 31 ++-- lib/gestalt/rules/filename_rule.rb | 4 +- lib/gestalt/rules/find_filenames_rule.rb | 33 ++++ lib/gestalt/rules/find_java_imports_rule.rb | 47 ++++++ lib/gestalt/rules/gestalt_rule.rb | 22 +++ lib/gestalt/rules/java_import_rule.rb | 24 +-- lib/gestalt/rules/java_package_rule.rb | 27 ---- lib/gestalt/rules/keyword_rule.rb | 6 +- lib/gestalt/rules/language_rule.rb | 8 +- lib/gestalt/rules/logical_rule.rb | 58 +++++--- lib/gestalt/rules/or_rule.rb | 7 +- lib/gestalt/rules/platform_rule.rb | 18 --- lib/gestalt/rules/rule.rb | 8 +- lib/gestalt/tools.rb | 4 +- lib/gestalt/trigger.rb | 13 ++ lib/ohcount.rb | 10 +- lib/ohcount/gestalt_facts.rb | 6 +- lib/ohcount/source_file.rb | 43 ++++++ lib/ohcount/source_file_list.rb | 14 +- test/gestalt_files/eclipse_platform/main.java | 2 - test/unit/gestalt/definitions_test.rb | 205 +++++++++++++++++++++++++ test/unit/gestalt/file_rule_test.rb | 80 +++++----- test/unit/gestalt/filename_rule_test.rb | 18 +++ test/unit/gestalt/keyword_rule_test.rb | 19 +++ test/unit/gestalt/platform_test.rb | 123 --------------- test/unit/gestalt/tool_test.rb | 32 ---- test/unit/source_file_list_test.rb | 11 -- test/unit/source_file_test.rb | 1 + 39 files changed, 1129 insertions(+), 380 deletions(-) create mode 100644 lib/gestalt/base.rb create mode 100644 lib/gestalt/definition.rb create mode 100644 lib/gestalt/definitions.rb create mode 100644 lib/gestalt/gestalt_engine.rb create mode 100644 lib/gestalt/gestalt_facts.rb create mode 100644 lib/gestalt/rules/find_filenames_rule.rb create mode 100644 lib/gestalt/rules/find_java_imports_rule.rb create mode 100644 lib/gestalt/rules/gestalt_rule.rb delete mode 100644 lib/gestalt/rules/java_package_rule.rb delete mode 100644 lib/gestalt/rules/platform_rule.rb create mode 100644 lib/gestalt/trigger.rb create mode 100644 test/unit/gestalt/definitions_test.rb create mode 100644 test/unit/gestalt/filename_rule_test.rb create mode 100644 test/unit/gestalt/keyword_rule_test.rb delete mode 100644 test/unit/gestalt/platform_test.rb delete mode 100644 test/unit/gestalt/tool_test.rb diff --git a/bin/ohcount b/bin/ohcount index ee1e54a..b196970 100755 --- a/bin/ohcount +++ b/bin/ohcount @@ -60,7 +60,6 @@ class OhcountCommandLine end def analyze_with_progress(what) - STDOUT.write "Examining #{source_file_list.size} file(s)" count = 0 source_file_list.analyze(what) do |s| if count % 100 == 0 @@ -73,13 +72,23 @@ class OhcountCommandLine end def write_gestalt - platforms = source_file_list.gestalt_facts.platforms - platforms = platforms.any? ? platforms.collect { |p| p.to_s.split('::').last }.join(", ") : 'None' - puts "Platforms detected: #{ platforms }" + typed_gestalts = {} + source_file_list.gestalts.each do |gestalt| + typed_gestalts[gestalt.type] ||= [] + typed_gestalts[gestalt.type] << gestalt.name + end + + puts '- Gestalts -------------------------------------------------------------------' + + typed_gestalts.each do |k,v| + names = v.join(", ") - tools = source_file_list.gestalt_facts.tools - tools = tools.any? ? tools.collect { |p| p.to_s.split('::').last }.join(", ") : 'None' - puts "Tools detected: #{ tools }" + if names.size > 120 + names = "[#{ v.size } found] #{names[0..120]}..." + end + + puts k.to_s.upcase + ": " + names + end end # Gestalt @@ -187,7 +196,17 @@ HELP printf(" %s\n", file) end + def memoryleak + puts "Parsing one file repeatedly. Watch your RAM vanish...." + s = Ohcount::SourceCode.new(files.first, :filenames => files) + while true + s.parse {} + end + end + def summary + STDOUT.write "Examining #{source_file_list.size} file(s)" + analyze_with_progress(:*) puts diff --git a/lib/gestalt/base.rb b/lib/gestalt/base.rb new file mode 100644 index 0000000..a08e1bf --- /dev/null +++ b/lib/gestalt/base.rb @@ -0,0 +1,32 @@ +module Ohcount + module Gestalt + + class Base + attr_reader :type, :name, :count + + def initialize(type, name, count = 1) + @type = type + @name = name + @count = count + end + + def ==(other) + other.type.to_s == self.type.to_s && + other.name == self.name && + other.count == self.count + end + + def <=>(other) + me = self.type.to_s + self.name.to_s + self.count.to_s + you = other.type.to_s + other.name.to_s + other.count.to_s + me <=> you + end + + # will return an array of detected gestalts from a source_file_list + def self.find_gestalts(source_file_list) + GestaltEngine.new.process(source_file_list).gestalts + end + + end + end +end diff --git a/lib/gestalt/definition.rb b/lib/gestalt/definition.rb new file mode 100644 index 0000000..68bbed0 --- /dev/null +++ b/lib/gestalt/definition.rb @@ -0,0 +1,72 @@ +require 'lib/gestalt/rules/rule' +require 'lib/gestalt/rules/logical_rule' +require 'lib/gestalt/rules/or_rule' +require 'lib/gestalt/rules/and_rule' +require 'lib/gestalt/rules/language_rule' +require 'lib/gestalt/rules/file_rule' +require 'lib/gestalt/rules/filename_rule' +require 'lib/gestalt/rules/find_filenames_rule' +require 'lib/gestalt/rules/c_header_rule' +require 'lib/gestalt/rules/keyword_rule' +require 'lib/gestalt/rules/c_keyword_rule' +require 'lib/gestalt/rules/gestalt_rule' +require 'lib/gestalt/rules/java_import_rule' +require 'lib/gestalt/rules/find_java_imports_rule' + +module Ohcount + module Gestalt + + class Definition + attr_reader :type, :fixed_name + + def initialize(type, fixed_name = nil, options = {}, &block) + @type = type + @fixed_name = fixed_name + if options[:rule] + @top_level_or = options[:rule] + else + @top_level_or = OrRule.new(&block) + end + end + + def gestalts(gestalt_engine) + @top_level_or.triggers(gestalt_engine).map do |trigger| + Gestalt::Base.new(type, trigger.name || self.fixed_name, trigger.count) + end + end + + def top_level_or + @top_level_or ||= OrRule.new + end + + def self.add_definition(definition) + @definitions ||= [] + @definitions << definition + end + + def self.all_definitions + @definitions || [] + end + + def clone + rule = top_level_or.clone + Definition.new(type,fixed_name,:rule => rule) + end + end + + + # DSL language to allow people to define gestalt definitions like this:\ + # + # define_xxx 'Foobar' do + # filenames 'foobar' + # end + # + def self.method_missing(method, *args, &block) + if method.to_s =~ /define_(.*)$/ + Definition.add_definition(Definition.new($1.intern,*args,&block)) + else + super + end + end + end +end diff --git a/lib/gestalt/definitions.rb b/lib/gestalt/definitions.rb new file mode 100644 index 0000000..2d306e5 --- /dev/null +++ b/lib/gestalt/definitions.rb @@ -0,0 +1,207 @@ +module Ohcount + module Gestalt + + + ############################# Platforms ############################# + # # + # Platforms is used in the most general sense of the word. We don't # + # discriminate between OS-platforms and a lightweight framework - # + # any type of dependency is fair game. # + # # + # What guides what we add here is mostly for internal Ohloh # + # purposes. # + # # + ##################################################################### + + define_platform 'POSIX' do + # gnu_lib && generic + c_headers 'pthread.h', 'xstrtol.h', 'xreadlink.h', 'fatal-signal.h', 'diacrit.h', 'syslog.h', 'sys/stat.h' + + # autoconf means m4 (unix macro processor) + language :autoconf + end + + define_platform 'Win32' do + c_headers 'windows.h' + c_keywords 'WM_PAINT', 'ReleaseDC', 'WndProc', :min => 2 + end + + define_platform 'WPF' do + filenames '\.xaml$' + end + + define_platform 'Dot_NET' do + language :csharp, :min_percent => 10 + end + + define_platform 'VisualBasic' do + language :visualbasic, :min_percent => 5 + end + + define_platform 'ASP_NET' do + filenames('\.(aspx|ascx|ashx|asax|axd)$') + end + + define_platform 'Ruby' do + language :ruby, :min_percent => 15 + end + + define_platform 'Rails' do + _and do + gestalt(:platform, 'Ruby') + ruby_keywords("RAILS_ROOT") + end + end + + define_platform 'Java' do + language :java, :min_percent => 15 + end + + define_platform 'Javascript' do + language :javascript, :min_percent => 20 + end + + define_platform 'JQuery' do + filenames 'jquery-\d.\d.\d.min.js' + end + + define_platform 'SpringFramework' do + _and do + gestalt(:platform,'Java') + filenames('spring\.jar$') + end + end + + define_platform 'XWindows' do + c_headers 'Xlib.h', 'X11\/xpm.h', 'X11/Xlib.h' + end + + define_platform 'Mac' do + # apple events + c_keywords 'AppleEvent', 'AEBuildAppleEvent' + + # plist is a mac thing, right? + filenames '\.plist' + end + + define_platform 'PHP' do + language :php, :min_percent => 15 + end + + define_platform 'WxWidgets' do + c_headers 'wx/window.h' + end + + define_platform 'ZendFramework' do + _and do + gestalt(:platform, 'PHP') + php_keywords('Zend_Controller_Action') + end + end + + define_platform 'Symfony' do + _and do + gestalt(:platform, 'PHP') + php_keywords('sfCore', 'sfConfig') + end + end + + define_platform 'Pear' do + _and do + gestalt(:platform, 'PHP') + _or do + filenames('\bpackage\.xml(\.tpl)?$') + xml_keywords('pear.php.net/dtd/package-2.0') + end + end + end + + define_platform 'Moodle' do + _and do + gestalt(:platform, 'PHP') + php_keywords("moodle") + end + end + + define_platform 'SQL' do + language :sql + end + + define_platform 'MySQL' do + php_keywords('mysql_connect') + end + + define_platform 'PostgreSQL' do + php_keywords('pg_connect') + end + + define_platform 'Python' do + language :python, :min_percent => 15 + end + + define_platform 'CakePHP' do + _and do + gestalt(:platform, 'PHP') + php_keywords('CAKE_CORE_INCLUDE_PATH') + end + end + + define_platform 'KDE' do + c_headers 'KDEInit.h', 'kdeversion.h' + end + + define_platform 'GTK' do + c_keywords 'gtk_init', 'gtk_main', 'gtk_window_new', 'GtkWidget' + end + + define_platform 'Drupal' do + _and do + gestalt(:platform, 'PHP') + _or do + php_keywords('drupal_set_message') + php_keywords('drupal_render') + php_keywords('Drupal', :min => 3) + end + end + end + + define_platform 'MSDos' do + c_keywords '__MSDOS__', 'MSDOS', :min => 2 + end + + define_platform 'EclipsePlatform' do + java_import /org\.eclipse\./ + end + + + ############################### Tools ############################### + + define_tool 'VisualStudio' do + filenames '\.(sln|vcproj|vsproj|csproj|vbproj|vbp)$' + end + + define_tool 'Eclipse' do + filenames '\.(project|classpath)$' + end + + define_tool 'NetBeans' do + filenames '\bnbplatform\b' + filenames '\.nbm$' + end + + + ########################## Java Jars ############################### + + define_java_jar do + find_filenames /([^\\^\/]*\.(jar|JAR))/, :name_from_match => 1 + end + + + ######################## Java Imports ############################## + + define_java_import do + find_java_imports + end + + end +end diff --git a/lib/gestalt/gestalt_engine.rb b/lib/gestalt/gestalt_engine.rb new file mode 100644 index 0000000..6ec1b45 --- /dev/null +++ b/lib/gestalt/gestalt_engine.rb @@ -0,0 +1,129 @@ +module Ohcount + module Gestalt + + # smells is a general class that aggregates facts required to deduce + # gestalts + class GestaltEngine + attr_reader :gestalts + + def initialize + @language_facts = LanguageFacts.new + @gestalts = [] + @source_file_rules = [] + @definitions = Definition.all_definitions.map do |d| + new_definition = d.clone + new_definition.top_level_or.each_rule do |r| + @source_file_rules << r if r.is_a?(FileRule) + end + new_definition + end + end + + def process_source_file(source_file) + @source_file_rules.each do |r| + r.process_source_file(source_file) + end + @language_facts.process_source_file(source_file) + end + + def process_source_files(source_file_list) + source_file_list.each_source_file do |source_file| + process_source_file source_file + end + self + end + + def process(what) + if what.is_a?(SourceFile) + process_source_file(what) + elsif what.is_a?(SourceFileList) + process_source_file_list(what) + else + raise ArgumentError.new + end + end + + def calc_gestalts(definitions = nil) + # since gestalts can depend on other gestalts, we perform an + # iterative process and break when no new gestalts have been + # detected. + gestalt_count = 0 + + while true do + + # collect what we can + yank_definitions = [] + @definitions.each do |d| + + new_gestalts = d.gestalts(self) + if new_gestalts.any? + yank_definitions << d + @gestalts += new_gestalts + end + end + @definitions -= yank_definitions + + # did we make any progress? + break if gestalt_count == @gestalts.size + + # nope, keep going + gestalt_count = @gestalts.size + end + + gestalts + end + + def has_gestalt?(type,name) + @gestalts.find do |g| + g.type.to_s == type.to_s && + g.name == name + end + end + + def includes_language?(language, min_percent) + @language_facts.includes_language?(language,min_percent) + end + end + + + # keeps track of languages seen + class LanguageFacts + + def initialize + @language_counts ||= {} + end + + def process_source_file(source_file) + source_file.language_breakdowns.each do |lb| + @language_counts[lb.name.intern] ||= 0 + @language_counts[lb.name.intern] += lb.code_count + end + end + + def includes_language?(language, min_percent = 0) + return false unless @language_counts[language] + language_percents[language] >= min_percent + end + + # ignores markup languages (xml/html) + def language_percents + @language_percents ||= begin + total = 0 + @language_counts.each do |name,code_count| + next if Language.new(name.to_s).category == 1 + total += code_count + end + + l = {} + @language_counts.each do |k,v| + l[k] = 100.0 * v.to_i / total + end + l + + end + end + end + + end +end + diff --git a/lib/gestalt/gestalt_facts.rb b/lib/gestalt/gestalt_facts.rb new file mode 100644 index 0000000..084f412 --- /dev/null +++ b/lib/gestalt/gestalt_facts.rb @@ -0,0 +1,82 @@ +module Ohcount + + module Gestalt + + class GestaltFacts + + def self. + + end + end +end + + # Represents language statistics for a collection of files + class GestaltFacts + attr_accessor :platforms, :tools, :file_rules, :language_counts + + def initialize + @platforms = [] + @tools = [] + @file_rules = {} + @language_counts = {} + end + + def process(source_file) + Gestalt::FileRule.rules_triggered_by(source_file).each do |r| + @file_rules[r] ||= 0 + @file_rules[r] += 1 + end + source_file.language_breakdowns.each do |lb| + @language_counts[lb.name.intern] ||= 0 + @language_counts[lb.name.intern] += lb.code_count + end + end + + def post_process + # since platforms can depend on other platforms, + # we perform an iterative process and break when + # no new platforms have been detected. + while true do + prev_platforms = self.platforms.clone + uninfered_platforms.each do |p| + platforms << p if p.triggered?(self) + end + prev_tools = self.tools.clone + uninfered_tools.each do |t| + tools << t if t.triggered?(self) + end + break if prev_platforms == self.platforms && prev_tools == self.tools + end + end + + def gestalts + + end + + def uninfered_platforms #:nodoc: + Gestalt::Platform.descendants - @platforms + end + + def uninfered_tools #:nodoc: + Gestalt::Tool.descendants - @tools + end + + def includes_language?(language, min_percent = 0) + return false unless language_counts[language] + language_percents[language] >= min_percent + end + + def language_percents + @language_percents ||= begin + total = language_counts.values.inject(0) { |s,c| s+c } + l = {} + language_counts.each do |k,v| + l[k] = 100.0 * v.to_i / total + end + l + end + end + + end +end + diff --git a/lib/gestalt/platform.rb b/lib/gestalt/platform.rb index 33d821c..940e0fe 100644 --- a/lib/gestalt/platform.rb +++ b/lib/gestalt/platform.rb @@ -10,7 +10,6 @@ require 'lib/gestalt/rules/c_keyword_rule' require 'lib/gestalt/rules/platform_rule' require 'lib/gestalt/rules/java_import_rule' -require 'lib/gestalt/rules/java_package_rule' module Ohcount module Gestalt diff --git a/lib/gestalt/platforms.rb b/lib/gestalt/platforms.rb index 5ba4f32..9bf0250 100644 --- a/lib/gestalt/platforms.rb +++ b/lib/gestalt/platforms.rb @@ -182,57 +182,13 @@ class Drupal < Platform ) end - class MSDOS < Platform + class MSDos < Platform c_keywords '__MSDOS__', 'MSDOS', :min => 2 end class EclipsePlatform < Platform java_import 'org.eclipse.' end - - class ApacheCommons < Platform - java_import 'org.apache.commons' - end - - class ApacheTomcat < Platform - java_import 'org.apache.tomcat' - end - - class ApacheGeronimo < Platform - java_import 'org.apache.geronimo' - end - - class ApacheMaven < Platform - java_import 'org.apache.maven' - filenames 'pom.xml' - end - - class JBoss < Platform - java_import 'org.jboss.' - end - - class GlassFish < Platform - _or( - java_import('org.glassfish.'), - java_package('org.glassfish.') - ) - end - - class NetBeans < Platform - java_import 'org.netbeans.' - end - - class SunEnterprise < Platform - _or( - java_import('com.sun.enterprise'), - java_package('com.sun.enterprise') - ) - end - - class GoogleWebToolkit < Platform - java_import 'com.google.gwt.' - end - end end diff --git a/lib/gestalt/rules/and_rule.rb b/lib/gestalt/rules/and_rule.rb index 9b3553b..c631519 100644 --- a/lib/gestalt/rules/and_rule.rb +++ b/lib/gestalt/rules/and_rule.rb @@ -2,11 +2,12 @@ module Ohcount module Gestalt # Will trigger if all sub-rules do class AndRule < LogicalRule - def triggered?(g_facts) + + def triggers(gestalt_engine) rules.each do |r| - return nil unless r.triggered?(g_facts) + return [] if r.triggers(gestalt_engine).empty? end - self + [Trigger.new] end end end diff --git a/lib/gestalt/rules/c_header_rule.rb b/lib/gestalt/rules/c_header_rule.rb index 1d49342..fbbb630 100644 --- a/lib/gestalt/rules/c_header_rule.rb +++ b/lib/gestalt/rules/c_header_rule.rb @@ -10,11 +10,15 @@ def initialize(*args) super(options) end - def trigger_file?(source_file) - return false unless ['c','cpp'].include?(source_file.polyglot) - regexp.match(source_file.language_breakdown('c').code) || - regexp.match(source_file.language_breakdown('cpp').code) - end + def process_source_file(source_file) + return unless ['c','cpp'].include?(source_file.polyglot) + + ['c','cpp'].each do |lang| + next unless source_file.language_breakdown(lang) + md = regexp.match(source_file.language_breakdown(lang).code) + @count += (md && md.size).to_i + end + end def regexp @regexp ||= begin diff --git a/lib/gestalt/rules/c_keyword_rule.rb b/lib/gestalt/rules/c_keyword_rule.rb index 2977f43..bbad838 100644 --- a/lib/gestalt/rules/c_keyword_rule.rb +++ b/lib/gestalt/rules/c_keyword_rule.rb @@ -6,11 +6,13 @@ def initialize(*keywords) super('c',*keywords) end - def trigger_file?(source_file) - return false unless ['c','cpp'].include?(source_file.polyglot) - regexp.match(source_file.language_breakdown('c').code) || - regexp.match(source_file.language_breakdown('cpp').code) - end + def process_source_file(source_file) + if source_file.language_breakdown('c') + @count += source_file.language_breakdown('c').code.scan(regexp).size + elsif source_file.language_breakdown('cpp') + @count += source_file.language_breakdown('cpp').code.scan(regexp).size + end + end end end end diff --git a/lib/gestalt/rules/file_rule.rb b/lib/gestalt/rules/file_rule.rb index 31abdf5..821679e 100644 --- a/lib/gestalt/rules/file_rule.rb +++ b/lib/gestalt/rules/file_rule.rb @@ -4,11 +4,13 @@ module Gestalt # on an individual file's attribute (like # code content, or filename, etc..) class FileRule < Rule - attr_reader :min_count + attr_reader :min_count, :count def initialize(args = {}) args ||= {} @min_count = 1 + @count = 0 + @triggers = [] args.each do |k,v| case k when :min then @min_count = v @@ -18,25 +20,34 @@ def initialize(args = {}) FileRule.add_instance(self) end - def triggered?(g) - g.file_rules[self].to_i >= min_count - end + # default implementation - will yield a single trigger if appropriate + def triggers(gestalt_engine) + if triggered? + [Trigger.new] + else + [] + end + end - def self.rules_triggered_by(source_file) - rules = instances.find_all do |r| - r.trigger_file?(source_file) - end - rules + def self.process_source_file(source_file) + instances.each do |rule| + next if rule.triggered? + rule.process_source_file(source_file) + end end def self.instances @instances ||= [] end - + def self.add_instance(r) instances << r end + def triggered? + @count >= @min_count + end + end end end diff --git a/lib/gestalt/rules/filename_rule.rb b/lib/gestalt/rules/filename_rule.rb index ee6e619..8f14e13 100644 --- a/lib/gestalt/rules/filename_rule.rb +++ b/lib/gestalt/rules/filename_rule.rb @@ -10,8 +10,8 @@ def initialize(*args) super(options) end - def trigger_file?(source_file) - regex.match(source_file.filename) + def process_source_file(source_file) + @count += 1 if regex.match(source_file.filename) end def regex diff --git a/lib/gestalt/rules/find_filenames_rule.rb b/lib/gestalt/rules/find_filenames_rule.rb new file mode 100644 index 0000000..d05c488 --- /dev/null +++ b/lib/gestalt/rules/find_filenames_rule.rb @@ -0,0 +1,33 @@ +module Ohcount + module Gestalt + + # will yield as many triggers as files that match the regexp + class FindFilenamesRule < FileRule + attr_reader :regex + + def initialize(regex, options = {}) + @regex = regex + @triggers = [] + @name_from_match = options.delete(:name_from_match).to_i + super(options) + end + + # deep clone + def clone + self.class.new(@regex,:name_from_match => @name_from_match) + end + + def triggers(gestalt_engine) + @triggers + end + + def process_source_file(source_file) + m = @regex.match(source_file.filename) + if m + @triggers << Trigger.new(:name => m[@name_from_match]) + end + end + + end + end +end diff --git a/lib/gestalt/rules/find_java_imports_rule.rb b/lib/gestalt/rules/find_java_imports_rule.rb new file mode 100644 index 0000000..818b379 --- /dev/null +++ b/lib/gestalt/rules/find_java_imports_rule.rb @@ -0,0 +1,47 @@ +module Ohcount + module Gestalt + + # Will yield one trigger per java import - each with the name of the imported + # namespace. Example java source file: + # + # import com.foo.bar; + # + # will yield a trigger with name='com.foo.bar' + class FindJavaImportsRule < FileRule + attr_reader :keywords, :language + + def initialize(*args) + @trigger_hash = {} + super(*args) + end + + def process_source_file(source_file) + return unless source_file.language_breakdown('java') + + java_code = source_file.language_breakdown('java').code + java_code.scan(import_regexp).each do |matches| + name = matches[0] + @trigger_hash[name] = @trigger_hash[name].to_i + 1 + end + end + + # implement deep clone + def clone + self.class.new(:min => @min_count) + end + + def triggers(gestalt_engine) + triggers = [] + @trigger_hash.each do |k,v| + triggers << Trigger.new(:name => k, :count => v) + end + triggers + end + + def import_regexp + /\bimport\s+([a-zA-Z][\w\.\*\-]*)/ + end + + end + end +end diff --git a/lib/gestalt/rules/gestalt_rule.rb b/lib/gestalt/rules/gestalt_rule.rb new file mode 100644 index 0000000..1ffd1a0 --- /dev/null +++ b/lib/gestalt/rules/gestalt_rule.rb @@ -0,0 +1,22 @@ +module Ohcount + module Gestalt + + # states that a certain gestalt is required. + class GestaltRule < Rule + attr_reader :type, :name + + def initialize(type, name) + @type = type + @name = name + end + + def triggers(gestalt_engine) + if gestalt_engine.has_gestalt?(type,name) + [Trigger.new] + else + [] + end + end + end + end +end diff --git a/lib/gestalt/rules/java_import_rule.rb b/lib/gestalt/rules/java_import_rule.rb index 1b6ff7d..863f7e5 100644 --- a/lib/gestalt/rules/java_import_rule.rb +++ b/lib/gestalt/rules/java_import_rule.rb @@ -1,25 +1,27 @@ module Ohcount module Gestalt - # Triggers if a c or cpp header is present + + # Triggers if a matching java 'import' statement is present class JavaImportRule < FileRule - attr_reader :imports def initialize(*args) options = args.pop if args.last.is_a?(Hash) - @imports = args + @regex = args[0] super(options) end - def trigger_file?(source_file) - return false unless source_file.polyglot == 'java' - regexp.match(source_file.language_breakdown('java').code) + def process_source_file(source_file) + return false unless source_file.language_breakdown('java') + + java_code = source_file.language_breakdown('java').code + java_code.scan(import_regexp).each do |match| + import = match[0] + @count += 1 if import =~ @regex + end end - def regexp - @regexp ||= begin - imports_term = "(" + imports.join("|") + ")" - Regexp.new("import\s+#{ imports_term }") - end + def import_regexp + /\bimport\s+([a-zA-Z][\w\.\*\-]*)/ end end end diff --git a/lib/gestalt/rules/java_package_rule.rb b/lib/gestalt/rules/java_package_rule.rb deleted file mode 100644 index 2713685..0000000 --- a/lib/gestalt/rules/java_package_rule.rb +++ /dev/null @@ -1,27 +0,0 @@ -module Ohcount - module Gestalt - # Triggers if the code implements a java package matching the given regex - class JavaPackageRule < FileRule - attr_reader :packages - - def initialize(*args) - options = args.pop if args.last.is_a?(Hash) - @packages = args - super(options) - end - - def trigger_file?(source_file) - return false unless source_file.polyglot == 'java' - regexp.match(source_file.language_breakdown('java').code) - end - - def regexp - @regexp ||= begin - packages_term = "(" + packages.join("|") + ")" - Regexp.new("package\s+#{ packages_term }") - end - end - end - end -end - diff --git a/lib/gestalt/rules/keyword_rule.rb b/lib/gestalt/rules/keyword_rule.rb index b9d6743..f054f12 100644 --- a/lib/gestalt/rules/keyword_rule.rb +++ b/lib/gestalt/rules/keyword_rule.rb @@ -11,9 +11,11 @@ def initialize(language, *args) super(options) end - def trigger_file?(source_file) + def process_source_file(source_file) return unless source_file.language_breakdown(language) - regexp.match(source_file.language_breakdown(language).code) + + code = source_file.language_breakdown(language).code + @count += code.scan(regexp).size end def regexp diff --git a/lib/gestalt/rules/language_rule.rb b/lib/gestalt/rules/language_rule.rb index 70c55d5..b66fcf5 100644 --- a/lib/gestalt/rules/language_rule.rb +++ b/lib/gestalt/rules/language_rule.rb @@ -13,8 +13,12 @@ def initialize(language, options= {}) @language = language end - def triggered?(g) - return self if g.includes_language?(language, min_percent) + def triggers(gestalt_engine) + if gestalt_engine.includes_language?(language, min_percent) + [Trigger.new] + else + [] + end end end diff --git a/lib/gestalt/rules/logical_rule.rb b/lib/gestalt/rules/logical_rule.rb index 1c0adc7..6fccce7 100644 --- a/lib/gestalt/rules/logical_rule.rb +++ b/lib/gestalt/rules/logical_rule.rb @@ -3,32 +3,37 @@ module Gestalt class LogicalRule < Rule attr_reader :rules - def initialize(*rules) + def initialize(*rules, &block) @rules = rules + self.instance_eval(&block) if block end - def new_rule(r_class, *args) - # since we might be nesting logical rules, we must remove - # any 'grandchildren rules' from our list, since we are giving - args.each do |a| - next unless a.is_a?(Rule) - @rules.delete(a) - end - r = r_class.new(*args) - @rules << r - r + def each_rule(&block) + @rules.each { |r| r.each_rule(&block) } + yield self + end + + def clone + cloned_rules = @rules.map { |r| + r.clone + } + self.class.new(*cloned_rules) + end + + def new_rule(r_class, *args, &block) + @rules << r_class.new(*args,&block) end - def _or(*args) - new_rule OrRule, *args + def _or(*args, &block) + new_rule OrRule, *args, &block end - def _and(*args) - new_rule AndRule, *args + def _and(*args, &block) + new_rule AndRule, *args, &block end - def platform(*args) - new_rule PlatformRule, *args + def gestalt(*args) + new_rule GestaltRule, *args end def language(*args) @@ -52,16 +57,21 @@ def java_import(*args) new_rule JavaImportRule, *args end - def java_package(*args) - new_rule JavaPackageRule, *args - end + def find_filenames(*args) + new_rule FindFilenamesRule, *args + end + + def find_java_imports(*args) + new_rule FindJavaImportsRule, *args + end - def method_missing(m,*args) - if /(.*)_keywords$/ =~ m.to_s + def method_missing(m,*args, &block) + if m.to_s =~ /^(.*)_keywords$/ language = $1 new_args = [language] + args - return new_rule(KeywordRule, *new_args) - end + new_rule(KeywordRule, *new_args, &block) + return + end super end diff --git a/lib/gestalt/rules/or_rule.rb b/lib/gestalt/rules/or_rule.rb index 4fa35ea..d180b03 100644 --- a/lib/gestalt/rules/or_rule.rb +++ b/lib/gestalt/rules/or_rule.rb @@ -2,11 +2,12 @@ module Ohcount module Gestalt # Will trigger if any sub-rule does class OrRule < LogicalRule - def triggered?(g_facts) + def triggers(gestalt_engine) rules.each do |r| - return r if r.triggered?(g_facts) + triggers = r.triggers(gestalt_engine) + return triggers if triggers.any? end - nil + [] end end end diff --git a/lib/gestalt/rules/platform_rule.rb b/lib/gestalt/rules/platform_rule.rb deleted file mode 100644 index 9ec5c2b..0000000 --- a/lib/gestalt/rules/platform_rule.rb +++ /dev/null @@ -1,18 +0,0 @@ -module Ohcount - module Gestalt - - # states that a platform depends on another platform - # being true. - class PlatformRule < Rule - attr_reader :platform - - def initialize(platform) - @platform = platform - end - - def triggered?(g_facts) - g_facts.platforms.include?(platform) - end - end - end -end diff --git a/lib/gestalt/rules/rule.rb b/lib/gestalt/rules/rule.rb index 2274c7d..710bcb1 100644 --- a/lib/gestalt/rules/rule.rb +++ b/lib/gestalt/rules/rule.rb @@ -5,11 +5,15 @@ def ==(other) return false unless self.class == other.class return false unless self.instance_variables == other.instance_variables self.instance_variables.each do |v| - return false unless self.send(v[1..-1]) == other.send(v[1..-1]) + return false unless self.instance_eval(v) == other.instance_eval(v) end true end + def each_rule + yield self + end + def to_sym self.class.to_sym end @@ -33,7 +37,7 @@ def self.to_sym def self.method_missing(m,*args) if /(.*)_keywords$/ =~ m.to_s language = $1 - return rules << KeywordLibraryRule.new(language,args) + return rules << KeywordRule.new(language,*args) end super end diff --git a/lib/gestalt/tools.rb b/lib/gestalt/tools.rb index d9db316..e1073d2 100644 --- a/lib/gestalt/tools.rb +++ b/lib/gestalt/tools.rb @@ -6,11 +6,11 @@ class VisualStudio < Tool filenames '\.(sln|vcproj|vsproj|csproj|vbproj|vbp)$' end - class EclipseIDE < Tool + class Eclipse < Tool filenames '\.(project|classpath)$' end - class NetBeansIDE < Tool + class NetBeans < Tool filenames '\bnbplatform\b' filenames '\.nbm$' end diff --git a/lib/gestalt/trigger.rb b/lib/gestalt/trigger.rb new file mode 100644 index 0000000..1e66097 --- /dev/null +++ b/lib/gestalt/trigger.rb @@ -0,0 +1,13 @@ +module Ohcount + module Gestalt + class Trigger + attr_reader :name, :count + + def initialize(args = {}) + @name = args[:name] + @count = args[:count] || 1 + end + + end + end +end diff --git a/lib/ohcount.rb b/lib/ohcount.rb index ccd1a9e..2f94592 100644 --- a/lib/ohcount.rb +++ b/lib/ohcount.rb @@ -29,7 +29,9 @@ module Ohcount require "lib/licenses/license_sniffer" -require "lib/gestalt/platform" -require "lib/gestalt/platforms" -require "lib/gestalt/tool" -require "lib/gestalt/tools" +# gestalt +require "lib/gestalt/trigger" +require "lib/gestalt/definition" +require "lib/gestalt/base" +require "lib/gestalt/definitions" +require "lib/gestalt/gestalt_engine" diff --git a/lib/ohcount/gestalt_facts.rb b/lib/ohcount/gestalt_facts.rb index c16af2f..e8e1c92 100644 --- a/lib/ohcount/gestalt_facts.rb +++ b/lib/ohcount/gestalt_facts.rb @@ -4,7 +4,7 @@ module Ohcount class GestaltFacts attr_accessor :platforms, :tools, :file_rules, :language_counts - def initialize + def initialize @platforms = [] @tools = [] @file_rules = {} @@ -39,6 +39,10 @@ def post_process end end + def gestalts + + end + def uninfered_platforms #:nodoc: Gestalt::Platform.descendants - @platforms end diff --git a/lib/ohcount/source_file.rb b/lib/ohcount/source_file.rb index a54ebd3..92327d0 100644 --- a/lib/ohcount/source_file.rb +++ b/lib/ohcount/source_file.rb @@ -192,5 +192,48 @@ def calc_large_diff(a,b) [added, removed] end + # we are in the process of consolidating various code-detected traits into + # an extensible attribute called 'gestalt'. + def gestalts + gestalt_engine = Gestalt::GestaltEngine.new + gestalt_engine.process(self) + gestalt_engine.calc_gestalts + gestalt_engine.gestalts + end + +# # returns the jars seen from this source_file +# def detected_jars +# jars = [] +# if File.extname(filename) == '.jar' +# # hey, we're a jar! +# jars << File.basename(filename) +# elsif File.basename(filename) == 'build.xml' +# # this logic is pretty dubious: +# # - many ant files include other files - we don't detect that +# # - specific jar dependencies can be listed in a '.properties' file - we don't detect that either +# # +# # however, might as well try this out anyway - live and learn, aye? +# self.parse do |language, semantic, line| +# next unless semantic == :code +# jars += line.scan(/\b(\w[\w\-_\.]*\.jar)\b/).flatten +# end +# end +# jars +# end +# +# # returns the java imports seen in this source_file +# def imports_from_java_file +# imports = [] +# if polyglot == 'java' +# parse do |language, semantic, line| +# next unless semantic == :code +# line.scan(/import\s+(\w\S*);/).each do |match| +# imports << match[0] +# end +# end +# end +# imports +# end + end end diff --git a/lib/ohcount/source_file_list.rb b/lib/ohcount/source_file_list.rb index 17ffd07..f39a59e 100644 --- a/lib/ohcount/source_file_list.rb +++ b/lib/ohcount/source_file_list.rb @@ -7,7 +7,7 @@ module Ohcount # sfl.loc_list.loc(:ruby).code # class SourceFileList < Array - attr_reader :loc_list, :gestalt_facts + attr_reader :loc_list, :java_facts # pass an array of filenames you want to process. # @@ -55,6 +55,7 @@ def files_from_path(path) # # :gestalt:: platform dependencies and tools usage # :languages:: detailed programming languages facts + # :java:: java-related dependencies (jars & imports) # # Examples # @@ -70,20 +71,25 @@ def analyze(what = [:*]) do_languages = what.include?(:language) || what.include?(:*) @loc_list = LocList.new if do_languages - @gestalt_facts = GestaltFacts.new if do_gestalt + @gestalt_engine = Gestalt::GestaltEngine.new if do_gestalt self.each do |file| # we process each file - even if its not a source_code - for # library rules sake - they sometimes want 'jar' files or something source_file = SourceFile.new(file, :filename => self) @loc_list += source_file.loc_list if do_languages - @gestalt_facts.process(source_file) if do_gestalt + @gestalt_engine.process(source_file) if do_gestalt yield source_file if block_given? end - @gestalt_facts.post_process if do_gestalt + @gestalt_engine.calc_gestalts if do_gestalt end + def gestalts + raise "No gestalts analyzed yet" unless @gestalt_engine + @gestalt_engine.gestalts + end + def each_source_file self.each do |file| sf = SourceFile.new(file, :filename => self) diff --git a/test/gestalt_files/eclipse_platform/main.java b/test/gestalt_files/eclipse_platform/main.java index cdd268f..2798a90 100644 --- a/test/gestalt_files/eclipse_platform/main.java +++ b/test/gestalt_files/eclipse_platform/main.java @@ -4,8 +4,6 @@ package net.ohloh.www; import java.text.SimpleDateFormat; - import java.util.Date; - import java.util.HashMap; import java.util.Map; import org.eclipse.core.lotsa_stuff; diff --git a/test/unit/gestalt/definitions_test.rb b/test/unit/gestalt/definitions_test.rb new file mode 100644 index 0000000..c7396ad --- /dev/null +++ b/test/unit/gestalt/definitions_test.rb @@ -0,0 +1,205 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +include Ohcount +include Ohcount::Gestalt + +class PlatformTest < Test::Unit::TestCase + + def test_zend_framework + assert_gestalts 'zend_framework', [ + Base.new(:platform,'PHP'), + Base.new(:platform,'ZendFramework') + ] + end + + def test_php + assert_gestalts 'php', [ + Base.new(:platform,'PHP') + ] + end + + def test_wx_widgets + assert_gestalts 'wx_widgets', [ + Base.new(:platform,'WxWidgets') + ] + end + + def test_eclipse_platform + assert_gestalts 'eclipse_platform', [ + Base.new(:platform,'Java'), + Base.new(:platform,'EclipsePlatform'), + Base.new(:java_import,"java.text.SimpleDateFormat"), + Base.new(:java_import,"java.util.Map"), + Base.new(:java_import,"org.eclipse.core.lotsa_stuff") + ] + end + + def test_win32_not_enough + assert_gestalts 'win32_not_enough', [] + end + + def test_win32_enough + assert_gestalts 'win32_enough', [ + Base.new(:platform, 'Win32') + ] + end + + def test_wpf + assert_gestalts 'wpf', [ + Base.new(:platform, 'WPF') + ] + end + + def test_asp_net + assert_gestalts 'asp_net', [ + Base.new(:platform, 'ASP_NET') + ] + end + + def test_ruby_just_enough + assert_gestalts 'ruby_just_enough', [ + Base.new(:platform, 'Ruby') + ] + end + + def test_ruby_not_enough + assert_gestalts 'ruby_not_enough', [] + end + + def test_cakephp + assert_gestalts 'cakephp', [ + Base.new(:platform, 'PHP'), + Base.new(:platform, 'CakePHP') + ] + end + + def test_symfony + assert_platform('symfony', :PHP, :Symfony) + end + + def test_pear + assert_platform('pear', :PHP, :Pear) + end + + def test_moodle + assert_platform('moodle', :PHP, :Moodle) + end + + def test_spring_framework + assert_gestalts 'spring_framework', [ + Base.new(:platform, 'Java'), + Base.new(:platform, 'SpringFramework'), + Base.new(:java_jar, 'spring.jar'), + ] + end + + def test_rails + assert_platform('rails', :Ruby, :Rails) + end + + def test_jquery + assert_platform('jquery', :Javascript, :JQuery) + end + + def test_python + assert_platform('python', :Python) + end + + def test_mac + assert_platform('mac', :Mac) + end + + def test_plist + assert_platform('plist', :Mac) + end + + def test_posix + assert_platform('posix', :POSIX) + end + + def test_x_windows + assert_platform('xwindows', :XWindows) + end + + def test_kde + assert_platform('kde', :KDE) + end + + def test_msdos + assert_platform('msdos', :MSDos) + end + + def test_gtk + assert_platform('gtk', :GTK) + end + + def test_drupal + assert_platform('drupal', :PHP, :Drupal) + end + + def test_vs_1 + assert_tool('vs_1', :VisualStudio) + end + + def test_eclipse + assert_tool('eclipse', :Eclipse) + end + + def test_netbeans + assert_tool('netbeans', :NetBeans) + end + + def test_java_imports_from_java_file + java = SourceFile.new("foo.java", :contents => <<-INLINE_C + import com.foo; + import net.ohloh; + import com.foo; + // import dont.import.this; + INLINE_C + ) + + expected_gestalts = [ + Base.new(:java_import, 'com.foo', 2), + Base.new(:java_import, 'net.ohloh'), + Base.new(:platform, 'Java'), + ] + + assert_equal expected_gestalts.sort, java.gestalts.sort + end + + def test_imports_from_java_file + jar = SourceFile.new("foo/foo.jar", :contents => '') + + expected_gestalts = [ + Base.new(:java_jar, 'foo.jar'), + ] + + assert_equal expected_gestalts.sort, jar.gestalts.sort + end + + protected + + def assert_tool(path, *tools) + gestalts = tools.map do |t| + Base.new(:tool, t.to_s) + end + assert_gestalts path, gestalts + end + + def assert_platform(path, *platforms) + gestalts = platforms.map do |p| + Base.new(:platform, p.to_s) + end + assert_gestalts path, gestalts + end + + def assert_gestalts(path, expected_gestalts) + sfl = SourceFileList.new(:path => test_dir(path)) + sfl.analyze(:gestalt) + assert_equal expected_gestalts.sort, sfl.gestalts.sort + end + + def test_dir(d) + File.expand_path(File.dirname(__FILE__) + "/../../gestalt_files/#{ d }") + end +end diff --git a/test/unit/gestalt/file_rule_test.rb b/test/unit/gestalt/file_rule_test.rb index 09cc4b8..dcddfab 100644 --- a/test/unit/gestalt/file_rule_test.rb +++ b/test/unit/gestalt/file_rule_test.rb @@ -1,40 +1,52 @@ require File.dirname(__FILE__) + '/../../test_helper' class FileRuleTest < Test::Unit::TestCase - - def test_trigger_c_header - r = Ohcount::Gestalt::CHeaderRule.new('foo.h') - s = Ohcount::SourceFile.new('header.h', :contents => <<-H_FILE - // a comment - include 'foo.h' - H_FILE - ) - assert r.trigger_file?(s) - end - - def test_c_keyword_rule - r = Ohcount::Gestalt::CKeywordRule.new('WM_PAINT') - s = Ohcount::SourceFile.new('header.h', :contents => <<-H_FILE - // a comment - (WM_PAINT) - H_FILE - ) - assert r.trigger_file?(s) - end - - def test_filename_rule - r = Ohcount::Gestalt::FilenameRule.new('header.h') - s = Ohcount::SourceFile.new('header.h') - assert r.trigger_file?(s) - end - - def test_filename_rule_advanced - r = Ohcount::Gestalt::FilenameRule.new('f[ab]o', 'foo') - assert r.trigger_file?(Ohcount::SourceFile.new('fao')) - assert r.trigger_file?(Ohcount::SourceFile.new('fbo')) - assert r.trigger_file?(Ohcount::SourceFile.new('foo')) - assert !r.trigger_file?(Ohcount::SourceFile.new('fco')) - end + include Ohcount::Gestalt + + def test_initialize + r = FileRule.new(:min => 5) + assert_equal 5, r.min_count + end + + def test_initialize_wrong_args + assert_raise ArgumentError do + r = FileRule.new(:boo => 1) + end + end + +# def test_trigger_c_header +# r = Ohcount::Gestalt::CHeaderRule.new('foo.h') +# s = Ohcount::SourceFile.new('header.h', :contents => <<-H_FILE +# // a comment +# include 'foo.h' +# H_FILE +# ) +# assert r.trigger_file?(s) +# end +# +# def test_c_keyword_rule +# r = Ohcount::Gestalt::CKeywordRule.new('WM_PAINT') +# s = Ohcount::SourceFile.new('header.h', :contents => <<-H_FILE +# // a comment +# (WM_PAINT) +# H_FILE +# ) +# assert r.trigger_file?(s) +# end +# +# def test_filename_rule +# r = Ohcount::Gestalt::FilenameRule.new('header.h') +# s = Ohcount::SourceFile.new('header.h') +# assert r.trigger_file?(s) +# end +# +# def test_filename_rule_advanced +# r = Ohcount::Gestalt::FilenameRule.new('f[ab]o', 'foo') +# assert r.trigger_file?(Ohcount::SourceFile.new('fao')) +# assert r.trigger_file?(Ohcount::SourceFile.new('fbo')) +# assert r.trigger_file?(Ohcount::SourceFile.new('foo')) +# assert !r.trigger_file?(Ohcount::SourceFile.new('fco')) +# end end diff --git a/test/unit/gestalt/filename_rule_test.rb b/test/unit/gestalt/filename_rule_test.rb new file mode 100644 index 0000000..d6e247a --- /dev/null +++ b/test/unit/gestalt/filename_rule_test.rb @@ -0,0 +1,18 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class FilenameRuleTest < Test::Unit::TestCase + include Ohcount::Gestalt + + def test_process_file + r = FilenameRule.new('foo\.rb') + s = Ohcount::SourceFile.new('/bar/com/foo.rb', :contents => <<-RUBY_CODE + # comment + code = 1 + RUBY_CODE + ) + assert r.process_source_file(s) + assert_equal 1, r.count + end +end + + diff --git a/test/unit/gestalt/keyword_rule_test.rb b/test/unit/gestalt/keyword_rule_test.rb new file mode 100644 index 0000000..64299a8 --- /dev/null +++ b/test/unit/gestalt/keyword_rule_test.rb @@ -0,0 +1,19 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class KeywordRuleTest < Test::Unit::TestCase + include Ohcount::Gestalt + + def test_process_file + r = KeywordRule.new('c', 'WIN32') + s = Ohcount::SourceFile.new('header.c', :contents => <<-C_CODE + // a comment + #ifdef WIN32 + ..some code.. + #endif + C_CODE + ) + assert r.process_source_file(s) + assert_equal 1, r.count + end +end + diff --git a/test/unit/gestalt/platform_test.rb b/test/unit/gestalt/platform_test.rb deleted file mode 100644 index 41cf6c0..0000000 --- a/test/unit/gestalt/platform_test.rb +++ /dev/null @@ -1,123 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -include Ohcount -include Ohcount::Gestalt - -class PlatformTest < Test::Unit::TestCase - - def test_zend_framework - assert_platform('zend_framework', PHP, ZendFramework) - end - - def test_wx_widgets - assert_platform('wx_widgets', WxWidgets) - end - - def test_eclipse_platform - assert_platform('eclipse_platform', Java, EclipsePlatform) - end - - def test_win32_not_enough - assert_platform('win32_not_enough') - end - - def test_win32_enough - assert_platform('win32_enough', Win32) - end - - def test_wpf - assert_platform('wpf', WPF) - end - - def test_asp_net - assert_platform('asp_net', ASP_NET) - end - - def test_ruby_just_enough - assert_platform('ruby_just_enough', Ruby) - end - - def test_ruby_not_enough - assert_platform('ruby_not_enough') - end - - def test_cakephp - assert_platform('cakephp', PHP, CakePHP) - end - - def test_symfony - assert_platform('symfony', PHP, Symfony) - end - - def test_pear - assert_platform('pear', PHP, Pear) - end - - def test_moodle - assert_platform('moodle', PHP, Moodle) - end - - def test_spring_framework - assert_platform('spring_framework', Java, SpringFramework) - end - - def test_rails - assert_platform('rails', Ruby, Rails) - end - - def test_jquery - assert_platform('jquery', Javascript, JQuery) - end - - def test_php - assert_platform('php', PHP) - end - - def test_python - assert_platform('python', Python) - end - - def test_mac - assert_platform('mac', Mac) - end - - def test_plist - assert_platform('plist', Mac) - end - - def test_posix - assert_platform('posix', POSIX) - end - - def test_x_windows - assert_platform('xwindows', XWindows) - end - - def test_kde - assert_platform('kde', KDE) - end - - def test_msdos - assert_platform('msdos', MSDOS) - end - - def test_gtk - assert_platform('gtk', GTK) - end - - def test_drupal - assert_platform('drupal', PHP, Drupal) - end - - protected - - def assert_platform(path, *platforms) - sfl = SourceFileList.new(:path => test_dir(path)) - sfl.analyze(:gestalt) - assert_equal platforms, sfl.gestalt_facts.platforms - end - - def test_dir(d) - File.expand_path(File.dirname(__FILE__) + "/../../gestalt_files/#{ d }") - end -end diff --git a/test/unit/gestalt/tool_test.rb b/test/unit/gestalt/tool_test.rb deleted file mode 100644 index 7753a83..0000000 --- a/test/unit/gestalt/tool_test.rb +++ /dev/null @@ -1,32 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -include Ohcount -include Ohcount::Gestalt - -class ToolTest < Test::Unit::TestCase - - def test_vs_1 - assert_tool('vs_1', VisualStudio) - end - - def test_eclipse - assert_tool('eclipse', EclipseIDE) - end - - def test_netbeans - assert_tool('netbeans', NetBeansIDE) - end - - protected - def assert_tool(path, *tools) - sfl = SourceFileList.new(:path => test_dir(path)) - sfl.analyze(:gestalt) - assert_equal tools, sfl.gestalt_facts.tools - end - - def test_dir(d) - File.expand_path(File.dirname(__FILE__) + "/../../gestalt_files/#{ d }") - end - -end - diff --git a/test/unit/source_file_list_test.rb b/test/unit/source_file_list_test.rb index 0e05a64..0abe691 100644 --- a/test/unit/source_file_list_test.rb +++ b/test/unit/source_file_list_test.rb @@ -3,11 +3,6 @@ class SourceFileListTest < Ohcount::Test -# def test_init_with_dir -# sfl = SourceFileList.new(:dir => test_dir('test_win32_enough')) -# assert_equal 2, sfl.size -# end - def test_language_facts sfl = SourceFileList.new(:path => test_dir('win32_enough')) sfl.analyze(:language) @@ -17,12 +12,6 @@ def test_language_facts assert_equal 2, sfl.loc_list.c.blanks end - def test_gestalt_facts - sfl = SourceFileList.new(:path => test_dir('win32_enough')) - sfl.analyze(:gestalt) - assert_equal [Win32], sfl.gestalt_facts.platforms - end - protected def license_file(f) diff --git a/test/unit/source_file_test.rb b/test/unit/source_file_test.rb index 24d227d..c93e957 100644 --- a/test/unit/source_file_test.rb +++ b/test/unit/source_file_test.rb @@ -119,4 +119,5 @@ def test_calc_diff assert_equal [1,0], SourceFile.new.calc_diff("Hello, World!\n" * 10, "Hello, World!\n" * 11) assert_equal [1,0], SourceFile.new.calc_diff("Hello, World!\n" * 10000, "Hello, World!\n" * 10001) end + end From f9987d74cc885a69981a7edf389ce2e26e2b7943 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 7 May 2009 14:43:26 -0700 Subject: [PATCH 118/387] [FIX] BlitzMax entry in the language map was incorrect. Should have been listed by *name*, not by its *extension*. --- lib/ohcount/language.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ohcount/language.rb b/lib/ohcount/language.rb index 4f9b501..03adfad 100644 --- a/lib/ohcount/language.rb +++ b/lib/ohcount/language.rb @@ -2,7 +2,7 @@ class Ohcount::Language attr_reader :name def initialize(name) - raise ArgumentError.new("language name can't be nil") unless name + raise ArgumentError.new("Language name can't be nil") unless name @name = name end @@ -15,7 +15,7 @@ def lang_map 'automake' => {:nice_name => 'Automake' , :category => 2}, 'awk' => {:nice_name => 'AWK' , :category => 0}, 'bat' => {:nice_name => 'DOS batch script' , :category => 0}, - 'bmx' => {:nice_name => 'BlitzMax' , :category => 0}, + 'blitzmax' => {:nice_name => 'BlitzMax' , :category => 0}, 'boo' => {:nice_name => 'Boo' , :category => 0}, 'c' => {:nice_name => 'C' , :category => 0}, 'classic_basic' => {:nice_name => 'Classic Basic' , :category => 0}, From 1b10e101e2bbeab3871b83088c71b363608d808a Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 7 May 2009 15:44:58 -0700 Subject: [PATCH 119/387] [CHANGE] Change the default sort order of gestalts: type, counts desc, name [CHANGE] bin/ohcount -g outputs bare gestalt records on each line for easier scripting --- bin/ohcount | 49 +++++++++++++++++++++++++++++++++++-------------- lib/gestalt/base.rb | 11 ++++++++--- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/bin/ohcount b/bin/ohcount index b196970..18d8088 100755 --- a/bin/ohcount +++ b/bin/ohcount @@ -60,6 +60,8 @@ class OhcountCommandLine end def analyze_with_progress(what) + STDOUT.write "Examining #{source_file_list.size} file(s)" + count = 0 source_file_list.analyze(what) do |s| if count % 100 == 0 @@ -72,29 +74,50 @@ class OhcountCommandLine end def write_gestalt - typed_gestalts = {} - source_file_list.gestalts.each do |gestalt| + typed_gestalts = {} + source_file_list.gestalts.sort.each do |gestalt| typed_gestalts[gestalt.type] ||= [] typed_gestalts[gestalt.type] << gestalt.name end - puts '- Gestalts -------------------------------------------------------------------' + puts "- Gestalts -------------------------------------------------------------------" - typed_gestalts.each do |k,v| - names = v.join(", ") + if typed_gestalts.any? + max_display = 8 + more = false - if names.size > 120 - names = "[#{ v.size } found] #{names[0..120]}..." - end + typed_gestalts.each do |k,v| + names = if v.size > max_display + more = true + v[0, max_display - 1].join(", ") + " (... #{v.size - max_display + 1} more)" + else + v.join(", ") + end + puts titleize(k) + "s: " + names + end - puts k.to_s.upcase + ": " + names - end + puts "\nRun `#{__FILE__} -g` to see all detected gestalts." if more + else + puts "None detected." + end + + puts + end + + def titleize(s) + s.to_s.downcase.split("_").map { |i| capitalize(i) }.join(" ") + end + + def capitalize(s) + s.to_s[0..0].upcase + s.to_s[1..-1] end # Gestalt def gestalt - analyze_with_progress(:gestalt) - write_gestalt + source_file_list.analyze(:gestalt) + source_file_list.gestalts.sort.each do |gestalt| + puts "#{gestalt.type}\t#{gestalt.count.to_s.rjust(8)}\t#{gestalt.name}" + end end def raw_entities @@ -205,8 +228,6 @@ HELP end def summary - STDOUT.write "Examining #{source_file_list.size} file(s)" - analyze_with_progress(:*) puts diff --git a/lib/gestalt/base.rb b/lib/gestalt/base.rb index a08e1bf..7584c17 100644 --- a/lib/gestalt/base.rb +++ b/lib/gestalt/base.rb @@ -17,9 +17,14 @@ def ==(other) end def <=>(other) - me = self.type.to_s + self.name.to_s + self.count.to_s - you = other.type.to_s + other.name.to_s + other.count.to_s - me <=> you + # Sort by type, then descending count, then name + if self.type != other.type + self.type.to_s <=> other.type.to_s + elsif self.count != other.count + -(self.count <=> other.count) + else + self.name.to_s <=> other.name.to_s + end end # will return an array of detected gestalts from a source_file_list From e5684d1e3b9b50a621e009945a055d6af09965e2 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 7 May 2009 15:53:16 -0700 Subject: [PATCH 120/387] [FIX] Remove unnecessary i9 file --- lib/licenses/ohcount-license_map.rb.diff | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 lib/licenses/ohcount-license_map.rb.diff diff --git a/lib/licenses/ohcount-license_map.rb.diff b/lib/licenses/ohcount-license_map.rb.diff deleted file mode 100644 index 8bcd98d..0000000 --- a/lib/licenses/ohcount-license_map.rb.diff +++ /dev/null @@ -1,15 +0,0 @@ ---- license_map.rb 2008-09-09 18:11:02.000000000 +0100 -+++ license_map-i9.rb 2009-04-16 15:05:46.000000000 +0100 -@@ -143,6 +143,11 @@ - "Historical Permission Notice and Disclaimer", - /\bhistorical\s*permission\s*notice\s*and\s*disclaimer\b/i ), - -+ SoftwareLicense.new(:i9_license, -+ "http://i9os.googlecode.com/svn/trunk/Documentation/Licenses/i9_License", -+ "i9 License", -+ /\bi9\s*\s*license\b/i ), -+ - SoftwareLicense.new(:ibm_public, - "http://www.opensource.org/licenses/ibmpl.php", - "IBM Public License", - From 00da9ac296630c75bc619632ec98ed9baf41fd3f Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 7 May 2009 16:02:16 -0700 Subject: [PATCH 121/387] [FIX] Clean up the alphabetic sort on the language extensions map --- lib/ohcount/detector.rb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index 553f740..6f6fb98 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -147,13 +147,14 @@ def self.binary_filename?(filename) '.c++' => "cpp", '.cxx' => "cpp", '.com' => "dcl", - '.el' => "emacslisp", '.cs' => :disambiguate_cs, + '.d' => 'dmd', + '.di' => 'dmd', '.dylan' => "dylan", '.e' => "eiffel", '.ebuild' => "ebuild", '.eclass' => "ebuild", - '.kdebuild-1' => "ebuild", + '.el' => "emacslisp", '.erl' => "erlang", '.exheres-0' => "exheres", '.exlib' => "exheres", @@ -187,9 +188,12 @@ def self.binary_filename?(filename) '.java' => "java", '.js' => "javascript", '.jsp' => "jsp", - '.lua' => "lua", - '.lsp' => "lisp", + '.kdebuild-1' => "ebuild", + '.latex' => 'tex', '.lisp' => "lisp", + '.lsp' => "lisp", + '.ltx' => 'tex', + '.lua' => "lua", '.m' => :matlab_octave_or_objective_c, '.mf' => 'metafont', '.mk' => 'make', @@ -236,6 +240,7 @@ def self.binary_filename?(filename) '.st' => :disambiguate_smalltalk, '.str' => "stratego", '.tcl' => "tcl", + '.tex' => 'tex', '.tpl' => "html", '.vala' => "vala", '.vb' => "visualbasic", @@ -249,12 +254,7 @@ def self.binary_filename?(filename) '.xml' => "xml", '.xs' => "c", '.xsd' => "xmlschema", - '.xsl' => "xslt", - '.d' => 'dmd', - '.di' => 'dmd', - '.tex' => 'tex', - '.ltx' => 'tex', - '.latex' => 'tex' + '.xsl' => "xslt" } # Map full filenames to glots. The right hand side is a string or symbol as From 186a2893efdc4f549f0a4bf5cd511daaefd98460 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 7 May 2009 16:04:18 -0700 Subject: [PATCH 122/387] [NEW] .z80 files now detected as assembler --- lib/ohcount/detector.rb | 3 ++- test/unit/detector_test.rb | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index 6f6fb98..0af8b22 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -254,7 +254,8 @@ def self.binary_filename?(filename) '.xml' => "xml", '.xs' => "c", '.xsd' => "xmlschema", - '.xsl' => "xslt" + '.xsl' => "xslt", + '.z80' => "assembler" } # Map full filenames to glots. The right hand side is a string or symbol as diff --git a/test/unit/detector_test.rb b/test/unit/detector_test.rb index 7093b9f..77ab6bd 100644 --- a/test/unit/detector_test.rb +++ b/test/unit/detector_test.rb @@ -89,6 +89,7 @@ def test_detect_polyglot assert_equal "glsl", do_detect("foo.glsl") assert_equal "glsl", do_detect("foo_glsl.vert") assert_equal "glsl", do_detect("foo_glsl.frag") + assert_equal "assembler", do_detect("foo.z80") end def test_upper_case_extensions From 4a64bb2a1c45221046d0a9d2c6bf6da1a74398f5 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 7 May 2009 16:10:52 -0700 Subject: [PATCH 123/387] [NEW] Test file for z80 --- test/detect_files/foo.z80 | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/detect_files/foo.z80 diff --git a/test/detect_files/foo.z80 b/test/detect_files/foo.z80 new file mode 100644 index 0000000..e69de29 From 10ca9fb5f95535e09b67edcab0b04a5c7a8ae7dd Mon Sep 17 00:00:00 2001 From: unwesen Date: Thu, 7 May 2009 16:12:45 -0700 Subject: [PATCH 124/387] [NEW] Boost license detection --- lib/licenses/license_map.rb | 6 ++++++ test/expected_licenses/boost_t1 | 1 + test/expected_licenses/boost_t2 | 1 + test/src_licenses/boost_t1.c | 25 +++++++++++++++++++++++++ test/src_licenses/boost_t2.c | 1 + 5 files changed, 34 insertions(+) create mode 100644 test/expected_licenses/boost_t1 create mode 100644 test/expected_licenses/boost_t2 create mode 100644 test/src_licenses/boost_t1.c create mode 100644 test/src_licenses/boost_t2.c diff --git a/lib/licenses/license_map.rb b/lib/licenses/license_map.rb index d081206..0ba99e8 100644 --- a/lib/licenses/license_map.rb +++ b/lib/licenses/license_map.rb @@ -365,6 +365,12 @@ def initialize() "BSD-ish (2 clause) License", /Copyright\s.{1,60}All rights reserved.{1,40}Redistribution and use in source and binary forms, with or without.{0,20}modification, are permitted provided that the following conditions.{0,20}\sare met.{0,20}\s{1,20}.{0,20}Redistributions of source code must retain the above copyright\s+.*notice, this list of conditions and the following disclaimer.\s+.*Redistributions in binary form must reproduce the above copyright\s+.*notice, this list of conditions and the following disclaimer in the\s+.*documentation and\/or other materials provided with the distribution\.\s+.*HOWEVER CAUSED AND ON ANY.*THEORY OF LIABILITY, WHETHER IN CONTRACT/m, /(The Regents of the University of California)|(used to endorse or promote\s+.*products\s+.*prior\s+.*written\s+.*permission\.)/m), + + SoftwareLicense.new(:boost, + "http://www.boost.org/LICENSE_1_0.txt", + "Boost Software License - Version 1.0 - August 17th, 2003", + /\bboost\s*software\s*license\b/i ) + ].each do |l| @licenses << l @map[l.symbol] = l diff --git a/test/expected_licenses/boost_t1 b/test/expected_licenses/boost_t1 new file mode 100644 index 0000000..d579dbe --- /dev/null +++ b/test/expected_licenses/boost_t1 @@ -0,0 +1 @@ +boost diff --git a/test/expected_licenses/boost_t2 b/test/expected_licenses/boost_t2 new file mode 100644 index 0000000..d579dbe --- /dev/null +++ b/test/expected_licenses/boost_t2 @@ -0,0 +1 @@ +boost diff --git a/test/src_licenses/boost_t1.c b/test/src_licenses/boost_t1.c new file mode 100644 index 0000000..f03ca30 --- /dev/null +++ b/test/src_licenses/boost_t1.c @@ -0,0 +1,25 @@ +/* + * Boost Software License - Version 1.0 - August 17th, 2003 + * + * Permission is hereby granted, free of charge, to any person or organization + * obtaining a copy of the software and accompanying documentation covered by + * this license (the "Software") to use, reproduce, display, distribute, + * execute, and transmit the Software, and to prepare derivative works of the + * Software, and to permit third-parties to whom the Software is furnished to + * do so, all subject to the following: + * + * The copyright notices in the Software and this entire statement, including + * the above license grant, this restriction and the following disclaimer, + * must be included in all copies of the Software, in whole or in part, and + * all derivative works of the Software, unless such copies or derivative + * works are solely in the form of machine-executable object code generated by + * a source language processor. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ diff --git a/test/src_licenses/boost_t2.c b/test/src_licenses/boost_t2.c new file mode 100644 index 0000000..b4821e0 --- /dev/null +++ b/test/src_licenses/boost_t2.c @@ -0,0 +1 @@ +// Boost Software License - Version 1.0 - August 17th, 2003 From b06d5e51c6672014ac869c5b96256d4e05b84450 Mon Sep 17 00:00:00 2001 From: James Webber Date: Tue, 21 Apr 2009 08:09:41 +0100 Subject: [PATCH 125/387] Output of file -b for xml can contain two spaces and no version. --- lib/ohcount/detector.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index 0af8b22..29965c7 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -300,7 +300,7 @@ def self.matlab_octave_or_objective_c(source_file) matlab_signatures = /(^\s*function\s*)|(^\s*%)|(^\s*\#)/ matlab_sig_score = 0.1 * lines_matching(buffer, matlab_signatures) - # if the contents contains '//', '/*', '@interface', or '@implementation', + # if the contents contains '//', '/*', '@interface', or '@implementation', # likely objective_c objective_c_signatures = /(^\s*\/\/\s*)|(^\s*\/\*)|(^[+-])|(@interface)|(@implementation)/ obj_c_sig_score = -0.1 * lines_matching(buffer, objective_c_signatures) @@ -623,7 +623,7 @@ def self.disambiguate_nil(source_file) when "Bourne-Again" return "shell" end - when /XML( 1\.0)? document text/, /^XML$/ + when /XML( 1\.0| )? document text/, /^XML$/ return 'xml' end # dang... no dice From 5b14f8097c7210282db1c6ae2f45fe507fc617fe Mon Sep 17 00:00:00 2001 From: James Webber Date: Tue, 21 Apr 2009 08:46:30 +0100 Subject: [PATCH 126/387] Detect *.cmake, CMakeLists.txt as cmake script. --- lib/ohcount/detector.rb | 2 ++ lib/ohcount/language.rb | 1 + 2 files changed, 3 insertions(+) diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index 29965c7..1a991f3 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -141,6 +141,7 @@ def self.binary_filename?(filename) '.c' => "c", '.C' => "cpp", '.cc' => "cpp", + '.cmake' => "cmake", '.ctp' => "php", '.cpp' => "cpp", '.css' => "css", @@ -261,6 +262,7 @@ def self.binary_filename?(filename) # Map full filenames to glots. The right hand side is a string or symbol as # for EXTENSION_MAP. FILENAME_MAP = { + 'CMakeLists.txt'=> 'cmake', 'Makefile' => 'make', 'GNUmakefile' => 'make', 'makefile' => 'make', diff --git a/lib/ohcount/language.rb b/lib/ohcount/language.rb index 03adfad..eb6425f 100644 --- a/lib/ohcount/language.rb +++ b/lib/ohcount/language.rb @@ -19,6 +19,7 @@ def lang_map 'boo' => {:nice_name => 'Boo' , :category => 0}, 'c' => {:nice_name => 'C' , :category => 0}, 'classic_basic' => {:nice_name => 'Classic Basic' , :category => 0}, + 'cmake' => {:nice_name => 'Cmake script' , :category => 2}, 'cpp' => {:nice_name => 'C++' , :category => 0}, 'clearsilver' => {:nice_name => 'ClearSilver' , :category => 0}, 'csharp' => {:nice_name => 'C#' , :category => 0}, From de3bbfe4fd92db66285745aabf62eaf356339594 Mon Sep 17 00:00:00 2001 From: James Webber Date: Tue, 21 Apr 2009 08:47:15 +0100 Subject: [PATCH 127/387] Test detection mappings for cmake. --- test/detect_files/CMakeLists.txt | 2 ++ test/detect_files/foo.cmake | 3 +++ test/unit/detector_test.rb | 2 ++ 3 files changed, 7 insertions(+) create mode 100644 test/detect_files/CMakeLists.txt create mode 100644 test/detect_files/foo.cmake diff --git a/test/detect_files/CMakeLists.txt b/test/detect_files/CMakeLists.txt new file mode 100644 index 0000000..8b54100 --- /dev/null +++ b/test/detect_files/CMakeLists.txt @@ -0,0 +1,2 @@ +# A cmake build script. +add_subdirectory("blah") diff --git a/test/detect_files/foo.cmake b/test/detect_files/foo.cmake new file mode 100644 index 0000000..a84001f --- /dev/null +++ b/test/detect_files/foo.cmake @@ -0,0 +1,3 @@ +# This is a cmake file. + +project(something) diff --git a/test/unit/detector_test.rb b/test/unit/detector_test.rb index 77ab6bd..7e19632 100644 --- a/test/unit/detector_test.rb +++ b/test/unit/detector_test.rb @@ -61,6 +61,7 @@ def test_fortran_fixedfree def test_detect_polyglot assert_equal "c", do_detect("foo.c") assert_equal "c", do_detect("uses_no_cpp.h") + assert_equal "cmake", do_detect("foo.cmake") assert_equal "cpp", do_detect("uses_cpp_headers.h") assert_equal "cpp", do_detect("uses_cpp_stdlib_headers.h") assert_equal "cpp", do_detect("uses_cpp_keywords.h") @@ -114,6 +115,7 @@ def test_by_filename assert_equal "autoconf", do_detect("configure.ac") assert_equal "autoconf", do_detect("configure.in") assert_equal "automake", do_detect("Makefile.am") + assert_equal "cmake", do_detect("CMakeLists.txt") assert_equal "make", do_detect("Makefile") end From 7df9a7e321040ae2c7a6ab54dfb98f37533207f4 Mon Sep 17 00:00:00 2001 From: James Webber Date: Tue, 21 Apr 2009 11:09:23 +0100 Subject: [PATCH 128/387] Add CMake parser. --- ext/ohcount_native/ragel_parser.c | 2 + ext/ohcount_native/ragel_parsers/cmake.rl | 123 ++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 ext/ohcount_native/ragel_parsers/cmake.rl diff --git a/ext/ohcount_native/ragel_parser.c b/ext/ohcount_native/ragel_parser.c index e6060a9..269b4e1 100644 --- a/ext/ohcount_native/ragel_parser.c +++ b/ext/ohcount_native/ragel_parser.c @@ -17,6 +17,7 @@ #include "ragel_parsers/classic_basic.h" #include "ragel_parsers/clearsilver.h" #include "ragel_parsers/clearsilverhtml.h" +#include "ragel_parsers/cmake.h" #include "ragel_parsers/cs_aspx.h" #include "ragel_parsers/css.h" #include "ragel_parsers/d.h" @@ -103,6 +104,7 @@ struct language languages[] = { { "classic_basic", parse_classic_basic }, { "clearsilver", parse_clearsilver }, { "clearsilver_template", parse_cshtml }, + { "cmake", parse_cmake }, { "cpp", parse_cpp }, { "cs_aspx", parse_cs_aspx }, { "csharp", parse_csharp }, diff --git a/ext/ohcount_native/ragel_parsers/cmake.rl b/ext/ohcount_native/ragel_parsers/cmake.rl new file mode 100644 index 0000000..9e8eba9 --- /dev/null +++ b/ext/ohcount_native/ragel_parsers/cmake.rl @@ -0,0 +1,123 @@ +// cmake.rl written by James Webber, bunkerprivate@googlemail.com, based on +// shell.rl written by Mitchell Foral. mitchellcaladbolgnet +// +// From shell, I remove single quote strings and added an @code to the end +// of a double quote string in case the terminating double string is on a line +// of its own. + +/************************* Required for every parser *************************/ +#ifndef RAGEL_CMAKE_PARSER +#define RAGEL_CMAKE_PARSER + +#include "ragel_parser_macros.h" + +// the name of the language +const char *CMAKE_LANG = "cmake"; + +// the languages entities +const char *cmake_entities[] = { + "space", "comment", "string", "any" +}; + +// constants associated with the entities +enum { + CMAKE_SPACE = 0, CMAKE_COMMENT, CMAKE_STRING, CMAKE_ANY +}; + +/*****************************************************************************/ + +%%{ + machine cmake; + write data; + include common "common.rl"; + + # Line counting machine + + action cmake_ccallback { + switch(entity) { + case CMAKE_SPACE: + ls + break; + case CMAKE_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(CMAKE_LANG) + break; + case NEWLINE: + std_newline(CMAKE_LANG) + } + } + + action es { + printf("endstring\n"); + } + + cmake_comment = '#' @comment nonnewline*; + + cmake_dq_str = + '"' @enqueue @code ( + newline %{ entity = INTERNAL_NL; } %cmake_ccallback + | + ws + | + [^\r\n\f\t "\\] @code + | + '\\' nonnewline @code + )* '"' @code @commit ; + + cmake_string = cmake_dq_str; + + cmake_line := |* + spaces ${ entity = CMAKE_SPACE; } => cmake_ccallback; + cmake_comment; + cmake_string; + newline ${ entity = NEWLINE; } => cmake_ccallback; + ^space ${ entity = CMAKE_ANY; } => cmake_ccallback; + *|; + + # Entity machine + + action cmake_ecallback { + callback(CMAKE_LANG, cmake_entities[entity], cint(ts), cint(te)); + } + + cmake_comment_entity = '#' nonnewline*; + + cmake_entity := |* + space+ ${ entity = CMAKE_SPACE; } => cmake_ecallback; + cmake_comment_entity ${ entity = CMAKE_COMMENT; } => cmake_ecallback; + # TODO: see shell.rl - (what is the todo for?!) + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with cmake script code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_cmake(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int start, int end) + ) { + init + + %% write init; + cs = (count) ? cmake_en_cmake_line : cmake_en_cmake_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(CMAKE_LANG) } +} + +#endif + +/*****************************************************************************/ From 7bd09c33639b6fb4f2f98082b076880d105dc632 Mon Sep 17 00:00:00 2001 From: James Webber Date: Tue, 21 Apr 2009 11:09:42 +0100 Subject: [PATCH 129/387] Unit test cmake parser. --- test/expected_dir/cmake1.cmake | 33 +++++++++++++++++++++++++++++++++ test/src_dir/cmake1.cmake | 33 +++++++++++++++++++++++++++++++++ test/unit/parsers/cmake_test.rb | 23 +++++++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 test/expected_dir/cmake1.cmake create mode 100644 test/src_dir/cmake1.cmake create mode 100644 test/unit/parsers/cmake_test.rb diff --git a/test/expected_dir/cmake1.cmake b/test/expected_dir/cmake1.cmake new file mode 100644 index 0000000..1dd5094 --- /dev/null +++ b/test/expected_dir/cmake1.cmake @@ -0,0 +1,33 @@ +cmake comment # blah comment +cmake comment # +cmake blank +cmake code something() +cmake comment # comment +cmake code something_else() +cmake blank +cmake code long_function( +cmake comment # comment +cmake code param +cmake code ) +cmake blank +cmake code long_string(" +cmake code # looks like a comment but isn't +cmake code ") +cmake blank +cmake code long_string( +cmake code " +cmake code # looks like a comment but isn't +cmake code " +cmake code ) +cmake blank +cmake code message( +cmake code ' +cmake comment # looks like a string but isn't +cmake code ' +cmake code ) +cmake blank +cmake code message("string") +cmake blank +cmake code message( +cmake blank +cmake code ) diff --git a/test/src_dir/cmake1.cmake b/test/src_dir/cmake1.cmake new file mode 100644 index 0000000..b9eecd3 --- /dev/null +++ b/test/src_dir/cmake1.cmake @@ -0,0 +1,33 @@ +# blah comment +# + +something() +# comment +something_else() + +long_function( + # comment + param +) + +long_string(" + # looks like a comment but isn't +") + +long_string( + " + # looks like a comment but isn't + " +) + +message( + ' + # looks like a string but isn't + ' +) + +message("string") + +message( + +) diff --git a/test/unit/parsers/cmake_test.rb b/test/unit/parsers/cmake_test.rb new file mode 100644 index 0000000..9083704 --- /dev/null +++ b/test/unit/parsers/cmake_test.rb @@ -0,0 +1,23 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::CmakeTest < Ohcount::Test + + def test_comments + lb = [Ohcount::LanguageBreakdown.new("cmake", "", "#comment", 0)] + assert_equal lb, Ohcount::parse(" #comment", "cmake") + end + + def test_empty_comments + lb = [Ohcount::LanguageBreakdown.new("cmake", "","#\n", 0)] + assert_equal lb, Ohcount::parse(" #\n", "cmake") + end + + def test_comprehensive + verify_parse("cmake1.cmake") + end + + def test_comment_entities + assert_equal('#comment', entities_array(" #comment", 'cmake', :comment).first) + end + +end From 14d05c78ba52fb531286932106c57842b6ed7302 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 7 May 2009 17:34:12 -0700 Subject: [PATCH 130/387] [FIX] Clean up the mess in Objective-C/Matlab/Octave disambiguation. Fixes Ticket 299. --- lib/ohcount/detector.rb | 72 +++++++++++++++++++++++++------------------ test/detect_files/TCPSocket.m | 49 +++++++++++++++++++++++++++++ test/unit/detector_test.rb | 9 +++--- 3 files changed, 96 insertions(+), 34 deletions(-) create mode 100644 test/detect_files/TCPSocket.m diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index 1a991f3..b7503d6 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -195,7 +195,7 @@ def self.binary_filename?(filename) '.lsp' => "lisp", '.ltx' => 'tex', '.lua' => "lua", - '.m' => :matlab_octave_or_objective_c, + '.m' => :disambiguate_m, '.mf' => 'metafont', '.mk' => 'make', '.ml' => "ocaml", @@ -284,45 +284,57 @@ def self.lines_matching(buffer, re) # This is done with a weighted heuristic that # scans the *.m file contents for keywords, # and also checks for the presence of matching *.h files. - def self.matlab_octave_or_objective_c(source_file) - buffer = source_file.contents + def self.disambiguate_m(source_file) + + # A positive number means it's probably Octave/Matlab. + # A negative number means it's probably Objective-C. + total = 0 - # if there are .h files in same directory and no C or C++ source files, + # If there are .h files in same directory and no C or C++ source files, # this probably isn't Matlab(TM) or Octave. Both allow compiled extensions # that often live in the same directory, so checking .h alone does not suffice. - has_headers = source_file.filenames.select { |a| a =~ /\.h$/ }.any? - has_c_cpp = !source_file.filenames.select { |a| a =~ /\.(c|cpp|C|c\+\+|cxx|cc)$/ }.any? - h_headers = 0.0 - h_headers = -0.5 if has_headers && !has_c_cpp - - # if the contents contain 'function (' on a single line - very likely to be Octave - # or Matlab(TM). - # if the contents contain lines starting with '%' or '#', they likely are comments - # in Octave or Matlab(TM) - matlab_signatures = /(^\s*function\s*)|(^\s*%)|(^\s*\#)/ - matlab_sig_score = 0.1 * lines_matching(buffer, matlab_signatures) - - # if the contents contains '//', '/*', '@interface', or '@implementation', - # likely objective_c + total -= 5 if has_h_headers?(source_file.filenames) && !has_c_files?(source_file.filenames) + + # 'function (' is likely to be Octave or Matlab(TM). + # Lines starting with '%' or '#' are likely comments in Octave or Matlab(TM). + # Note that '#' might begin '#import', so we count it as a comment only if it + # is followed by a space. + matlab_signatures = /(^\s*function\s*\()|(^\s*%)|(^\s*\#+\s+)/ + total += lines_matching(source_file.contents, matlab_signatures) + + # '//', '/*', '@interface', or '@implementation' are likely objective_c objective_c_signatures = /(^\s*\/\/\s*)|(^\s*\/\*)|(^[+-])|(@interface)|(@implementation)/ - obj_c_sig_score = -0.1 * lines_matching(buffer, objective_c_signatures) + total -= lines_matching(source_file.contents, objective_c_signatures) - matlab = h_headers + matlab_sig_score + obj_c_sig_score + if total > 0 + disambiguate_matlab_octave(source_file) + else + 'objective_c' + end + end - if matlab > 0 - # Octave-specific keywords: endfunction, endwhile, end_try_catch, end_unwind_protect - # Also, # is only an Octave comment character. - oct_specific_sigs = /(\bend(function|while|_try_catch|unwind_protect))|(^\s*\#)/ - if lines_matching(buffer, oct_specific_sigs) > 0 - return 'octave' - else - return 'matlab' - end + def self.disambiguate_matlab_octave(source_file) + # Octave-specific keywords: endfunction, endwhile, end_try_catch, end_unwind_protect + # Also, # is only an Octave comment character. + oct_specific_sigs = /(\bend(function|while|_try_catch|unwind_protect))|(^\s*\#)/ + + if lines_matching(source_file.contents, oct_specific_sigs) > 0 + 'octave' else - return 'objective_c' + 'matlab' end end + def self.has_h_headers?(filenames) + filenames.each { |a| return true if a =~ /\.h$/ } + false + end + + def self.has_c_files?(filenames) + filenames.each { |a| return true if a =~ /\.(c|cpp|C|c\+\+|cxx|cc)$/ } + false + end + # For *.h files, differentiates C, C++ and Objective-C. # # This is done with a weighted heuristic that diff --git a/test/detect_files/TCPSocket.m b/test/detect_files/TCPSocket.m new file mode 100644 index 0000000..bb387e6 --- /dev/null +++ b/test/detect_files/TCPSocket.m @@ -0,0 +1,49 @@ +/** + * This code is free software; you can redistribute it and/or modify it under + * the terms of the new BSD License. + * + * Copyright (c) 2009, Sebastian Staudt + */ + +#import +#import + +#import "SteamCondenserException.h" +#import "TCPSocket.h" + + +@implementation TCPSocket + +-(void) connectWithHost:(NSHost*) aHost andPort:(unsigned short) aPort { + remoteHost = aHost; + remotePort = aPort; + + struct sockaddr_in remoteSocket; + remoteSocket.sin_family = AF_INET; + remoteSocket.sin_port = htons(remotePort); + NSString* address; + NSEnumerator* addressEnumerator = [[remoteHost addresses] objectEnumerator]; + while(address = [addressEnumerator nextObject]) { + if(inet_pton(AF_INET, [address cStringUsingEncoding:NSASCIIStringEncoding], &remoteSocket.sin_addr) == 1) { + break; + } + } + + fdsocket = socket(AF_INET, SOCK_STREAM, 0); + if(fdsocket < 0) { + @throw [[SteamCondenserException alloc] initWithMessage:[NSString stringWithFormat:@"Error creating socket: %s", strerror(errno)]]; + } + + if(connect(fdsocket, (struct sockaddr*) &remoteSocket, sizeof(remoteSocket)) < 0) { + @throw [[SteamCondenserException alloc] initWithMessage:[NSString stringWithFormat:@"Error connecting socket: %s", strerror(errno)]]; + } + + if(!isBlocking) { + fcntl(fdsocket, F_SETFL, O_NONBLOCK); + } + else { + fcntl(fdsocket, F_SETFL, 0); + } +} + +@end diff --git a/test/unit/detector_test.rb b/test/unit/detector_test.rb index 7e19632..9c868c8 100644 --- a/test/unit/detector_test.rb +++ b/test/unit/detector_test.rb @@ -48,9 +48,13 @@ def test_smalltalk assert_equal nil, do_detect("english.st") end - def test_matlab_or_objective_c + def test_disambiguate_m assert_equal 'objective_c', do_detect("t1.m") assert_equal 'objective_c', do_detect("t2.m") + assert_equal 'objective_c', do_detect("TCPSocket.m") + assert_equal 'objective_c', do_detect("foo_objective_c.m", ["foo_objective_c.m", "bar.h", "README"]) + assert_equal 'matlab', do_detect("foo_matlab.m", ["foo_matlab.m", "bar.m", "README"]) + assert_equal 'octave', do_detect("foo_octave.m", ["foo_octave.m", "foo_matlab.m", "bar.m", "README"]) end def test_fortran_fixedfree @@ -67,9 +71,6 @@ def test_detect_polyglot assert_equal "cpp", do_detect("uses_cpp_keywords.h") assert_equal "ruby", do_detect("foo.rb") assert_equal "make", do_detect("foo.mk") - assert_equal "matlab", do_detect("foo_matlab.m", ["foo_matlab.m", "bar.m", "README"]) - assert_equal "octave", do_detect("foo_octave.m", ["foo_octave.m", "foo_matlab.m", "bar.m", "README"]) - assert_equal "objective_c", do_detect("foo_objective_c.m", ["foo_objective_c.m", "bar.h", "README"]) assert_equal "objective_c", do_detect("foo_objective_c.h", ["foo_objective_c.h, different_than_foo.m"]) assert_equal "php", do_detect("upper_case_php") assert_equal "smalltalk", do_detect("example.st") From 174bbace0b58ef967064fb6d72a29a6fb9cbdd1b Mon Sep 17 00:00:00 2001 From: Mechiel Lukkien Date: Tue, 21 Apr 2009 14:07:51 +0200 Subject: [PATCH 131/387] add support for Limbo. it adds a parser, adjusts the detector (there is now extension clash between matlab/limbo/objective c, and another for for limbo/basic). there are also sample limbo files (in public domain) and a test. all tests pass with this. it has been tested on a large body of limbo code (mixed with C, makefile, shell, awk): http://code.google.com/p/inferno-os/ more info on Limbo: http://www.vitanuova.com/inferno/papers/limbo.html --- ext/ohcount_native/ragel_parsers/limbo.rl | 144 ++++++++++++++++++++++++++++++ test/expected_dir/limbo.b | 65 ++++++++++++++ test/expected_dir/limbo.m | 8 ++ test/src_dir/limbo.b | 65 ++++++++++++++ test/src_dir/limbo.m | 8 ++ test/unit/parsers/limbo_test.rb | 24 +++++ 6 files changed, 314 insertions(+) create mode 100644 ext/ohcount_native/ragel_parsers/limbo.rl create mode 100644 test/expected_dir/limbo.b create mode 100644 test/expected_dir/limbo.m create mode 100644 test/src_dir/limbo.b create mode 100644 test/src_dir/limbo.m create mode 100644 test/unit/parsers/limbo_test.rb diff --git a/ext/ohcount_native/ragel_parsers/limbo.rl b/ext/ohcount_native/ragel_parsers/limbo.rl new file mode 100644 index 0000000..dff11b7 --- /dev/null +++ b/ext/ohcount_native/ragel_parsers/limbo.rl @@ -0,0 +1,144 @@ +// limbo.rl +// http://www.vitanuova.com/inferno/papers/limbo.html + +/************************* Required for every parser *************************/ +#ifndef RAGEL_LIMBO_PARSER +#define RAGEL_LIMBO_PARSER + +#include "ragel_parser_macros.h" + +// the name of the language +const char *LIMBO_LANG = "limbo"; + +// the languages entities +const char *limbo_entities[] = { + "space", "comment", "string", "number", + "keyword", "identifier", "operator", "any" +}; + +// constants associated with the entities +enum { + LIMBO_SPACE = 0, LIMBO_COMMENT, LIMBO_STRING, LIMBO_NUMBER, + LIMBO_KEYWORD, LIMBO_IDENTIFIER, LIMBO_OPERATOR, LIMBO_ANY +}; + +/*****************************************************************************/ + +%%{ + machine limbo; + write data; + include common "common.rl"; + + # Line counting machine + + action limbo_ccallback { + switch(entity) { + case LIMBO_SPACE: + ls + break; + case LIMBO_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(LIMBO_LANG) + break; + case NEWLINE: + std_newline(LIMBO_LANG) + } + } + + limbo_comment = '#' @comment nonnewline*; + + limbo_sq_str = + '\'' @code ( + [^\r\n\f\t '\\] @code + | + '\\' nonnewline @code + )* '\'' @commit; + limbo_dq_str = + '"' @enqueue @code ( + [^\r\n\f\t "\\] @code + | + '\\' nonnewline @code + )* '"' @commit; + limbo_string = limbo_sq_str | limbo_dq_str; + + limbo_line := |* + spaces ${ entity = LIMBO_SPACE; } => limbo_ccallback; + limbo_comment; + limbo_string; + newline ${ entity = NEWLINE; } => limbo_ccallback; + ^space ${ entity = LIMBO_ANY; } => limbo_ccallback; + *|; + + # Entity machine + + action limbo_ecallback { + callback(LIMBO_LANG, limbo_entities[entity], cint(ts), cint(te)); + } + + limbo_comment_entity = '#' nonnewline*; + + # todo: this probably allows multi-line strings too, which limbo doesn't allow? + limbo_string_entity = sq_str_with_escapes | dq_str_with_escapes; + + # todo: support numbers with specified radix? e.g. 16rFF, 8r666, 2b10101 + limbo_number_entity = float | integer; + + # todo: support utf-8 identifiers + limbo_identifier_entity = (alpha | '_') (alnum | '_')*; + + limbo_keyword_entity = + 'alt' | 'break' | 'continue' | 'exit' | 'return' | 'spawn' | 'implement' | 'import' | 'load' | 'raise' | 'raises' + 'include' | 'array' | 'big' | 'byte' | 'chan' | 'con' | 'int' | 'list' | 'real' | 'string' | 'fn' | + 'adt' | 'pick' | 'module' | + 'for' | 'while' | 'do' | + 'if' | 'else' | 'case' | 'or' | 'to' | + '=>' | + 'ref' | 'self' | 'cyclic' | 'type' | 'of' | + 'tl' | 'hd' | 'len' | 'tagof' | + 'nil'; + + limbo_operator_entity = [+\-/*%!=^&|~:;.,()\[\]{}>]; + + limbo_entity := |* + space+ ${ entity = LIMBO_SPACE; } => limbo_ecallback; + limbo_comment_entity ${ entity = LIMBO_COMMENT; } => limbo_ecallback; + limbo_string_entity ${ entity = LIMBO_STRING; } => limbo_ecallback; + limbo_number_entity ${ entity = LIMBO_NUMBER; } => limbo_ecallback; + limbo_keyword_entity ${ entity = LIMBO_KEYWORD; } => limbo_ecallback; + limbo_identifier_entity ${ entity = LIMBO_IDENTIFIER; } => limbo_ecallback; + limbo_operator_entity ${ entity = LIMBO_OPERATOR; } => limbo_ecallback; + ^(space | digit) ${ entity = C_ANY; } => limbo_ecallback; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with Limbo code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_limbo(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int start, int end) + ) { + init + + %% write init; + cs = (count) ? limbo_en_limbo_line : limbo_en_limbo_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(LIMBO_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/test/expected_dir/limbo.b b/test/expected_dir/limbo.b new file mode 100644 index 0000000..c76e9ea --- /dev/null +++ b/test/expected_dir/limbo.b @@ -0,0 +1,65 @@ +limbo code implement HgReadrevlog; +limbo blank +limbo code include "sys.m"; +limbo code sys: Sys; +limbo code sprint: import sys; +limbo code include "draw.m"; +limbo code include "arg.m"; +limbo code include "string.m"; +limbo code str: String; +limbo code include "mercurial.m"; +limbo code mercurial: Mercurial; +limbo code Revlog, Repo, Entry, Nodeid, Change: import mercurial; +limbo blank +limbo code dflag: int; +limbo blank +limbo code HgReadrevlog: module { +limbo code init: fn(nil: ref Draw->Context, args: list of string); +limbo code }; +limbo blank +limbo code init(nil: ref Draw->Context, args: list of string) +limbo code { +limbo code sys = load Sys Sys->PATH; +limbo code arg := load Arg Arg->PATH; +limbo code str = load String String->PATH; +limbo code mercurial = load Mercurial Mercurial->PATH; +limbo code mercurial->init(); +limbo blank +limbo code arg->init(args); +limbo code arg->setusage(arg->progname()+" [-d] path"); +limbo code while((c := arg->opt()) != 0) +limbo code case c { +limbo code 'd' => dflag++; +limbo code if(dflag > 1) +limbo code mercurial->debug++; +limbo code * => arg->usage(); +limbo code } +limbo code args = arg->argv(); +limbo code if(len args != 1) +limbo code arg->usage(); +limbo code path := hd args; +limbo blank +limbo code (rl, err) := Revlog.open(path); +limbo code if(err != nil) +limbo code fail(err); +limbo blank +limbo code last: int; +limbo code (last, err) = rl.lastrev(); +limbo code if(err != nil) +limbo code fail(err); +limbo blank +limbo code e: ref Entry; +limbo code for(i := 0; i <= last; i++) { +limbo code (e, err) = rl.findrev(i); +limbo code if(err != nil) +limbo code fail(err); +limbo comment #sys->print("entry %d:\n", i); +limbo code sys->print("%s\n", e.text()); +limbo code } +limbo code } +limbo blank +limbo code fail(s: string) +limbo code { +limbo code sys->fprint(sys->fildes(2), "%s\n", s); +limbo code raise "fail:"+s; +limbo code } diff --git a/test/expected_dir/limbo.m b/test/expected_dir/limbo.m new file mode 100644 index 0000000..ae490fa --- /dev/null +++ b/test/expected_dir/limbo.m @@ -0,0 +1,8 @@ +limbo code Htmlent: module { +limbo code PATH: con "/dis/lib/htmlent.dis"; +limbo code entities: array of (string, int); +limbo blank +limbo code init: fn(); +limbo code lookup: fn(name: string): int; +limbo code conv: fn(s: string): string; +limbo code }; diff --git a/test/src_dir/limbo.b b/test/src_dir/limbo.b new file mode 100644 index 0000000..ad49168 --- /dev/null +++ b/test/src_dir/limbo.b @@ -0,0 +1,65 @@ +implement HgReadrevlog; + +include "sys.m"; + sys: Sys; + sprint: import sys; +include "draw.m"; +include "arg.m"; +include "string.m"; + str: String; +include "mercurial.m"; + mercurial: Mercurial; + Revlog, Repo, Entry, Nodeid, Change: import mercurial; + +dflag: int; + +HgReadrevlog: module { + init: fn(nil: ref Draw->Context, args: list of string); +}; + +init(nil: ref Draw->Context, args: list of string) +{ + sys = load Sys Sys->PATH; + arg := load Arg Arg->PATH; + str = load String String->PATH; + mercurial = load Mercurial Mercurial->PATH; + mercurial->init(); + + arg->init(args); + arg->setusage(arg->progname()+" [-d] path"); + while((c := arg->opt()) != 0) + case c { + 'd' => dflag++; + if(dflag > 1) + mercurial->debug++; + * => arg->usage(); + } + args = arg->argv(); + if(len args != 1) + arg->usage(); + path := hd args; + + (rl, err) := Revlog.open(path); + if(err != nil) + fail(err); + + last: int; + (last, err) = rl.lastrev(); + if(err != nil) + fail(err); + + e: ref Entry; + for(i := 0; i <= last; i++) { + (e, err) = rl.findrev(i); + if(err != nil) + fail(err); + #sys->print("entry %d:\n", i); + sys->print("%s\n", e.text()); + } +} + +fail(s: string) +{ + sys->fprint(sys->fildes(2), "%s\n", s); + raise "fail:"+s; +} diff --git a/test/src_dir/limbo.m b/test/src_dir/limbo.m new file mode 100644 index 0000000..fcd10ff --- /dev/null +++ b/test/src_dir/limbo.m @@ -0,0 +1,8 @@ +Htmlent: module { + PATH: con "/dis/lib/htmlent.dis"; + entities: array of (string, int); + + init: fn(); + lookup: fn(name: string): int; + conv: fn(s: string): string; +}; diff --git a/test/unit/parsers/limbo_test.rb b/test/unit/parsers/limbo_test.rb new file mode 100644 index 0000000..f41788d --- /dev/null +++ b/test/unit/parsers/limbo_test.rb @@ -0,0 +1,24 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class Ohcount::LimboTest < Ohcount::Test + + def test_comments + lb = [Ohcount::LanguageBreakdown.new("limbo", "", "#comment", 0)] + assert_equal lb, Ohcount::parse(" #comment", "limbo") + end + + def test_empty_comments + lb = [Ohcount::LanguageBreakdown.new("limbo", "","#\n", 0)] + assert_equal lb, Ohcount::parse(" #\n", "limbo") + end + + def test_comprehensive + verify_parse("limbo.b") + verify_parse("limbo.m") + end + + def test_comment_entities + assert_equal('#comment', entities_array(" #comment", 'limbo', :comment).first) + end + +end From 5f04972947dee41da4eefe47ccd902e2f7539f5d Mon Sep 17 00:00:00 2001 From: Mechiel Lukkien Date: Tue, 21 Apr 2009 14:15:36 +0200 Subject: [PATCH 132/387] and add the modified files too... --- ext/ohcount_native/ragel_parser.c | 2 ++ lib/ohcount/language.rb | 1 + test/unit/detector_test.rb | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ext/ohcount_native/ragel_parser.c b/ext/ohcount_native/ragel_parser.c index 269b4e1..9847c66 100644 --- a/ext/ohcount_native/ragel_parser.c +++ b/ext/ohcount_native/ragel_parser.c @@ -39,6 +39,7 @@ #include "ragel_parsers/java.h" #include "ragel_parsers/javascript.h" #include "ragel_parsers/jsp.h" +#include "ragel_parsers/limbo.h" #include "ragel_parsers/lisp.h" #include "ragel_parsers/lua.h" #include "ragel_parsers/makefile.h" @@ -129,6 +130,7 @@ struct language languages[] = { { "java", parse_java }, { "javascript", parse_javascript }, { "jsp", parse_jsp }, + { "limbo", parse_limbo }, { "lisp", parse_lisp }, { "lua", parse_lua }, { "make", parse_makefile }, diff --git a/lib/ohcount/language.rb b/lib/ohcount/language.rb index eb6425f..0cb0394 100644 --- a/lib/ohcount/language.rb +++ b/lib/ohcount/language.rb @@ -41,6 +41,7 @@ def lang_map 'html' => {:nice_name => 'HTML' , :category => 1}, 'java' => {:nice_name => 'Java' , :category => 0}, 'javascript' => {:nice_name => 'JavaScript' , :category => 0}, + 'limbo' => {:nice_name => 'Limbo' , :category => 0}, 'lisp' => {:nice_name => 'Lisp' , :category => 0}, 'lua' => {:nice_name => 'Lua' , :category => 0}, 'make' => {:nice_name => 'Make' , :category => 2}, diff --git a/test/unit/detector_test.rb b/test/unit/detector_test.rb index 7e19632..42e17e8 100644 --- a/test/unit/detector_test.rb +++ b/test/unit/detector_test.rb @@ -48,7 +48,7 @@ def test_smalltalk assert_equal nil, do_detect("english.st") end - def test_matlab_or_objective_c + def test_matlab_octave_limbo_or_objective_c assert_equal 'objective_c', do_detect("t1.m") assert_equal 'objective_c', do_detect("t2.m") end From 66aa0bb417c4bcf4e219cf14995ff8f8464133be Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 7 May 2009 18:12:47 -0700 Subject: [PATCH 133/387] [NEW] More disambiguation cleanup to support Limbo --- lib/ohcount/detector.rb | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/lib/ohcount/detector.rb b/lib/ohcount/detector.rb index b7503d6..66b4438 100644 --- a/lib/ohcount/detector.rb +++ b/lib/ohcount/detector.rb @@ -132,7 +132,7 @@ def self.binary_filename?(filename) '.aspx' => :disambiguate_aspx, '.asm' => "assembler", '.awk' => "awk", - '.b' => :disambiguate_non_visual_basic, + '.b' => :disambiguate_b, '.bas' => :disambiguate_basic, '.bat' => "bat", '.bi' => :disambiguate_non_visual_basic, @@ -279,37 +279,41 @@ def self.lines_matching(buffer, re) buffer.inject(0) { |total, line| line =~ re ? total+1 : total } end - # For *.m files, differentiates between Matlab(TM), Octave, and Objective-C. + # For *.m files, differentiates between Matlab(TM), Octave, Limbo, and Objective-C. # # This is done with a weighted heuristic that # scans the *.m file contents for keywords, # and also checks for the presence of matching *.h files. def self.disambiguate_m(source_file) - # A positive number means it's probably Octave/Matlab. - # A negative number means it's probably Objective-C. - total = 0 + # '//', '/*', '@interface', or '@implementation' are likely objective_c + objective_c_signatures = /(^\s*\/\/\s*)|(^\s*\/\*)|(^[+-])|(@interface)|(@implementation)/ + objective_c_score = lines_matching(source_file.contents, objective_c_signatures) # If there are .h files in same directory and no C or C++ source files, # this probably isn't Matlab(TM) or Octave. Both allow compiled extensions # that often live in the same directory, so checking .h alone does not suffice. - total -= 5 if has_h_headers?(source_file.filenames) && !has_c_files?(source_file.filenames) + objective_c_score += 5 if has_h_headers?(source_file.filenames) && !has_c_files?(source_file.filenames) # 'function (' is likely to be Octave or Matlab(TM). # Lines starting with '%' or '#' are likely comments in Octave or Matlab(TM). # Note that '#' might begin '#import', so we count it as a comment only if it # is followed by a space. matlab_signatures = /(^\s*function\s*\()|(^\s*%)|(^\s*\#+\s+)/ - total += lines_matching(source_file.contents, matlab_signatures) + matlab_score = lines_matching(source_file.contents, matlab_signatures) - # '//', '/*', '@interface', or '@implementation' are likely objective_c - objective_c_signatures = /(^\s*\/\/\s*)|(^\s*\/\*)|(^[+-])|(@interface)|(@implementation)/ - total -= lines_matching(source_file.contents, objective_c_signatures) + # Lines starting with # are limbo comments + # Declarations are of the form: : (with type commonly module/adt/fn(/con) + # Some .m files only have a list of includes. + limbo_signatures = /(^[ \t]*#\s)|(:[ \t]+(module|adt|fn ?\(|con[ \t]))|(^include[ \t]+"[^"]+\.m";)/ + limbo_score = lines_matching(source_file.contents, limbo_signatures) - if total > 0 - disambiguate_matlab_octave(source_file) - else + if limbo_score > objective_c_score && limbo_score > matlab_score + 'limbo' + elsif objective_c_score > matlab_score 'objective_c' + else + disambiguate_matlab_octave(source_file) end end @@ -689,5 +693,17 @@ def self.disambiguate_smalltalk(source_file) nil end + def self.disambiguate_b(source_file) + # implement and include lines are good indicators, but not always present + # return|break|continue statements, or pick & case constructs are good differentiators with basic + limbo_b_line = /(implement[ \t])|(include[ \t]+"[^"]*";)|((return|break|continue).*;|(pick|case).*\{)/ + + if lines_matching(source_file.contents, limbo_b_line) > 0 + 'limbo' + else + disambiguate_non_visual_basic(source_file) + end + end + end end From 6d68ae2c4d6f1371381ba49d9116e96c3b91a032 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 17 May 2009 14:15:44 -0400 Subject: [PATCH 134/387] Initial import of C source code. --- src/detector.c | 627 ++++++++++++++++++++++++++++ src/detector.h | 32 ++ src/diff.c | 646 ++++++++++++++++++++++++++++ src/diff.h | 20 + src/hash/cppheaders.gperf | 91 ++++ src/hash/disambiguatefuncs.gperf | 27 ++ src/hash/extensions.gperf | 176 ++++++++ src/hash/filenames.gperf | 13 + src/hash/generate_headers | 9 + src/hash/languages.gperf | 84 ++++ src/hash/options.gperf | 20 + src/hash/parsers.gperf | 159 +++++++ src/languages.h | 88 ++++ src/licenses.c | 882 +++++++++++++++++++++++++++++++++++++++ src/licenses.h | 120 ++++++ src/loc.c | 419 +++++++++++++++++++ src/loc.h | 310 ++++++++++++++ src/ohcount.c | 316 ++++++++++++++ src/ohcount.h | 129 ++++++ src/parsed_language.c | 73 ++++ src/parsed_language.h | 60 +++ src/parser.c | 27 ++ src/parser.h | 303 ++++++++++++++ src/parser_macros.h | 431 +++++++++++++++++++ src/parsers/actionscript.rl | 125 ++++++ src/parsers/ada.rl | 105 +++++ src/parsers/assembler.rl | 118 ++++++ src/parsers/autoconf.rl | 122 ++++++ src/parsers/automake.rl | 107 +++++ src/parsers/awk.rl | 107 +++++ src/parsers/bat.rl | 102 +++++ src/parsers/blitzmax.rl | 126 ++++++ src/parsers/boo.rl | 145 +++++++ src/parsers/c.rl | 216 ++++++++++ src/parsers/classic_basic.rl | 103 +++++ src/parsers/clearsilver.rl | 105 +++++ src/parsers/clearsilverhtml.rl | 239 +++++++++++ src/parsers/cmake.rl | 125 ++++++ src/parsers/common.rl | 82 ++++ src/parsers/compile | 49 +++ src/parsers/cs_aspx.rl | 241 +++++++++++ src/parsers/css.rl | 134 ++++++ src/parsers/d.rl | 179 ++++++++ src/parsers/dcl.rl | 107 +++++ src/parsers/dylan.rl | 118 ++++++ src/parsers/ebuild.rl | 108 +++++ src/parsers/eiffel.rl | 104 +++++ src/parsers/erlang.rl | 108 +++++ src/parsers/exheres.rl | 108 +++++ src/parsers/factor.rl | 105 +++++ src/parsers/fortranfixed.rl | 104 +++++ src/parsers/fortranfree.rl | 118 ++++++ src/parsers/glsl.rl | 185 ++++++++ src/parsers/groovy.rl | 141 +++++++ src/parsers/haml.rl | 219 ++++++++++ src/parsers/haskell.rl | 146 +++++++ src/parsers/haxe.rl | 125 ++++++ src/parsers/html.rl | 181 ++++++++ src/parsers/java.rl | 120 ++++++ src/parsers/javascript.rl | 136 ++++++ src/parsers/jsp.rl | 238 +++++++++++ src/parsers/limbo.rl | 146 +++++++ src/parsers/lisp.rl | 151 +++++++ src/parsers/lua.rl | 172 ++++++++ src/parsers/makefile.rl | 107 +++++ src/parsers/matlab.rl | 123 ++++++ src/parsers/metafont.rl | 106 +++++ src/parsers/metapost.rl | 106 +++++ src/parsers/metapost_with_tex.rl | 140 +++++++ src/parsers/mxml.rl | 199 +++++++++ src/parsers/nix.rl | 177 ++++++++ src/parsers/objective_c.rl | 125 ++++++ src/parsers/objective_j.rl | 126 ++++++ src/parsers/ocaml.rl | 128 ++++++ src/parsers/octave.rl | 123 ++++++ src/parsers/pascal.rl | 137 ++++++ src/parsers/perl.rl | 155 +++++++ src/parsers/php.rl | 137 ++++++ src/parsers/phphtml.rl | 238 +++++++++++ src/parsers/pike.rl | 118 ++++++ src/parsers/python.rl | 144 +++++++ src/parsers/r.rl | 109 +++++ src/parsers/rexx.rl | 130 ++++++ src/parsers/rhtml.rl | 238 +++++++++++ src/parsers/ruby.rl | 187 +++++++++ src/parsers/scala.rl | 118 ++++++ src/parsers/scilab.rl | 110 +++++ src/parsers/shell.rl | 126 ++++++ src/parsers/smalltalk.rl | 113 +++++ src/parsers/sql.rl | 128 ++++++ src/parsers/stratego.rl | 144 +++++++ src/parsers/structured_basic.rl | 104 +++++ src/parsers/tcl.rl | 121 ++++++ src/parsers/tex.rl | 102 +++++ src/parsers/vb_aspx.rl | 238 +++++++++++ src/parsers/vhdl.rl | 107 +++++ src/parsers/vim.rl | 102 +++++ src/parsers/visual_basic.rl | 105 +++++ src/parsers/xaml.rl | 125 ++++++ src/parsers/xml.rl | 127 ++++++ src/parsers/xmlschema.rl | 129 ++++++ src/parsers/xslt.rl | 127 ++++++ src/sourcefile.c | 447 ++++++++++++++++++++ src/sourcefile.h | 223 ++++++++++ src/structs.h | 339 +++++++++++++++ 105 files changed, 16720 insertions(+) create mode 100644 src/detector.c create mode 100644 src/detector.h create mode 100644 src/diff.c create mode 100644 src/diff.h create mode 100644 src/hash/cppheaders.gperf create mode 100644 src/hash/disambiguatefuncs.gperf create mode 100644 src/hash/extensions.gperf create mode 100644 src/hash/filenames.gperf create mode 100755 src/hash/generate_headers create mode 100644 src/hash/languages.gperf create mode 100644 src/hash/options.gperf create mode 100644 src/hash/parsers.gperf create mode 100644 src/languages.h create mode 100644 src/licenses.c create mode 100644 src/licenses.h create mode 100644 src/loc.c create mode 100644 src/loc.h create mode 100644 src/ohcount.c create mode 100644 src/ohcount.h create mode 100644 src/parsed_language.c create mode 100644 src/parsed_language.h create mode 100644 src/parser.c create mode 100644 src/parser.h create mode 100644 src/parser_macros.h create mode 100644 src/parsers/actionscript.rl create mode 100644 src/parsers/ada.rl create mode 100644 src/parsers/assembler.rl create mode 100644 src/parsers/autoconf.rl create mode 100644 src/parsers/automake.rl create mode 100644 src/parsers/awk.rl create mode 100644 src/parsers/bat.rl create mode 100644 src/parsers/blitzmax.rl create mode 100644 src/parsers/boo.rl create mode 100644 src/parsers/c.rl create mode 100644 src/parsers/classic_basic.rl create mode 100644 src/parsers/clearsilver.rl create mode 100644 src/parsers/clearsilverhtml.rl create mode 100644 src/parsers/cmake.rl create mode 100644 src/parsers/common.rl create mode 100755 src/parsers/compile create mode 100644 src/parsers/cs_aspx.rl create mode 100644 src/parsers/css.rl create mode 100644 src/parsers/d.rl create mode 100644 src/parsers/dcl.rl create mode 100644 src/parsers/dylan.rl create mode 100644 src/parsers/ebuild.rl create mode 100644 src/parsers/eiffel.rl create mode 100644 src/parsers/erlang.rl create mode 100644 src/parsers/exheres.rl create mode 100644 src/parsers/factor.rl create mode 100644 src/parsers/fortranfixed.rl create mode 100644 src/parsers/fortranfree.rl create mode 100644 src/parsers/glsl.rl create mode 100644 src/parsers/groovy.rl create mode 100644 src/parsers/haml.rl create mode 100644 src/parsers/haskell.rl create mode 100644 src/parsers/haxe.rl create mode 100644 src/parsers/html.rl create mode 100644 src/parsers/java.rl create mode 100644 src/parsers/javascript.rl create mode 100644 src/parsers/jsp.rl create mode 100644 src/parsers/limbo.rl create mode 100644 src/parsers/lisp.rl create mode 100644 src/parsers/lua.rl create mode 100644 src/parsers/makefile.rl create mode 100644 src/parsers/matlab.rl create mode 100644 src/parsers/metafont.rl create mode 100644 src/parsers/metapost.rl create mode 100644 src/parsers/metapost_with_tex.rl create mode 100644 src/parsers/mxml.rl create mode 100644 src/parsers/nix.rl create mode 100644 src/parsers/objective_c.rl create mode 100644 src/parsers/objective_j.rl create mode 100644 src/parsers/ocaml.rl create mode 100644 src/parsers/octave.rl create mode 100644 src/parsers/pascal.rl create mode 100644 src/parsers/perl.rl create mode 100644 src/parsers/php.rl create mode 100644 src/parsers/phphtml.rl create mode 100644 src/parsers/pike.rl create mode 100644 src/parsers/python.rl create mode 100644 src/parsers/r.rl create mode 100644 src/parsers/rexx.rl create mode 100644 src/parsers/rhtml.rl create mode 100644 src/parsers/ruby.rl create mode 100644 src/parsers/scala.rl create mode 100644 src/parsers/scilab.rl create mode 100644 src/parsers/shell.rl create mode 100644 src/parsers/smalltalk.rl create mode 100644 src/parsers/sql.rl create mode 100644 src/parsers/stratego.rl create mode 100644 src/parsers/structured_basic.rl create mode 100644 src/parsers/tcl.rl create mode 100644 src/parsers/tex.rl create mode 100644 src/parsers/vb_aspx.rl create mode 100644 src/parsers/vhdl.rl create mode 100644 src/parsers/vim.rl create mode 100644 src/parsers/visual_basic.rl create mode 100644 src/parsers/xaml.rl create mode 100644 src/parsers/xml.rl create mode 100644 src/parsers/xmlschema.rl create mode 100644 src/parsers/xslt.rl create mode 100644 src/sourcefile.c create mode 100644 src/sourcefile.h create mode 100644 src/structs.h diff --git a/src/detector.c b/src/detector.c new file mode 100644 index 0000000..f65867c --- /dev/null +++ b/src/detector.c @@ -0,0 +1,627 @@ +// detector.c written by Mitchell Foral. mitchellcaladbolg.net. +// See COPYING for license information. + +#include +#include +#include +#include + +#include "detector.h" +#include "languages.h" + +#include "hash/cppheader_hash.h" +#include "hash/disambiguatefunc_hash.h" +#include "hash/extension_hash.h" +#include "hash/filename_hash.h" +#include "hash/language_hash.h" + +#define ISAMBIGUOUS(x) (x[0] == '\1') +#define DISAMBIGUATEWHAT(x) &x[1] + +const char *ohcount_detect_language(SourceFile *sourcefile) { + const char *language = NULL; + char *p, *pe; + int length; + + // Attempt to detect based on file extension. + length = strlen(sourcefile->ext); + struct ExtensionMap *re = ohcount_hash_language_from_ext(sourcefile->ext, + length); + if (re) language = re->value; + if (language == NULL) { + // Try the lower-case version of this extension. + char lowerext[length]; + strncpy(lowerext, sourcefile->ext, length); + lowerext[length] = '\0'; + for (p = lowerext; p < lowerext + length; p++) *p = tolower(*p); + struct ExtensionMap *re = ohcount_hash_language_from_ext(lowerext, length); + if (re) return re->value; + } + if (language) { + if (ISAMBIGUOUS(language)) { + // Call the appropriate function for disambiguation. + length = strlen(DISAMBIGUATEWHAT(language)); + struct DisambiguateFuncsMap *rd = + ohcount_hash_disambiguate_func_from_id(DISAMBIGUATEWHAT(language), + length); + if (rd) return rd->value(sourcefile); + } else return language; + } + + // Attempt to detect based on filename. + length = strlen(sourcefile->filename); + struct FilenameMap *rf = + ohcount_hash_language_from_filename(sourcefile->filename, length); + if (rf) return rf->value; + + char line[81], buf[81]; + + // Attempt to detect using Emacs mode line (/^-\*-\s*mode[\s:]*\w/i). + p = ohcount_sourcefile_get_contents(sourcefile); + pe = p; + char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); + while (pe < eof) { + // Get the contents of the first line. + while (pe < eof && *pe != '\r' && *pe != '\n') pe++; + length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); + strncpy(line, p, length); + line[length] = '\0'; + if (*line == '#' && *(line + 1) == '!') { + // First line was sh-bang; loop to get contents of second line. + while (*pe == '\r' || *pe == '\n') pe++; + p = pe; + } else break; + } + for (p = line; p < line + strlen(line); p++) *p = tolower(*p); + p = strstr(line, "-*-"); + if (p) { + p += 3; + while (*p == ' ' || *p == '\t') p++; + if (strncmp(p, "mode", 4) == 0) { + p += 4; + while (*p == ' ' || *p == '\t' || *p == ':') p++; + } + pe = p; + while (isalnum(*pe)) pe++; + length = pe - p; + strncpy(buf, p, length); + buf[length] = '\0'; + struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); + if (rl) return rl->value; + } + + // Attempt to detect based on Unix 'file' command. + char *path = sourcefile->filepath; + if (sourcefile->diskpath) + path = sourcefile->diskpath; + char command[strlen(path) + 10]; + sprintf(command, "file -b '%s'", path); + FILE *f = popen(command, "r"); + if (f) { + fgets(line, sizeof(line), f); + for (p = line; p < line + strlen(line); p++) *p = tolower(*p); + p = strstr(line, "script text"); + if (p && p == line) { // /^script text(?: executable)? for \w/ + p = strstr(line, "for "); + if (p) { + p += 4; + pe = p; + while (isalnum(*pe)) pe++; + length = pe - p; + strncpy(buf, p, length); + buf[length] = '\0'; + struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); + if (rl) language = rl->value; + } + } else if (p) { // /(\w+)(?: -\w+)* script text/ + do { + p--; + pe = p; + while (*p == ' ') p--; + while (p != line && isalnum(*(p - 1))) p--; + if (*(p - 1) == '-') p--; + } while (*p == '-'); // Skip over any switches. + length = pe - p; + strncpy(buf, p, length); + buf[length] = '\0'; + struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); + if (rl) language = rl->value; + } else if (strstr(line, "xml")) language = LANG_XML; + fclose(f); + if (language) return language; + } + + return NULL; +} + +const char *disambiguate_aspx(SourceFile *sourcefile) { + char *p, *pe; + int length; + + p = ohcount_sourcefile_get_contents(sourcefile); + char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); + while (p < eof) { + // /<%@\s*Page[^>]+Language="VB"[^>]+%>/ + p = strstr(p, "<%@"); + pe = strstr(p, "%>"); + if (p && pe) { + p += 3; + length = pe - p; + char buf[length]; + strncpy(buf, p, length); + buf[length] = '\0'; + for (p = buf; p < buf + strlen(buf); p++) + *p = tolower(*p); + p = buf; + while (*p == ' ' || *p == '\t') p++; + if (strncmp(p, "page", 4) == 0) { + p += 4; + if (strstr(p, "language=\"vb\"")) + return LANG_VB_ASPX; + } + } + p++; + } + return LANG_CS_ASPX; +} + +const char *disambiguate_b(SourceFile *sourcefile) { + char *p = ohcount_sourcefile_get_contents(sourcefile); + char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); + while (p < eof) { + // /(implement[ \t])|(include[ \t]+"[^"]*";)| + // ((return|break|continue).*;|(pick|case).*\{)/ + if (strncmp(p, "implement", 9) == 0 && + (*(p + 9) == ' ' || *(p + 9) == '\t')) + return LANG_LIMBO; + else if (strncmp(p, "include", 7) == 0 && + (*(p + 7) == ' ' || *(p + 7) == '\t')) { + p += 7; + while (*p == ' ' || *p == '\t') p++; + if (*p == '"') { + while (*p != '"' && p < eof) p++; + if (*p == '"' && *(p + 1) == ';') + return LANG_LIMBO; + } + } else if (strncmp(p, "return", 6) == 0 || + strncmp(p, "break", 5) == 0 || + strncmp(p, "continue", 8) == 0) { + if (strstr(p, ";")) + return LANG_LIMBO; + } else if (strncmp(p, "pick", 4) == 0 || + strncmp(p, "case", 4) == 0) { + if (strstr(p, "{")) + return LANG_LIMBO; + } + p++; + } + return disambiguate_basic(sourcefile); +} + +const char *disambiguate_basic(SourceFile *sourcefile) { + char *p, *pe; + int length; + + // Attempt to detect based on file contents. + char line[81]; + p = ohcount_sourcefile_get_contents(sourcefile); + pe = p; + char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); + while (pe < eof) { + // Get a line at a time. + while (pe < eof && *pe != '\r' && *pe != '\n') pe++; + length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); + strncpy(line, p, length); + line[length] = '\0'; + char *line_end = pe; + + p = line; + if (isdigit(*p)) { + // /^\d+\s+\w/ + p++; + while (isdigit(*p)) p++; + if (*p == ' ' || *p == '\t') { + p++; + while (*p == ' ' || *p == '\t') p++; + if (isalnum(*p)) + return LANG_CLASSIC_BASIC; + } + } + + // Next line. + pe = line_end; + while (*pe == '\r' || *pe == '\n') pe++; + p = pe; + } + + // Attempt to detect from associated VB files in file context. + char **filenames = ohcount_sourcefile_get_filenames(sourcefile); + if (filenames) { + int i; + for (i = 0; filenames[i] != NULL; i++) { + pe = filenames[i] + strlen(filenames[i]); + p = pe; + while (p > filenames[i] && *(p - 1) != '.') p--; + length = pe - p; + if (length == 3 && + (strncmp(p, "frm", length) == 0 || + strncmp(p, "frx", length) == 0 || + strncmp(p, "vba", length) == 0 || + strncmp(p, "vbp", length) == 0 || + strncmp(p, "vbs", length) == 0)) { + return LANG_VISUALBASIC; + } + } + } + + return LANG_STRUCTURED_BASIC; +} + +const char *disambiguate_cs(SourceFile *sourcefile) { + // Attempt to detect based on file contents. + if (strstr(ohcount_sourcefile_get_contents(sourcefile), "filename); + if (strcmp(sourcefile->ext, "h") == 0) { + char path[length]; + strncpy(path, sourcefile->filename, length); + path[length] = '\0'; + *(path + length - 1) = 'm'; + char **filenames = ohcount_sourcefile_get_filenames(sourcefile); + if (filenames) { + int i; + for (i = 0; filenames[i] != NULL; i++) + if (strcmp(path, filenames[i]) == 0) + return LANG_OBJECTIVE_C; + } + } + + // Attempt to detect based on file contents. + char line[81], buf[81]; + p = ohcount_sourcefile_get_contents(sourcefile); + pe = p; + char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); + while (pe < eof) { + // Get a line at a time. + while (pe < eof && *pe != '\r' && *pe != '\n') pe++; + length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); + strncpy(line, p, length); + line[length] = '\0'; + char *line_end = pe; + + // Look for C++ headers. + if (*line == '#') { + p = line + 1; + while (*p == ' ' || *p == '\t') p++; + if (strncmp(p, "include", 7) == 0 && + (*(p + 7) == ' ' || *(p + 7) == '\t')) { + // /^#\s*include\s+[<"][^>"]+[>"]/ + p += 8; + while (*p == ' ' || *p == '\t') p++; + if (*p == '<' || *p == '"') { + // Is the header file a C++ header file? + p++; + pe = p; + while (pe < p + strlen(line) && *pe != '>' && *pe != '"') pe++; + length = pe - p; + strncpy(buf, p, length); + buf[length] = '\0'; + if (ohcount_hash_is_cppheader(buf, length)) + return LANG_CPP; + // Is the extension for the header file a C++ file? + p = pe; + while (p > line && *(p - 1) != '.') p--; + length = pe - p; + strncpy(buf, p, length); + buf[length] = '\0'; + struct ExtensionMap *re = ohcount_hash_language_from_ext(buf, length); + if (re && strcmp(re->value, LANG_CPP) == 0) + return LANG_CPP; + } + } + } + + // Look for C++ keywords. + p = line; + while (p < line + strlen(line) && *p != '\r' && *p != '\n') { + if (islower(*p) && !isalnum(*(p - 1)) && *(p - 1) != '_') { + pe = p; + while (islower(*pe)) pe++; + if (!isalnum(*pe) && *pe != '_') { + length = pe - p; + strncpy(buf, p, length); + buf[length] = '\0'; + if (strcmp(buf, "class") == 0 || + strcmp(buf, "namespace") == 0 || + strcmp(buf, "template") == 0 || + strcmp(buf, "typename") == 0) + return LANG_CPP; + } + p = pe + 1; + } else p++; + } + + // Next line. + pe = line_end; + while (*pe == '\r' || *pe == '\n') pe++; + p = pe; + } + + // Nothing to suggest C++. + return LANG_C; +} + +const char *disambiguate_in(SourceFile *sourcefile) { + char *p, *pe; + int length; + const char *language = NULL; + + p = sourcefile->filepath; + pe = p + strlen(p) - 3; + if (strstr(p, ".") <= pe) { + // Only if the filename has an extension prior to the .in + length = pe - p; + char buf[length]; + strncpy(buf, p, length); + buf[length] = '\0'; + SourceFile *undecorated = ohcount_sourcefile_new(buf); + p = ohcount_sourcefile_get_contents(sourcefile); + // The filepath without the '.in' extension does not exist on disk. The + // sourcefile->diskpath field must be set incase the detector needs to run + // 'file -b' on the file. + ohcount_sourcefile_set_diskpath(undecorated, sourcefile->filepath); + ohcount_sourcefile_set_contents(undecorated, p); + char **filenames = ohcount_sourcefile_get_filenames(sourcefile); + ohcount_sourcefile_set_filenames(undecorated, filenames); + language = ohcount_sourcefile_get_language(undecorated); + ohcount_sourcefile_free(undecorated); + } + return language; +} + +const char *disambiguate_inc(SourceFile *sourcefile) { + char *p = ohcount_sourcefile_get_contents(sourcefile); + char *eof = p + strlen(p); + while (p < eof) { + if (*p == '\0') + return BINARY; + else if (*p == '?' && strncmp(p + 1, "php", 3) == 0) + return LANG_PHP; + p++; + } + return NULL; +} + +const char *disambiguate_m(SourceFile *sourcefile) { + char *p, *pe; + int length; + + // Attempt to detect based on a weighted heuristic of file contents. + int matlab_score = 0; + int objective_c_score = 0; + int limbo_score = 0; + int octave_syntax_detected = 0; + + int i, has_h_headers = 0, has_c_files = 0; + char **filenames = ohcount_sourcefile_get_filenames(sourcefile); + if (filenames) { + for (i = 0; filenames[i] != NULL; i++) { + p = filenames[i]; + pe = p + strlen(p); + if (pe - p >= 4) { + if (*(pe - 4) == '.' && *(pe - 3) == 'c' && + ((*(pe - 2) == 'p' && *(pe - 1) == 'p') || + (*(pe - 2) == '+' && *(pe - 1) == '+') || + (*(pe - 2) == 'x' && *(pe - 1) == 'x'))) { + has_c_files = 1; + break; // short circuit + } + } else if (pe - p >= 3) { + if (*(pe - 3) == '.' && *(pe - 2) == 'c' && *(pe - 1) == 'c') { + has_c_files = 1; + break; // short circuit + } + } else if (pe - p >= 2) { + if (*(pe - 2) == '.') { + if (*(pe - 1) == 'h') + has_h_headers = 1; + else if (*(pe - 1) == 'c' || *(pe - 1) == 'C') { + has_c_files = 1; + break; // short circuit + } + } + } + } + } + if (has_h_headers && !has_c_files) + objective_c_score += 5; + + char line[81], buf[81]; + p = ohcount_sourcefile_get_contents(sourcefile); + pe = p; + char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); + while (pe < eof) { + // Get a line at a time. + while (pe < eof && *pe != '\r' && *pe != '\n') pe++; + length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); + strncpy(line, p, length); + line[length] = '\0'; + char *line_end = pe; + + // Look for tell-tale lines. + p = line; + while (*p == ' ' || *p == '\t') p++; + if (*p == '%') { // Matlab comment + matlab_score++; + } else if (*p == '#') { // Limbo or Octave comment + while (*p == '#') p++; + if (*p == ' ' || *p == '\t') { + limbo_score++; + matlab_score++; + octave_syntax_detected = 1; + } + } else if (*p == '/' && *(p + 1) == '/' || *(p + 1) == '*') { + objective_c_score++; // Objective C comment + } else if (*p == '+' || *p == '-') { // Objective C method signature + objective_c_score++; + } else if (*p == '@') { // Objective C method signature + if (strncmp(p, "@implementation", 15) == 0 || + strncmp(p, "@interface", 10) == 0) + objective_c_score++; + } else if (strncmp(p, "function", 8) == 0) { // Matlab or Octave function + p += 8; + while (*p == ' ' || *p == '\t') p++; + if (*p == '(') + matlab_score++; + } else if (strncmp(p, "include", 7) == 0) { // Limbo include + // /^include[ \t]+"[^"]+\.m";/ + p += 7; + if (*p == ' ' || *p == '\t') { + while (*p == ' ' || *p == '\t') p++; + if (*p == '"') { + while (*p != '"' && p < line + strlen(line)) p++; + if (*p == '"' && *(p - 2) == '.' && *(p - 1) == 'm') + limbo_score++; + } + } + } + + // Look for Octave keywords. + p = line; + while (p < line + strlen(line)) { + if (islower(*p) && !isalnum(*(p - 1))) { + pe = p; + while (islower(*pe) || *pe == '_') pe++; + if (!isalnum(*pe)) { + length = pe - p; + strncpy(buf, p, length); + buf[length] = '\0'; + if (strcmp(buf, "end_try_catch") == 0 || + strcmp(buf, "end_unwind_protect") == 0 || + strcmp(buf, "endfunction") == 0 || + strcmp(buf, "endwhile") == 0) + octave_syntax_detected = 1; + } + p = pe + 1; + } else p++; + } + + // Look for Limbo declarations + p = line; + while (p < line + strlen(line)) { + if (*p == ':' && (*(p + 1) == ' ' || *(p + 1) == '\t')) { + // /:[ \t]+(module|adt|fn ?\(|con[ \t])/ + p += 2; + if (strncmp(p, "module", 6) == 0 && !isalnum(*(p + 6)) || + strncmp(p, "adt", 3) == 0 && !isalnum(*(p + 3)) || + strncmp(p, "fn", 2) == 0 && + (*(p + 2) == ' ' && *(p + 3) == '(' || *(p + 2) == '(') || + strncmp(p, "con", 3) == 0 && + (*(p + 3) == ' ' || *(p + 3) == '\t')) + limbo_score++; + } else p++; + } + + // Next line. + pe = line_end; + while (*pe == '\r' || *pe == '\n') pe++; + p = pe; + } + + if (limbo_score > objective_c_score && limbo_score > matlab_score) + return LANG_LIMBO; + else if (objective_c_score > matlab_score) + return LANG_OBJECTIVE_C; + else + return octave_syntax_detected ? LANG_OCTAVE : LANG_MATLAB; +} + +const char *disambiguate_st(SourceFile *sourcefile) { + char *p, *pe; + int length; + + // Attempt to detect based on file contents. + int found_assignment = 0, found_block_start = 0, found_block_end = 0; + + char line[81]; + p = ohcount_sourcefile_get_contents(sourcefile); + pe = p; + char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); + while (pe < eof) { + // Get a line at a time. + while (p < eof && *pe != '\r' && *pe != '\n') pe++; + length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); + strncpy(line, p, length); + line[length] = '\0'; + char *line_end = pe; + + for (p = line; p < line + strlen(line); p++) { + if (*p == ':') { + p++; + while (p < line + strlen(line) && (*p == ' ' || *p == '\t')) p++; + if (*p == '=') + found_assignment = 1; + else if (*p == '[') + found_block_start = 1; + } else if (*p == ']' && *(p + 1) == '.') found_block_end = 1; + if (found_assignment && found_block_start && found_block_end) + return LANG_SMALLTALK; + } + + // Next line. + pe = line_end; + while (*pe == '\r' || *pe == '\n') pe++; + p = pe; + } + + return NULL; +} diff --git a/src/detector.h b/src/detector.h new file mode 100644 index 0000000..e63646c --- /dev/null +++ b/src/detector.h @@ -0,0 +1,32 @@ +// detector.h written by Mitchell Foral. mitchellcaladbolg.net. +// See COPYING for license information. + +#ifndef OHCOUNT_DETECTOR_H +#define OHCOUNT_DETECTOR_H + +/** + * @page detector_doc Detector Documentation + * + * @section language How to Add a New Language + * + * @li Add your language to 'src/languages.h' and 'src/hash/languages.gperf'. + * @li Update 'src/hash/extensions.gperf' to identify files that use the new + * language (or 'src/hash/filenames.gperf'). + * @li Regenerate the hash header files with 'src/hash/generate_headers'. + * @li Add your tests to 'test/unit/detector_test.h', rebuild the tests, and + * run them to confirm the detector changes. + * @li Follow the detailed instructions in the Parser Documentation. + * @li Rebuild Ohcount. + */ + +#include "sourcefile.h" + +/** + * Attempts to detect the programming language used by the given file. + * The returned pointer is used internally and must not be 'free'd. + * @param sourcefile A SourceFile created by ohcount_sourcefile_new(). + * @return pointer to a string with the detected language or NULL. + */ +const char *ohcount_detect_language(SourceFile *sourcefile); + +#endif diff --git a/src/diff.c b/src/diff.c new file mode 100644 index 0000000..399cb2d --- /dev/null +++ b/src/diff.c @@ -0,0 +1,646 @@ + +/* + * The bulk of this software is derived from Plan 9 and is thus distributed + * under the Lucent Public License, Version 1.02, reproduced below. + * + * =================================================================== + * + * Lucent Public License Version 1.02 + * + * THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS PUBLIC + * LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE + * PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + * + * 1. DEFINITIONS + * + * "Contribution" means: + * + * a. in the case of Lucent Technologies Inc. ("LUCENT"), the Original + * Program, and + * b. in the case of each Contributor, + * + * i. changes to the Program, and + * ii. additions to the Program; + * + * where such changes and/or additions to the Program were added to the + * Program by such Contributor itself or anyone acting on such + * Contributor's behalf, and the Contributor explicitly consents, in + * accordance with Section 3C, to characterization of the changes and/or + * additions as Contributions. + * + * "Contributor" means LUCENT and any other entity that has Contributed a + * Contribution to the Program. + * + * "Distributor" means a Recipient that distributes the Program, + * modifications to the Program, or any part thereof. + * + * "Licensed Patents" mean patent claims licensable by a Contributor + * which are necessarily infringed by the use or sale of its Contribution + * alone or when combined with the Program. + * + * "Original Program" means the original version of the software + * accompanying this Agreement as released by LUCENT, including source + * code, object code and documentation, if any. + * + * "Program" means the Original Program and Contributions or any part + * thereof + * + * "Recipient" means anyone who receives the Program under this + * Agreement, including all Contributors. + * + * 2. GRANT OF RIGHTS + * + * a. Subject to the terms of this Agreement, each Contributor hereby + * grants Recipient a non-exclusive, worldwide, royalty-free copyright + * license to reproduce, prepare derivative works of, publicly display, + * publicly perform, distribute and sublicense the Contribution of such + * Contributor, if any, and such derivative works, in source code and + * object code form. + * + * b. Subject to the terms of this Agreement, each Contributor hereby + * grants Recipient a non-exclusive, worldwide, royalty-free patent + * license under Licensed Patents to make, use, sell, offer to sell, + * import and otherwise transfer the Contribution of such Contributor, if + * any, in source code and object code form. The patent license granted + * by a Contributor shall also apply to the combination of the + * Contribution of that Contributor and the Program if, at the time the + * Contribution is added by the Contributor, such addition of the + * Contribution causes such combination to be covered by the Licensed + * Patents. The patent license granted by a Contributor shall not apply + * to (i) any other combinations which include the Contribution, nor to + * (ii) Contributions of other Contributors. No hardware per se is + * licensed hereunder. + * + * c. Recipient understands that although each Contributor grants the + * licenses to its Contributions set forth herein, no assurances are + * provided by any Contributor that the Program does not infringe the + * patent or other intellectual property rights of any other entity. Each + * Contributor disclaims any liability to Recipient for claims brought by + * any other entity based on infringement of intellectual property rights + * or otherwise. As a condition to exercising the rights and licenses + * granted hereunder, each Recipient hereby assumes sole responsibility + * to secure any other intellectual property rights needed, if any. For + * example, if a third party patent license is required to allow + * Recipient to distribute the Program, it is Recipient's responsibility + * to acquire that license before distributing the Program. + * + * d. Each Contributor represents that to its knowledge it has sufficient + * copyright rights in its Contribution, if any, to grant the copyright + * license set forth in this Agreement. + * + * 3. REQUIREMENTS + * + * A. Distributor may choose to distribute the Program in any form under + * this Agreement or under its own license agreement, provided that: + * + * a. it complies with the terms and conditions of this Agreement; + * + * b. if the Program is distributed in source code or other tangible + * form, a copy of this Agreement or Distributor's own license agreement + * is included with each copy of the Program; and + * + * c. if distributed under Distributor's own license agreement, such + * license agreement: + * + * i. effectively disclaims on behalf of all Contributors all warranties + * and conditions, express and implied, including warranties or + * conditions of title and non-infringement, and implied warranties or + * conditions of merchantability and fitness for a particular purpose; + * ii. effectively excludes on behalf of all Contributors all liability + * for damages, including direct, indirect, special, incidental and + * consequential damages, such as lost profits; and + * iii. states that any provisions which differ from this Agreement are + * offered by that Contributor alone and not by any other party. + * + * B. Each Distributor must include the following in a conspicuous + * location in the Program: + * + * Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights + * Reserved. + * + * C. In addition, each Contributor must identify itself as the + * originator of its Contribution in a manner that reasonably allows + * subsequent Recipients to identify the originator of the Contribution. + * Also, each Contributor must agree that the additions and/or changes + * are intended to be a Contribution. Once a Contribution is contributed, + * it may not thereafter be revoked. + * + * 4. COMMERCIAL DISTRIBUTION + * + * Commercial distributors of software may accept certain + * responsibilities with respect to end users, business partners and the + * like. While this license is intended to facilitate the commercial use + * of the Program, the Distributor who includes the Program in a + * commercial product offering should do so in a manner which does not + * create potential liability for Contributors. Therefore, if a + * Distributor includes the Program in a commercial product offering, + * such Distributor ("Commercial Distributor") hereby agrees to defend + * and indemnify every Contributor ("Indemnified Contributor") against + * any losses, damages and costs (collectively"Losses") arising from + * claims, lawsuits and other legal actions brought by a third party + * against the Indemnified Contributor to the extent caused by the acts + * or omissions of such Commercial Distributor in connection with its + * distribution of the Program in a commercial product offering. The + * obligations in this section do not apply to any claims or Losses + * relating to any actual or alleged intellectual property infringement. + * In order to qualify, an Indemnified Contributor must: a) promptly + * notify the Commercial Distributor in writing of such claim, and b) + * allow the Commercial Distributor to control, and cooperate with the + * Commercial Distributor in, the defense and any related settlement + * negotiations. The Indemnified Contributor may participate in any such + * claim at its own expense. + * + * For example, a Distributor might include the Program in a commercial + * product offering, Product X. That Distributor is then a Commercial + * Distributor. If that Commercial Distributor then makes performance + * claims, or offers warranties related to Product X, those performance + * claims and warranties are such Commercial Distributor's responsibility + * alone. Under this section, the Commercial Distributor would have to + * defend claims against the Contributors related to those performance + * claims and warranties, and if a court requires any Contributor to pay + * any damages as a result, the Commercial Distributor must pay those + * damages. + * + * 5. NO WARRANTY + * + * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS + * PROVIDED ON AN"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY + * WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY + * OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely + * responsible for determining the appropriateness of using and + * distributing the Program and assumes all risks associated with its + * exercise of rights under this Agreement, including but not limited to + * the risks and costs of program errors, compliance with applicable + * laws, damage to or loss of data, programs or equipment, and + * unavailability or interruption of operations. + * + * 6. DISCLAIMER OF LIABILITY + * + * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR + * ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING + * WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR + * DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * 7. EXPORT CONTROL + * + * Recipient agrees that Recipient alone is responsible for compliance + * with the United States export administration regulations (and the + * export control laws and regulation of any other countries). + * + * 8. GENERAL + * + * If any provision of this Agreement is invalid or unenforceable under + * applicable law, it shall not affect the validity or enforceability of + * the remainder of the terms of this Agreement, and without further + * action by the parties hereto, such provision shall be reformed to the + * minimum extent necessary to make such provision valid and enforceable. + * + * If Recipient institutes patent litigation against a Contributor with + * respect to a patent applicable to software (including a cross-claim or + * counterclaim in a lawsuit), then any patent licenses granted by that + * Contributor to such Recipient under this Agreement shall terminate as + * of the date such litigation is filed. In addition, if Recipient + * institutes patent litigation against any entity (including a + * cross-claim or counterclaim in a lawsuit) alleging that the Program + * itself (excluding combinations of the Program with other software or + * hardware) infringes such Recipient's patent(s), then such Recipient's + * rights granted under Section 2(b) shall terminate as of the date such + * litigation is filed. + * + * All Recipient's rights under this Agreement shall terminate if it + * fails to comply with any of the material terms or conditions of this + * Agreement and does not cure such failure in a reasonable period of + * time after becoming aware of such noncompliance. If all Recipient's + * rights under this Agreement terminate, Recipient agrees to cease use + * and distribution of the Program as soon as reasonably practicable. + * However, Recipient's obligations under this Agreement and any licenses + * granted by Recipient relating to the Program shall continue and + * survive. + * + * LUCENT may publish new versions (including revisions) of this + * Agreement from time to time. Each new version of the Agreement will be + * given a distinguishing version number. The Program (including + * Contributions) may always be distributed subject to the version of the + * Agreement under which it was received. In addition, after a new + * version of the Agreement is published, Contributor may elect to + * distribute the Program (including its Contributions) under the new + * version. No one other than LUCENT has the right to modify this + * Agreement. Except as expressly stated in Sections 2(a) and 2(b) above, + * Recipient receives no rights or licenses to the intellectual property + * of any Contributor under this Agreement, whether expressly, by + * implication, estoppel or otherwise. All rights in the Program not + * expressly granted under this Agreement are reserved. + * + * This Agreement is governed by the laws of the State of New York and + * the intellectual property laws of the United States of America. No + * party to this Agreement will bring a legal action under this Agreement + * more than one year after the cause of action arose. Each party waives + * its rights to a jury trial in any resulting litigation. + */ + +#include +#include + +#include "diff.h" + +struct cand { + int x; + int y; + int pred; +} cand; + +struct line { + int serial; + int value; +} *file[2], line; + +int len[2]; +struct line *sfile[2]; // shortened by pruning common prefix and suffix +int slen[2]; +int pref, suff; // length of prefix and suffix +int *class; // will be overlaid on file[0] +int *member; // will be overlaid on file[1] +int *klist; // will be overlaid on file[0] after class +struct cand *clist; // merely a free storage pot for candidates +int clen; +int *J; // will be overlaid on class + +#define HALFLONG 16 +#define low(x) (x&((1L<>HALFLONG) + +/** + * Returns a computed hash for a given string. + * Hashing has the effect of arranging line in 7-bit bytes and then summing 1-s + * complement in 16-bit hunks. + * @param line The line of a buffer to hash. + */ +static int hash(char *line) { + long sum; + unsigned shift; + char *p; + int len; + + sum = 1; + shift = 0; + len = strlen(line); + p = line; + while (len--) { + sum += (long)*p++ << (shift &= (HALFLONG-1)); + shift += 7; + } + sum = low(sum) + high(sum); + return ((short)low(sum) + (short)high(sum)); +} + +/** + * Hashes each line in the given string buffer and stores it internally. + * @param i 0 for diff 'from', 1 for diff 'to'. + * @param buf The string buffer to prepare from. + */ +void prepare(int i, const char *buf) { + struct line *p; + int j; + char bufcpy[strlen(buf)]; + char *l; + + p = malloc(3*sizeof(struct line)); + j = 0; + strncpy(bufcpy, buf, strlen(buf)); + bufcpy[strlen(buf)] = 0; + l = strtok(bufcpy, "\n"); + while (l) { + p = realloc(p, (++j+3)*sizeof(struct line)); + p[j].value = hash(l); + l = strtok(NULL, "\n"); + } + len[i] = j; + file[i] = p; +} + +/** + * Adds to the count of lines added and removed for this diff. + * Diff 'from' chunks are counted as lines removed and diff 'to' chunks are + * counted as lines added. + * @param a The diff 'from' chunk's beginning line number. + * @param b The diff 'from' chunk's ending line number. + * @param c The diff 'to' chunk's beginning line number. + * @param d The diff 'to' chunk's ending line number. + * @param added Int pointer to the running number of lines added for this diff. + * @param removed Int pointer to the running number of lines removed for this + * diff. + */ +void change(int a, int b, int c, int d, int *added, int *removed) { + if (a > b && c > d) + return; + + if(a <= 1) + a = 1; + if(b > len[0]) + b = len[0]; + if(a <= b) + *removed += b - a + 1; + + if(c <= 1) + c = 1; + if(d > len[1]) + d = len[1]; + if(c <= d) + *added += d - c + 1; +} + +/* + * diff - differential file comparison + * + * Uses an algorithm due to Harold Stone, which finds + * a pair of longest identical subsequences in the two + * files. + * + * The major goal is to generate the match vector J. + * J[i] is the index of the line in file1 corresponding + * to line i file0. J[i] = 0 if there is no + * such line in file1. + * + * Lines are hashed so as to work in core. All potential + * matches are located by sorting the lines of each file + * on the hash (called value). In particular, this + * collects the equivalence classes in file1 together. + * Subroutine equiv replaces the value of each line in + * file0 by the index of the first element of its + * matching equivalence in (the reordered) file1. + * To save space equiv squeezes file1 into a single + * array member in which the equivalence classes + * are simply concatenated, except that their first + * members are flagged by changing sign. + * + * Next the indices that point into member are unsorted into + * array class according to the original order of file0. + * + * The cleverness lies in routine stone. This marches + * through the lines of file0, developing a vector klist + * of "k-candidates". At step i a k-candidate is a matched + * pair of lines x,y (x in file0 y in file1) such that + * there is a common subsequence of lenght k + * between the first i lines of file0 and the first y + * lines of file1, but there is no such subsequence for + * any smaller y. x is the earliest possible mate to y + * that occurs in such a subsequence. + * + * Whenever any of the members of the equivalence class of + * lines in file1 matable to a line in file0 has serial number + * less than the y of some k-candidate, that k-candidate + * with the smallest such y is replaced. The new + * k-candidate is chained (via pred) to the current + * k-1 candidate so that the actual subsequence can + * be recovered. When a member has serial number greater + * that the y of all k-candidates, the klist is extended. + * At the end, the longest subsequence is pulled out + * and placed in the array J by unravel. + * + * With J in hand, the matches there recorded are + * check'ed against reality to assure that no spurious + * matches have crept in due to hashing. If they have, + * they are broken, and "jackpot " is recorded--a harmless + * matter except that a true match for a spuriously + * mated line may now be unnecessarily reported as a change. + * + * Much of the complexity of the program comes simply + * from trying to minimize core utilization and + * maximize the range of doable problems by dynamically + * allocating what is needed and reusing what is not. + * The core requirements for problems larger than somewhat + * are (in words) 2*length(file0) + length(file1) + + * 3*(number of k-candidates installed), typically about + * 6n words for files of length n. + */ + +static void sort(struct line *a, int n) { /*shellsort CACM #201*/ + int m; + struct line *ai, *aim, *j, *k; + struct line w; + int i; + + m = 0; + for (i = 1; i <= n; i *= 2) + m = 2*i - 1; + for (m /= 2; m != 0; m /= 2) { + k = a+(n-m); + for (j = a+1; j <= k; j++) { + ai = j; + aim = ai+m; + do { + if (aim->value > ai->value || + aim->value == ai->value && + aim->serial > ai->serial) + break; + w = *ai; + *ai = *aim; + *aim = w; + + aim = ai; + ai -= m; + } while (ai > a && aim >= ai); + } + } +} + +static void unsort(struct line *f, int l, int *b) { + int *a; + int i; + + a = malloc((l+1)*sizeof(int)); + for(i=1;i<=l;i++) + a[f[i].serial] = f[i].value; + for(i=1;i<=l;i++) + b[i] = a[i]; + free(a); +} + +static void prune(void) { + int i, j; + + for(pref=0;prefx = x; + q->y = y; + q->pred = pred; + return clen++; +} + +static int search(int *c, int k, int y) { + int i, j, l; + int t; + + if(clist[c[k]].y < y) /*quick look for typical case*/ + return k+1; + i = 0; + j = k+1; + while((l=(i+j)/2) > i) { + t = clist[c[l]].y; + if(t > y) + j = l; + else if(t < y) + i = l; + else + return l; + } + return l+1; +} + +static int stone(int *a, int n, int *b, int *c) { + int i, k, y; + int j, l; + int oldc, tc; + int oldl; + + k = 0; + c[0] = newcand(0,0,0); + for(i=1; i<=n; i++) { + j = a[i]; + if(j==0) + continue; + y = -b[j]; + oldl = 0; + oldc = c[0]; + do { + if(y <= clist[oldc].y) + continue; + l = search(c, k, y); + if(l!=oldl+1) + oldc = c[l-1]; + if(l<=k) { + if(clist[c[l]].y <= y) + continue; + tc = c[l]; + c[l] = newcand(i,y,oldc); + oldc = tc; + oldl = l; + } else { + c[l] = newcand(i,y,oldc); + k++; + break; + } + } while((y=b[++j]) > 0); + } + return k; +} + +static void unravel(int p) { + int i; + struct cand *q; + + for(i=0; i<=len[0]; i++) { + if (i <= pref) + J[i] = i; + else if (i > len[0]-suff) + J[i] = i+len[1]-len[0]; + else + J[i] = 0; + } + for(q=clist+p;q->y!=0;q=clist+q->pred) + J[q->x+pref] = q->y+pref; +} + +static void output(int *added, int *removed) { + int m, i0, i1, j0, j1; + + m = len[0]; + J[0] = 0; + J[m+1] = len[1]+1; + for (i0 = 1; i0 <= m; i0 = i1+1) { + while (i0 <= m && J[i0] == J[i0-1]+1) + i0++; + j0 = J[i0-1]+1; + i1 = i0-1; + while (i1 < m && J[i1+1] == 0) + i1++; + j1 = J[i1+1]-1; + J[i1] = j1; + change(i0, i1, j0, j1, added, removed); + } + if (m == 0) + change(1, 0, 1, len[1], added, removed); +} + +void ohcount_calc_diff(const char *from, const char *to, int *added, + int *removed) { + int k; + + prepare(0, from); + prepare(1, to); + clen = 0; + prune(); + sort(sfile[0], slen[0]); + sort(sfile[1], slen[1]); + + member = (int *)file[1]; + equiv(sfile[0], slen[0], sfile[1], slen[1], member); + member = realloc(member, (slen[1]+2)*sizeof(int)); + + class = (int *)file[0]; + unsort(sfile[0], slen[0], class); + class = realloc(class, (slen[0]+2)*sizeof(int)); + + klist = malloc((slen[0]+2)*sizeof(int)); + clist = malloc(sizeof(struct cand)); + k = stone(class, slen[0], member, klist); + free(member); + free(class); + + J = malloc((len[0]+2)*sizeof(int)); + unravel(klist[k]); + free(clist); + free(klist); + + *added = *removed = 0; + output(added, removed); + free(J); +} diff --git a/src/diff.h b/src/diff.h new file mode 100644 index 0000000..44739a4 --- /dev/null +++ b/src/diff.h @@ -0,0 +1,20 @@ +// diff.h written by Mitchell Foral. mitchellcaladbolg.net. +// See COPYING for license information. + +#ifndef OHCOUNT_DIFF_H +#define OHCOUNT_DIFF_H + +/** + * Computes the diff between the lines of two given string buffers. + * The results are stored in the passed integer pointers. + * Note: The algorithm discussed mentions a check being performed to find lines + * matched incorrectly due to hashing; it is not in this implementation. + * @param from The diff 'from' buffer. + * @param to The diff 'to' buffer. + * @param added Int pointer the number of lines added result is stored to. + * @param removed Int pointer the number of lines removed result is stored to. + */ +void ohcount_calc_diff(const char *from, const char *to, int *added, + int *removed); + +#endif diff --git a/src/hash/cppheaders.gperf b/src/hash/cppheaders.gperf new file mode 100644 index 0000000..3a70930 --- /dev/null +++ b/src/hash/cppheaders.gperf @@ -0,0 +1,91 @@ +struct CppHeaderMap { const char *key; int value; }; +%% +algorithm, 1 +array, 1 +bitset, 1 +cassert, 1 +ccomplex, 1 +cctype, 1 +cerrno, 1 +cfenv, 1 +cfloat, 1 +cinttypes, 1 +ciso646, 1 +climits, 1 +clocale, 1 +cmath, 1 +csetjmp, 1 +csignal, 1 +cstdarg, 1 +cstdbool, 1 +cstddef, 1 +cstdint, 1 +cstdio, 1 +cstdlib, 1 +cstring, 1 +ctgmath, 1 +ctime, 1 +cwchar, 1 +cwctype, 1 +deque, 1 +exception, 1 +fstream, 1 +functional, 1 +iomanip, 1 +ios, 1 +iosfwd, 1 +iostream, 1 +istream, 1 +iterator, 1 +limits, 1 +list, 1 +locale, 1 +map, 1 +memory, 1 +new, 1 +numeric, 1 +ostream, 1 +queue, 1 +random, 1 +regex, 1 +set, 1 +sstream, 1 +stack, 1 +stdexcept, 1 +streambuf, 1 +string, 1 +system_error, 1 +tuple, 1 +type_traits, 1 +typeinfo, 1 +unordered_map, 1 +unordered_set, 1 +utility, 1 +valarray, 1 +vector, 1 +tr1/array, 1 +tr1/ccomplex, 1 +tr1/cctype, 1 +tr1/cfenv, 1 +tr1/cfloat, 1 +tr1/cinttypes, 1 +tr1/climits, 1 +tr1/cmath, 1 +tr1/complex, 1 +tr1/cstdarg, 1 +tr1/cstdbool, 1 +tr1/cstdint, 1 +tr1/cstdio, 1 +tr1/cstdlib, 1 +tr1/ctgmath, 1 +tr1/ctime, 1 +tr1/cwchar, 1 +tr1/cwctype, 1 +tr1/memory, 1 +tr1/random, 1 +tr1/regex, 1 +tr1/tuple, 1 +tr1/type_traits, 1 +tr1/unordered_map, 1 +tr1/unordered_set, 1 +tr1/utility, 1 diff --git a/src/hash/disambiguatefuncs.gperf b/src/hash/disambiguatefuncs.gperf new file mode 100644 index 0000000..1bd1a6b --- /dev/null +++ b/src/hash/disambiguatefuncs.gperf @@ -0,0 +1,27 @@ +%{ +#include "../detector.h" +#include "../sourcefile.h" + +const char *disambiguate_aspx(SourceFile *sourcefile); +const char *disambiguate_b(SourceFile *sourcefile); +const char *disambiguate_basic(SourceFile *sourcefile); +const char *disambiguate_cs(SourceFile *sourcefile); +const char *disambiguate_fortran(SourceFile *sourcefile); +const char *disambiguate_h(SourceFile *sourcefile); +const char *disambiguate_in(SourceFile *sourcefile); +const char *disambiguate_inc(SourceFile *sourcefile); +const char *disambiguate_m(SourceFile *sourcefile); +const char *disambiguate_st(SourceFile *sourcefile); +%} +struct DisambiguateFuncsMap { const char *key; const char* (*value)(SourceFile*); }; +%% +aspx, disambiguate_aspx +b, disambiguate_b +basic, disambiguate_basic +cs, disambiguate_cs +fortran, disambiguate_fortran +h, disambiguate_h +in, disambiguate_in +inc, disambiguate_inc +m, disambiguate_m +st, disambiguate_st diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf new file mode 100644 index 0000000..46c0ac7 --- /dev/null +++ b/src/hash/extensions.gperf @@ -0,0 +1,176 @@ +%{ +#include "../languages.h" +#define BINARY NULL +#define DISAMBIGUATE(x) ("\1" x) +%} +struct ExtensionMap { const char *key; const char *value; }; +%% +C, LANG_CPP +H, LANG_CPP +ada, LANG_ADA +adb, LANG_ADA +ads, LANG_ADA +aiff, BINARY +as, LANG_ACTIONSCRIPT +ascx, DISAMBIGUATE("aspx") +asm, LANG_ASSEMBLER +aspx, DISAMBIGUATE("aspx") +au, BINARY +avi, BINARY +awk, LANG_AWK +b, DISAMBIGUATE("b") +bas, DISAMBIGUATE("basic") +bat, LANG_BAT +bi, DISAMBIGUATE("basic") +bmp, BINARY +bmx, LANG_BLITZMAX +boo, LANG_BOO +c, LANG_C +c++, LANG_CPP +cache, BINARY +cc, LANG_CPP +cmake, LANG_CMAKE +com, LANG_DCL +cpp, LANG_CPP +cs, DISAMBIGUATE("cs") +css, LANG_CSS +ctp, LANG_PHP +cxx, LANG_CPP +d, LANG_DMD +dat, BINARY +di, LANG_DMD +doc, BINARY +dylan, LANG_DYLAN +e, LANG_EIFFEL +ebuild, LANG_EBUILD +eclass, LANG_EBUILD +el, LANG_EMACSLISP +erl, LANG_ERLANG +exheres-0, LANG_EXHERES +exlib, LANG_EXHERES +f, DISAMBIGUATE("fortran") +f03, DISAMBIGUATE("fortran") +f77, DISAMBIGUATE("fortran") +f90, DISAMBIGUATE("fortran") +f95, DISAMBIGUATE("fortran") +factor, LANG_FACTOR +frag, LANG_GLSL +frm, LANG_VISUALBASIC +frx, LANG_VISUALBASIC +ftn, DISAMBIGUATE("fortran") +gif, BINARY +glsl, LANG_GLSL +groovy, LANG_GROOVY +gz, BINARY +h, DISAMBIGUATE("h") +h++, LANG_CPP +haml, LANG_HAML +hh, LANG_CPP +hpp, LANG_CPP +hrl, LANG_ERLANG +hs, LANG_HASKELL +htm, LANG_HTML +html, LANG_HTML +hx, LANG_HAXE +hxx, LANG_CPP +icns, BINARY +in, DISAMBIGUATE("in") +inc, DISAMBIGUATE("inc") +j, LANG_OBJECTIVE_J +jar, BINARY +java, LANG_JAVA +jpeg, BINARY +jpg, BINARY +js, LANG_JAVASCRIPT +jsp, LANG_JSP +kdebuild-1, LANG_EBUILD +latex, LANG_TEX +lisp, LANG_LISP +lsp, LANG_LISP +ltx, LANG_TEX +lua, LANG_LUA +m, DISAMBIGUATE("m") +m4a, BINARY +mf, LANG_METAFONT +mk, LANG_MAKE +ml, LANG_OCAML +mli, LANG_OCAML +mm, LANG_OBJECTIVE_C +mov, BINARY +mp, LANG_METAPOST_WITH_TEX +mp3, BINARY +mpg, BINARY +mxml, LANG_MXML +nix, LANG_NIX +nse, LANG_LUA +ogg, BINARY +p6, LANG_PERL +pas, LANG_PASCAL +perl, LANG_PERL +pdf, BINARY +ph, LANG_PERL +php, LANG_PHP +php3, LANG_PHP +php4, LANG_PHP +php5, LANG_PHP +pike, LANG_PIKE +pl, LANG_PERL +pm, LANG_PERL +pmc, LANG_C +pmod, LANG_PIKE +png, BINARY +pnt, BINARY +pod, LANG_PERL +pp, LANG_PASCAL +ppt, BINARY +py, LANG_PYTHON +qt, BINARY +r, LANG_R +ra, BINARY +rb, LANG_RUBY +rex, LANG_REXX +rexx, LANG_REXX +rhtml, LANG_RHTML +s, LANG_ASSEMBLER +sc, LANG_SCHEME +scala, LANG_SCALA +sce, LANG_SCILAB +sci, LANG_SCILAB +scm, LANG_SCHEME +sh, LANG_SHELL +sls, LANG_SCHEME +sps, LANG_SCHEME +sql, LANG_SQL +ss, LANG_SCHEME +st, DISAMBIGUATE("st") +str, LANG_STRATEGO +svg, BINARY +svgz, BINARY +svn, BINARY +swf, BINARY +t, LANG_PERL +tar, BINARY +tcl, LANG_TCL +tex, LANG_TEX +tgz, BINARY +tif, BINARY +tiff, BINARY +tpl, LANG_HTML +vala, LANG_VALA +vb, LANG_VISUALBASIC +vba, LANG_VISUALBASIC +vbs, LANG_VISUALBASIC +vert, LANG_GLSL +vhd, LANG_VHDL +vhdl, LANG_VHDL +vim, LANG_VIM +wav, BINARY +xaml, LANG_XAML +xls, BINARY +xlw, BINARY +xml, LANG_XML +xs, LANG_C +xsd, LANG_XMLSCHEMA +xsl, LANG_XSLT +z80, LANG_ASSEMBLER +zip, BINARY diff --git a/src/hash/filenames.gperf b/src/hash/filenames.gperf new file mode 100644 index 0000000..54b1685 --- /dev/null +++ b/src/hash/filenames.gperf @@ -0,0 +1,13 @@ +%{ +#include "../languages.h" +%} +struct FilenameMap { const char *key; const char *value; }; +%% +CMakeLists.txt, LANG_CMAKE +GNUmakefile, LANG_MAKE +Makefile, LANG_MAKE +Makefile.am, LANG_AUTOMAKE +configure, LANG_AUTOCONF +configure.ac, LANG_AUTOCONF +configure.in, LANG_AUTOCONF +makefile, LANG_MAKE diff --git a/src/hash/generate_headers b/src/hash/generate_headers new file mode 100755 index 0000000..06fe011 --- /dev/null +++ b/src/hash/generate_headers @@ -0,0 +1,9 @@ +#!/bin/sh + +gperf -L ANSI-C -E -D -K key -H ohcount_hash_language -N ohcount_hash_language_from_name -t languages.gperf > language_hash.h +gperf -L ANSI-C -E -D -K key -H ohcount_hash_extension -N ohcount_hash_language_from_ext -t extensions.gperf > extension_hash.h +gperf -L ANSI-C -E -D -K key -H ohcount_hash_filename -N ohcount_hash_language_from_filename -t filenames.gperf > filename_hash.h +gperf -L ANSI-C -E -D -K key -H ohcount_hash_disambiguatefunc -N ohcount_hash_disambiguate_func_from_id -t disambiguatefuncs.gperf > disambiguatefunc_hash.h +gperf -L ANSI-C -E -D -K key -H ohcount_hash_cppheader -N ohcount_hash_is_cppheader -t cppheaders.gperf > cppheader_hash.h +gperf -L ANSI-C -E -D -K key -H ohcount_hash_parser -N ohcount_hash_parser_from_language -t parsers.gperf > parser_hash.h +gperf -L ANSI-C -E -D -K key -H ohcount_hash_options -N ohcount_hash_command_from_flag -t options.gperf > option_hash.h diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf new file mode 100644 index 0000000..ed746e6 --- /dev/null +++ b/src/hash/languages.gperf @@ -0,0 +1,84 @@ +%{ +#include "../languages.h" +%} +struct LanguageMap { const char *key; const char *value; }; +%% +actionscript, LANG_ACTIONSCRIPT +ada, LANG_ADA +assembler, LANG_ASSEMBLER +autoconf, LANG_AUTOCONF +automake, LANG_AUTOMAKE +awk, LANG_AWK +bat, LANG_BAT +blitzmax, LANG_BLITZMAX +boo, LANG_BOO +c, LANG_C +classic_basic, LANG_CLASSIC_BASIC +clearsilver, LANG_CLEARSILVER +clearsilver_template, LANG_CLEARSILVER_TEMPLATE +cpp, LANG_CPP +cs_aspx, LANG_CS_ASPX +csharp, LANG_CSHARP +css, LANG_CSS +dcl, LANG_DCL +dmd, LANG_DMD +dylan, LANG_DYLAN +ebuild, LANG_EBUILD +eiffel, LANG_EIFFEL +erlang, LANG_ERLANG +exheres, LANG_EXHERES +emacslisp, LANG_EMACSLISP +factor, LANG_FACTOR +fortranfixed, LANG_FORTRANFIXED +fortranfree, LANG_FORTRANFREE +glsl, LANG_GLSL +groovy, LANG_GROOVY +haskell, LANG_HASKELL +haml, LANG_HAML +haxe, LANG_HAXE +html, LANG_HTML +java, LANG_JAVA +javascript, LANG_JAVASCRIPT +jsp, LANG_JSP +limbo, LANG_LIMBO +lisp, LANG_LISP +lua, LANG_LUA +make, LANG_MAKE +matlab, LANG_MATLAB +metafont, LANG_METAFONT +metapost, LANG_METAPOST +metapost_with_tex, LANG_METAPOST_WITH_TEX +mxml, LANG_MXML +nix, LANG_NIX +objective_c, LANG_OBJECTIVE_C +objective_j, LANG_OBJECTIVE_J +ocaml, LANG_OCAML +octave, LANG_OCTAVE +pascal, LANG_PASCAL +perl, LANG_PERL +php, LANG_PHP +pike, LANG_PIKE +python, LANG_PYTHON +r, LANG_R +rexx, LANG_REXX +rhtml, LANG_RHTML +ruby, LANG_RUBY +scala, LANG_SCALA +scheme, LANG_SCHEME +scilab, LANG_SCILAB +shell, LANG_SHELL +smalltalk, LANG_SMALLTALK +stratego, LANG_STRATEGO +structured_basic, LANG_STRUCTURED_BASIC +sql, LANG_SQL +tcl, LANG_TCL +tex, LANG_TEX +vala, LANG_VALA +vb_aspx, LANG_VB_ASPX +vhdl, LANG_VHDL +vim, LANG_VIM +visualbasic, LANG_VISUALBASIC +xaml, LANG_XAML +xml, LANG_XML +xslt, LANG_XSLT +xmlschema, LANG_XMLSCHEMA diff --git a/src/hash/options.gperf b/src/hash/options.gperf new file mode 100644 index 0000000..4df3769 --- /dev/null +++ b/src/hash/options.gperf @@ -0,0 +1,20 @@ +%{ +#include "../ohcount.h" +%} +struct OhcountOption { const char *key; int value; }; +%% +-a, COMMAND_ANNOTATE +--annotate, COMMAND_ANNOTATE +-d, COMMAND_DETECT +--detect, COMMAND_DETECT +-h, COMMAND_HELP +--help, COMMAND_HELP +-g, COMMAND_GESTALT +--gestalt, COMMAND_GESTALT +-i, COMMAND_INDIVIDUAL +--individual, COMMAND_INDIVIDUAL +-l, COMMAND_LICENSES +--license, COMMAND_LICENSES +-re, COMMAND_RAWENTITIES +-s, COMMAND_SUMMARY +--summary, COMMAND_SUMMARY diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf new file mode 100644 index 0000000..a16792c --- /dev/null +++ b/src/hash/parsers.gperf @@ -0,0 +1,159 @@ +%{ +#include "../parsers/actionscript.h" +#include "../parsers/ada.h" +#include "../parsers/assembler.h" +#include "../parsers/autoconf.h" +#include "../parsers/automake.h" +#include "../parsers/awk.h" +#include "../parsers/bat.h" +#include "../parsers/blitzmax.h" +#include "../parsers/boo.h" +#include "../parsers/c.h" +#include "../parsers/classic_basic.h" +#include "../parsers/clearsilver.h" +#include "../parsers/clearsilverhtml.h" +#include "../parsers/cmake.h" +#include "../parsers/cs_aspx.h" +#include "../parsers/css.h" +#include "../parsers/d.h" +#include "../parsers/dcl.h" +#include "../parsers/dylan.h" +#include "../parsers/ebuild.h" +#include "../parsers/eiffel.h" +#include "../parsers/erlang.h" +#include "../parsers/exheres.h" +#include "../parsers/factor.h" +#include "../parsers/fortranfixed.h" +#include "../parsers/fortranfree.h" +#include "../parsers/glsl.h" +#include "../parsers/groovy.h" +#include "../parsers/haml.h" +#include "../parsers/haskell.h" +#include "../parsers/haxe.h" +#include "../parsers/html.h" +#include "../parsers/java.h" +#include "../parsers/javascript.h" +#include "../parsers/jsp.h" +#include "../parsers/lisp.h" +#include "../parsers/limbo.h" +#include "../parsers/lua.h" +#include "../parsers/makefile.h" +#include "../parsers/matlab.h" +#include "../parsers/metafont.h" +#include "../parsers/metapost.h" +#include "../parsers/metapost_with_tex.h" +#include "../parsers/mxml.h" +#include "../parsers/nix.h" +#include "../parsers/objective_c.h" +#include "../parsers/objective_j.h" +#include "../parsers/ocaml.h" +#include "../parsers/octave.h" +#include "../parsers/pascal.h" +#include "../parsers/perl.h" +#include "../parsers/phphtml.h" +#include "../parsers/pike.h" +#include "../parsers/python.h" +#include "../parsers/r.h" +#include "../parsers/rexx.h" +#include "../parsers/ruby.h" +#include "../parsers/rhtml.h" +#include "../parsers/scala.h" +#include "../parsers/scilab.h" +#include "../parsers/shell.h" +#include "../parsers/smalltalk.h" +#include "../parsers/stratego.h" +#include "../parsers/structured_basic.h" +#include "../parsers/sql.h" +#include "../parsers/tcl.h" +#include "../parsers/tex.h" +#include "../parsers/vb_aspx.h" +#include "../parsers/vhdl.h" +#include "../parsers/vim.h" +#include "../parsers/visual_basic.h" +#include "../parsers/xaml.h" +#include "../parsers/xml.h" +#include "../parsers/xslt.h" +#include "../parsers/xmlschema.h" +%} +struct ParserMap { const char *key; void (*parser)(char *, int, int, void(*) (const char *, const char *, int, int, void *), void *); }; +%% +actionscript, parse_actionscript +ada, parse_ada +assembler, parse_assembler +autoconf, parse_autoconf +automake, parse_automake +awk, parse_awk +bat, parse_bat +blitzmax, parse_blitzmax +boo, parse_boo +c, parse_c +cmake, parse_cmake +classic_basic, parse_classic_basic +clearsilver, parse_clearsilver +clearsilver_template, parse_cshtml +cpp, parse_cpp +cs_aspx, parse_cs_aspx +csharp, parse_csharp +css, parse_css +dcl, parse_dcl +dmd, parse_d +dylan, parse_dylan +ebuild, parse_ebuild +eiffel, parse_eiffel +erlang, parse_erlang +exheres, parse_exheres +emacslisp, parse_emacslisp +factor, parse_factor +fortranfixed, parse_fortranfixed +fortranfree, parse_fortranfree +glsl, parse_glsl +groovy, parse_groovy +haskell, parse_haskell +haml, parse_haml +haxe, parse_haxe +html, parse_html +java, parse_java +javascript, parse_javascript +jsp, parse_jsp +lisp, parse_lisp +limbo, parse_limbo +lua, parse_lua +make, parse_makefile +matlab, parse_matlab +metafont, parse_metafont +metapost, parse_metapost +metapost_with_tex, parse_mptex +mxml, parse_mxml +nix, parse_nix +objective_c, parse_objective_c +objective_j, parse_objective_j +ocaml, parse_ocaml +octave, parse_octave +pascal, parse_pascal +perl, parse_perl +php, parse_phtml +pike, parse_pike +python, parse_python +r, parse_r +rexx, parse_rexx +rhtml, parse_rhtml +ruby, parse_ruby +scala, parse_scala +scheme, parse_scheme +scilab, parse_scilab +shell, parse_shell +smalltalk, parse_smalltalk +stratego, parse_stratego +structured_basic, parse_structured_basic +sql, parse_sql +tcl, parse_tcl +tex, parse_tex +vala, parse_vala +vb_aspx, parse_vb_aspx +vhdl, parse_vhdl +vim, parse_vim +visualbasic, parse_visual_basic +xaml, parse_xaml +xml, parse_xml +xslt, parse_xslt +xmlschema, parse_xmlschema diff --git a/src/languages.h b/src/languages.h new file mode 100644 index 0000000..0a3a569 --- /dev/null +++ b/src/languages.h @@ -0,0 +1,88 @@ +// languages.h written by Mitchell Foral. mitchellcaladbolg.net. +// See COPYING for license information. + +#ifndef OHCOUNT_LANGUAGES_H +#define OHCOUNT_LANGUAGES_H + +#define LANG_ACTIONSCRIPT "actionscript" +#define LANG_ADA "ada" +#define LANG_ASSEMBLER "assembler" +#define LANG_AUTOCONF "autoconf" +#define LANG_AUTOMAKE "automake" +#define LANG_AWK "awk" +#define LANG_BAT "bat" +#define LANG_BLITZMAX "blitzmax" +#define LANG_BOO "boo" +#define LANG_C "c" +#define LANG_CLASSIC_BASIC "classic_basic" +#define LANG_CLEARSILVER "clearsilver" +#define LANG_CLEARSILVER_TEMPLATE "clearsilver_template" +#define LANG_CMAKE "cmake" +#define LANG_CPP "cpp" +#define LANG_CS_ASPX "cs_aspx" +#define LANG_CSHARP "csharp" +#define LANG_CSS "css" +#define LANG_DCL "dcl" +#define LANG_DMD "dmd" +#define LANG_DYLAN "dylan" +#define LANG_EBUILD "ebuild" +#define LANG_EIFFEL "eiffel" +#define LANG_ERLANG "erlang" +#define LANG_EXHERES "exheres" +#define LANG_EMACSLISP "emacslisp" +#define LANG_FACTOR "factor" +#define LANG_FORTRANFIXED "fortranfixed" +#define LANG_FORTRANFREE "fortranfree" +#define LANG_GLSL "glsl" +#define LANG_GROOVY "groovy" +#define LANG_HASKELL "haskell" +#define LANG_HAML "haml" +#define LANG_HAXE "haxe" +#define LANG_HTML "html" +#define LANG_JAVA "java" +#define LANG_JAVASCRIPT "javascript" +#define LANG_JSP "jsp" +#define LANG_LIMBO "limbo" +#define LANG_LISP "lisp" +#define LANG_LUA "lua" +#define LANG_MAKE "make" +#define LANG_MATLAB "matlab" +#define LANG_METAFONT "metafont" +#define LANG_METAPOST "metapost" +#define LANG_METAPOST_WITH_TEX "metapost_with_tex" +#define LANG_MXML "mxml" +#define LANG_NIX "nix" +#define LANG_OBJECTIVE_C "objective_c" +#define LANG_OBJECTIVE_J "objective_j" +#define LANG_OCAML "ocaml" +#define LANG_OCTAVE "octave" +#define LANG_PASCAL "pascal" +#define LANG_PERL "perl" +#define LANG_PHP "php" +#define LANG_PIKE "pike" +#define LANG_PYTHON "python" +#define LANG_R "r" +#define LANG_REXX "rexx" +#define LANG_RHTML "rhtml" +#define LANG_RUBY "ruby" +#define LANG_SCALA "scala" +#define LANG_SCHEME "scheme" +#define LANG_SCILAB "scilab" +#define LANG_SHELL "shell" +#define LANG_SMALLTALK "smalltalk" +#define LANG_STRATEGO "stratego" +#define LANG_STRUCTURED_BASIC "structured_basic" +#define LANG_SQL "sql" +#define LANG_TCL "tcl" +#define LANG_TEX "tex" +#define LANG_VALA "vala" +#define LANG_VB_ASPX "vb_aspx" +#define LANG_VHDL "vhdl" +#define LANG_VIM "vim" +#define LANG_VISUALBASIC "visualbasic" +#define LANG_XAML "xaml" +#define LANG_XML "xml" +#define LANG_XSLT "xslt" +#define LANG_XMLSCHEMA "xmlschema" + +#endif diff --git a/src/licenses.c b/src/licenses.c new file mode 100644 index 0000000..10db559 --- /dev/null +++ b/src/licenses.c @@ -0,0 +1,882 @@ +// licenses.c written by Mitchell Foral. mitchellcaladbolg.net. +// See COPYING for license information. + +#include +#include + +#include "licenses.h" +#include "parser.h" + +// Holds licenses and their associated details and patterns. +License license_map[] = { + { + LIC_ACADEMIC, + "http://www.opensource.org/licenses/afl-3.0.php", + "Academic Free License", + "\\bAcademic\\s*Free\\s*License\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_ADAPTIVE, + "http://www.opensource.org/licenses/apl1.0.php", + "Adaptive Public License", + "\\bAdaptive\\s*Public\\s*License\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_AFFERO, + "http://www.affero.org/oagpl.html", + "GNU Affero General Public License", + "\\bGNU\\s+Affero\\s+General\\s+Public\\s+License\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_APACHE, + "http://www.opensource.org/licenses/apachepl.php", + "Apache Software License", + "(\\bApache\\s*Software\\s*License(?![\\s,]*2))|(\\bapache\\s*license(?![\\s,]*2))", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_APACHE2, + "http://www.opensource.org/licenses/apache2.0.php", + "Apache License, 2.0", + "\\bapache\\s+(software\\s+)?license,?\\s+(version\\s+)?2", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_APPLE_OPEN_SOURCE, + "http://www.opensource.org/licenses/apsl-2.0.php", + "Apple Public Source License", + "\\bApple\\s*Public\\s*Source\\s*License\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_ARTISTIC, + "http://www.opensource.org/licenses/artistic-license.php", + "Artistic license", + "\\bartistic\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_ATTRIBUTION_ASSURANCE, + "http://www.opensource.org/licenses/attribution.php", + "Attribution Assurance Licenses", + "\\battribution\\s*assurance\\s*license(s)?\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_BOOST, + "http://www.boost.org/LICENSE_1_0.txt", + "Boost Software License - Version 1.0 - August 17th, 2003", + "\\bboost\\s*software\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_BSD, + "http://www.opensource.org/licenses/bsd-license.php", + "New BSD license", + "(\\bbsd\\s*license\\b)|(The Regents of the University of California)", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_CECILL, + "http://www.cecill.info/licences/Licence_CeCILL_V2-en.html", + "CeCILL license", + "\\bcecill\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_CECILL_B, + "http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html", + "CeCILL-B license", + "\\bcecill-b\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_CECILL_C, + "http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html", + "CeCILL-C license", + "\\bcecill-c\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_COMPUTER_ASSOCIATES_TRUSTED, + "http://www.opensource.org/licenses/ca-tosl1.1.php", + "Computer Associates Trusted Open Source License 1.1", + "\\bcomputer\\s*associates\\s*trusted\\s*open\\s*source\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_COMMON_DEVELOPMENT_AND_DISTRIBUTION, + "http://www.opensource.org/licenses/cddl1.php", + "Common Development and Distribution License", + "\\bcommon\\s*development\\s*and\\s*distribution\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_COMMON_PUBLIC, + "http://www.opensource.org/licenses/cpl1.0.php", + "Common Public License 1.0", + "\\bcommon\\s*public\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_CUA_OFFICE, + "http://www.opensource.org/licenses/cuaoffice.php", + "CUA Office Public License Version 1.0", + "\\bCUA\\s*office\\s*public\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_EU_DATAGRID, + "http://www.opensource.org/licenses/eudatagrid.php", + "EU DataGrid Software License", + "\\beu\\s*datagrid\\s*software\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_ECLIPSE, + "http://www.opensource.org/licenses/eclipse-1.0.php", + "Eclipse Public License", + "\\beclipse\\s*public\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_EDUCATIONAL, + "http://www.opensource.org/licenses/ecl1.php", + "Educational Community License", + "\\beducational\\s*community\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_EIFFEL, + "http://www.opensource.org/licenses/eiffel.php", + "Eiffel Forum License", + "\\beiffel\\s*forum\\s*license(?![,V\\s]*2)\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_EIFFEL2, + "http://www.opensource.org/licenses/ver2_eiffel.php", + "Eiffel Forum License V2.0", + "\\beiffel\\s*forum\\s*license [,V\\s]*2", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_ENTESSA, + "http://www.opensource.org/licenses/entessa.php", + "Entessa Public License", + "\\bentessa\\s*public\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_FAIR, + "http://www.opensource.org/licenses/fair.php", + "Fair License", + "\\bfair\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_FRAMEWORX, + "http://www.opensource.org/licenses/frameworx.php", + "Frameworx License", + "\\bframeworx\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_GPL3_OR_LATER, + "http://www.gnu.org/licenses/gpl-3.0.html", + "GNU General Public License 3.0", + "\\b(GNU GENERAL PUBLIC LICENSE|GPL).{0,100}(Version)? 3.{0,50}later", + PCRE_CASELESS | PCRE_MULTILINE, + NULL, + 0, + NULL, NULL + }, + { + LIC_GPL3, + "http://www.gnu.org/licenses/gpl-3.0.html", + "GNU General Public License 3.0", + "GNU (GENERAL PUBLIC LICENSE|GPL).{0,100}(Version |v)3", + PCRE_CASELESS | PCRE_MULTILINE, + "((at your option) any later version)|(GENERAL PUBLIC LICENSE.*GENERAL PUBLIC LICENSE)", + PCRE_CASELESS, + NULL, NULL + }, + { + LIC_LGPL3, + "http://www.gnu.org/licenses/lgpl-3.0.html", + "GNU Lesser General Public License 3.0", + "((\\blgpl\\b)|(\\bgnu\\s*(library|lesser)\\s*(general\\s*)?(public\\s*)?license\\b)|(\\b(lesser|library)\\s*gpl\\b)).{0,10}(\\bas published by the free software foundation\\b)?.{0,10}(\\bversion\\b)?.{0,10}\\b3(\\.0)?\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_GPL, + "http://www.opensource.org/licenses/gpl-license.php", + "GNU General Public License (GPL)", + "(\\bgpl\\b)|(\\bgplv2\\b)|(\\bgnu\\s*general\\s*public\\s*license\\b)|(\\bwww\\.gnu\\.org\\/licenses\\/gpl\\.txt\\b)", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_LGPL, + "http://www.opensource.org/licenses/lgpl-license.php", + "GNU Library or \"Lesser\" GPL (LGPL)", + "(\\blgpl\\b)|(\\bgnu\\s*(library|lesser)\\s*(general\\s*)?(public\\s*)?license\\b)|(\\b(lesser|library)\\s*gpl\\b)", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_HISTORICAL, + "http://www.opensource.org/licenses/historical.php", + "Historical Permission Notice and Disclaimer", + "\\bhistorical\\s*permission\\s*notice\\s*and\\s*disclaimer\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_I9, + "http://i9os.googlecode.com/svn/trunk/Documentation/Licenses/i9_License", + "i9 License", + "\\bi9\\s*\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_IBM_PUBLIC, + "http://www.opensource.org/licenses/ibmpl.php", + "IBM Public License", + "\\bibm\\s*public\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_INTEL_OPEN_SOURCE, + "http://www.opensource.org/licenses/intel-open-source-license.php", + "Intel Open Source License", + "\\bintel\\s*open\\s*source\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_JABBER_OPEN_SOURCE, + "http://www.opensource.org/licenses/jabberpl.php", + "Jabber Open Source License", + "\\bjabber\\s*open\\s*source\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_LUCENT_PLAN9, + "http://www.opensource.org/licenses/plan9.php", + "Lucent Public License (Plan9)", + "\\blucent\\s*public\\s*license[\\s(]*plan9", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_LUCENT_PUBLIC, + "http://www.opensource.org/licenses/lucent1.02.php", + "Lucent Public License Version 1.02", + "\\blucent\\s*public\\s*license\\s*(version)?\\s+1", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_MIT, + "http://www.opensource.org/licenses/mit-license.php", + "MIT license", + "(\\bmit\\s*license\\b)|(\\bMIT\\/X11\\s*license\\b)", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_MITRE, + "http://www.opensource.org/licenses/mitrepl.php", + "MITRE Collaborative Virtual Workspace License (CVW License)", + "\\bmitre\\s*collaborative\\s*virtual\\s*workspace\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_MOTOSOTO, + "http://www.opensource.org/licenses/motosoto.php", + "Motosoto License", + "\\bmotosoto\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_MOZILLA_PUBLIC1, + "http://www.opensource.org/licenses/mozilla1.0.php", + "Mozilla Public License 1.0 (MPL)", + "\\bmozilla\\s*public\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_MOZILLA_PUBLIC11, + "http://www.opensource.org/licenses/mozilla1.1.php", + "Mozilla Public License 1.1 (MPL)", + "\\bmozilla\\s*public\\s*license 1\\.1\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_NASA_OPEN, + "http://www.opensource.org/licenses/nasa1.3.php", + "NASA Open Source Agreement 1.3", + "\\bnasa\\s*open\\s*source\\s*agreement\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_NAUMEN, + "http://www.opensource.org/licenses/naumen.php", + "Naumen Public License", + "\\bnaumen\\s*public\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_NETHACK, + "http://www.opensource.org/licenses/nethack.php", + "Nethack General Public License", + "\\bnethack\\s*general\\s*public\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_NOKIA_OPEN_SOURCE, + "http://www.opensource.org/licenses/nokia.php", + "Nokia Open Source License", + "\\bnokia\\s*open\\s*source\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_OCLC_RESEARCH, + "http://www.opensource.org/licenses/oclc2.php", + "OCLC Research Public License 2.0", + "\\boclc\\s*research\\s*public\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_OPEN_GROUP_TEST, + "http://www.opensource.org/licenses/opengroup.php", + "Open Group Test Suite License", + "\\bopen\\s*group\\s*test\\s*suite\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_OPEN_SOFTWARE, + "http://www.opensource.org/licenses/osl-3.0.php", + "Open Software License", + "\\bopen\\s*software\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_PHP_LICENSE, + "http://www.opensource.org/licenses/php.php", + "PHP License", + "\\bphp\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_PYTHON_LICENSE, + "http://www.opensource.org/licenses/pythonpl.php", + "Python license", + "\\bpython\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_PYTHON_SOFTWARE_FOUNDATION, + "http://www.opensource.org/licenses/PythonSoftFoundation.php", + "Python Software Foundation License", + "\\bpython\\s*software\\s*foundation\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_QT_PUBLIC, + "http://www.opensource.org/licenses/qtpl.php", + "Qt Public License (QPL)", + "\\bqt\\s*public\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_REALNETWORKS_PUBLIC_SOURCE, + "http://www.opensource.org/licenses/real.php", + "RealNetworks Public Source License V1.0", + "\\brealnetworks\\s*public\\s*source\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_RECIPROCAL_PUBLIC, + "http://www.opensource.org/licenses/rpl.php", + "Reciprocal Public License", + "\\breciprocal\\s*public\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_RICOH_SOURCE, + "http://www.opensource.org/licenses/ricohpl.php", + "Ricoh Source Code Public License", + "\\bricoh\\s*source\\s*code\\s*public\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_SLEEPYCAT, + "http://www.opensource.org/licenses/sleepycat.php", + "Sleepycat License", + "\\bsleepycat\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_SUGARCRM113, + "http://www.sugarcrm.com/SPL", + "SugarCRM Public License 1.1.3", + "\\bsugar\\s*public\\s*license\\s*version\\s*1\\.1\\.3\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_SUN_INDUSTRY_STANDARDS, + "http://www.opensource.org/licenses/sisslpl.php", + "Sun Industry Standards Source License (SISSL)", + "\\bsun\\s*industry\\s*standards\\s*source\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_SUN_PUBLIC, + "http://www.opensource.org/licenses/sunpublic.php", + "Sun Public License", + "\\bsun\\s*public\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_SYBASE_OPEN_WATCOM, + "http://www.opensource.org/licenses/sybase.php", + "Sybase Open Watcom Public License 1.0", + "\\bsybase\\s*open\\s*watcom\\s*public\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_U_OF_I_NCSA, + "http://www.opensource.org/licenses/UoI-NCSA.php", + "University of Illinois/NCSA Open Source License", + "\\buniversity\\s*of\\s*illinois\\/ncsa\\s*open\\s*source\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_VOVIDA_SOFTWARE, + "http://www.opensource.org/licenses/vovidapl.php", + "Vovida Software License v. 1.0", + "\\bvovida\\s*software\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_W3C, + "http://www.opensource.org/licenses/W3C.php", + "W3C License", + "\\bw3c\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_WXWINDOWS, + "http://www.opensource.org/licenses/wxwindows.php", + "wxWindows Library License", + "\\bwxwindows\\s*library\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_XNET, + "http://www.opensource.org/licenses/xnet.php", + "X.Net License", + "\\bx\\.net\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_ZOPE, + "http://www.opensource.org/licenses/zpl.php", + "Zope Public License", + "\\bzope\\s*public\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_ZLIB_LIBPNG, + "http://www.opensource.org/licenses/zlib-license.php", + "zlib/libpng license", + "\\bzlib\\/libpng\\s*license\\b", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_APACHE_ISH, + "", + "Apache-ish License", + "(\\bapache-style.*license\\b)|(\\bapache-like.*license\\b)", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, + { + LIC_BSD_ISH, + "", + "BSD-ish License", + "Copyright\\s.{1,40}All rights reserved.{0,40}Redistribution and use in source and binary forms, with or without.{0,20}modification, are permitted provided that the following conditions.{0,20}\\sare met.{1,40}Redistributions of source code must retain the above copyright\\s.*notice, this list of conditions and the following disclaimer\\.\\s+.*Redistributions in binary form must reproduce the above.*copyright\\s+.{0,10}notice, this list of conditions and the following.*disclaimer in the\\s+.*documentation.*(The (name|names) of the (author|contributors) may not|Neither the name of the).*be used to endorse or promote\\s+.*products\\s+.*derived\\s+.*from this software without specific prior written\\s+.*permission.*HOWEVER\\s+.*CAUSED AND ON ANY.*THEORY OF LIABILITY, WHETHER IN CONTRACT", + PCRE_MULTILINE, + "The Regents of the University of California", + 0, + NULL, NULL + }, + { + LIC_BSD_2CLAUSE_ISH, + "", + "BSD-ish (2 clause) License", + "Copyright\\s.{1,60}All rights reserved.{1,40}Redistribution and use in source and binary forms, with or without.{0,20}modification, are permitted provided that the following conditions.{0,20}\\sare met.{0,20}\\s{1,20}.{0,20}Redistributions of source code must retain the above copyright\\s+.*notice, this list of conditions and the following disclaimer.\\s+.*Redistributions in binary form must reproduce the above copyright\\s+.*notice, this list of conditions and the following disclaimer in the\\s+.*documentation and\\/or other materials provided with the distribution\\.\\s+.*HOWEVER CAUSED AND ON ANY.*THEORY OF LIABILITY, WHETHER IN CONTRACT", + PCRE_MULTILINE, + "(The Regents of the University of California)|(used to endorse or promote\\s+.*products\\s+.*prior\\s+.*written\\s+.*permission\\.)", + PCRE_MULTILINE, + NULL, NULL + }, + { NULL, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL }, +}; +int license_map_length = 0; // will be set dynamically + +/** Compiles the regular expressions defined in license_map. */ +void compile_regexps() { + if (license_map_length == 0) + return; + const char *err; + int erroffset; + int i; + for (i = 0; i < license_map_length; i++) { + License *l = &license_map[i]; + int flags; + if (l->re) { + flags = l->re_flags; + if (flags & PCRE_MULTILINE) + flags |= PCRE_DOTALL; + l->regexp = pcre_compile(l->re, flags, &err, &erroffset, NULL); + } + if (l->exclude_re) { + flags = l->exclude_re_flags; + if (flags & PCRE_MULTILINE) + flags |= PCRE_DOTALL; + l->exclude_regexp = pcre_compile(l->exclude_re, flags, &err, &erroffset, + NULL); + } + } +} + +/** + * Overrides a less-specific license l with a more-specific one if the latter + * was detected. + */ +#define OVERRIDE_LICENSE(l, with) { \ + if (strcmp(license_map[i].name, l) == 0) { \ + for (j = 0; j < license_map_length; j++) \ + if (potential_licenses_s[j] > -1 && \ + strcmp(license_map[j].name, with) == 0) { \ + overridden = 1; \ + break; \ + } \ + } \ +} + +LicenseList *ohcount_detect_license(SourceFile *sourcefile) { + LicenseList *list = ohcount_license_list_new(); + + // Get the size of this map and compile the REs. Only runs once. + if (license_map_length == 0) { + while (license_map[license_map_length].name) license_map_length++; + compile_regexps(); + } + + ohcount_sourcefile_parse(sourcefile); + + int potential_licenses_s[license_map_length]; + int potential_licenses_e[license_map_length]; + + char *p, *q; + int i, j, k; + int ovector[30]; // recommended by PCRE + ParsedLanguageList *iter; + iter = ohcount_sourcefile_get_parsed_language_list(sourcefile)->head; + while (iter) { + char buffer[ohcount_sourcefile_get_contents_size(sourcefile)]; + p = iter->pl->comments; + q = buffer; + char *eof = p + strlen(p); + while (p < eof) { + // Strip leading whitespace and punctuation. + while (*p == ' ' || *p == '\t' || ispunct(*p)) p++; + // Copy line contents. + while (p < eof && *p != '\r' && *p != '\n') *q++ = *p++; + // Strip newline characters. + while (*p == '\r' || *p == '\n') p++; + // Add a trailing space. + *q++ = ' '; + } + *q = '\0'; + + for (j = 0; j < license_map_length; j++) { + potential_licenses_s[j] = -1; + potential_licenses_e[j] = -1; + if (pcre_exec(license_map[j].regexp, NULL, buffer, q - buffer, 0, 0, + ovector, 30) >= 0) { + int m0 = ovector[0], m1 = ovector[1]; + // Exclude terms that may not exist in the license. + if (license_map[j].exclude_re && + pcre_exec(license_map[j].exclude_regexp, NULL, buffer + m0, m1 - m0, + 0, 0, ovector, 30) >= 0) + continue; + potential_licenses_s[j] = m0; + potential_licenses_e[j] = m1; + for (k = 0; k < j; k++) { + // If this matched license is completely contained inside another one, + // do not include it. + if ((potential_licenses_s[k] < m0 && potential_licenses_e[k] >= m1) || + (potential_licenses_s[k] <= m0 && potential_licenses_e[k] > m1)) { + potential_licenses_s[j] = -1; + potential_licenses_e[j] = -1; + } + // If this matched license completely contains another one, do not + // include the latter. + if ((m0 < potential_licenses_s[k] && m1 >= potential_licenses_e[k]) || + (m0 <= potential_licenses_s[k] && m1 > potential_licenses_e[k])) { + potential_licenses_s[k] = -1; + potential_licenses_e[k] = -1; + } + } + } + } + iter = iter->next; + } + + // Create the list of licenses from potential licenses. + for (i = 0; i < license_map_length; i++) { + if (potential_licenses_s[i] > -1) { + int overridden = 0; + OVERRIDE_LICENSE(LIC_GPL, LIC_GPL3); + OVERRIDE_LICENSE(LIC_GPL, LIC_GPL3_OR_LATER); + OVERRIDE_LICENSE(LIC_GPL3, LIC_GPL3_OR_LATER); + OVERRIDE_LICENSE(LIC_BSD_2CLAUSE_ISH, LIC_BSD_ISH); + if (!overridden) { + if (list->head == NULL) { // empty list + list->head = list; + list->tail = list; + list->head->lic = &license_map[i]; + list->next = NULL; + } else { + LicenseList *item = ohcount_license_list_new(); + item->lic = &license_map[i]; + list->tail->next = item; + list->tail = item; + } + } + } + } + + return list; +} + +LicenseList *ohcount_license_list_new() { + LicenseList *list = malloc(sizeof(LicenseList)); + list->lic = NULL; + list->next = NULL; + list->head = NULL; + list->tail = NULL; + return list; +} + +void ohcount_license_list_free(LicenseList *list) { + if (list->head) { + LicenseList *iter = list->head; + while (iter) { + LicenseList *next = iter->next; + free(iter); + iter = next; + } + } else free(list); +} diff --git a/src/licenses.h b/src/licenses.h new file mode 100644 index 0000000..cc8acee --- /dev/null +++ b/src/licenses.h @@ -0,0 +1,120 @@ +// licenses.h written by Mitchell Foral. mitchellcaladbolg.net. +// See COPYING for license information. + +#ifndef OHCOUNT_LICENSES_H +#define OHCOUNT_LICENSES_H + +/** + * @page license_doc License Documentation + * @author Mitchell Foral + * + * @section license How to Add a New License + * + * @li Add your license to 'src/licenses.h' and 'src/licenses.c'. Don't forget + * that two '\\'s are required to represent one '\\' in a C string. + * @li Add your tests to the 'test/src_licenses/' and 'test/expected_licenses/' + * directories. Note that multiple licenses must be separated by newlines and + * be in the order they appear in the input file. + * @li Run the test suite (a rebuild is not necessary; your added tests are + * detected and run automatically) to verify your licenses are correctly + * detected. + * @li Rebuild Ohcount. + */ + +#include "sourcefile.h" + +#define LIC_ACADEMIC "academic" +#define LIC_ADAPTIVE "adaptive" +#define LIC_AFFERO "affero" +#define LIC_APACHE "apache" +#define LIC_APACHE2 "apache_2" +#define LIC_APPLE_OPEN_SOURCE "apple_open_source" +#define LIC_ARTISTIC "artistic" +#define LIC_ATTRIBUTION_ASSURANCE "attribution_assurance" +#define LIC_BOOST "boost" +#define LIC_BSD "bsd" +#define LIC_CECILL "cecill" +#define LIC_CECILL_B "cecill_b" +#define LIC_CECILL_C "cecill_c" +#define LIC_COMPUTER_ASSOCIATES_TRUSTED "computer_associates_trusted" +#define LIC_COMMON_DEVELOPMENT_AND_DISTRIBUTION \ + "common_development_and_distribution" +#define LIC_COMMON_PUBLIC "common_public" +#define LIC_CUA_OFFICE "cua_office" +#define LIC_EU_DATAGRID "eu_datagrid" +#define LIC_ECLIPSE "eclipse" +#define LIC_EDUCATIONAL "educational" +#define LIC_EIFFEL "eiffel" +#define LIC_EIFFEL2 "eiffel_2" +#define LIC_ENTESSA "entessa" +#define LIC_FAIR "fair" +#define LIC_FRAMEWORX "frameworx" +#define LIC_GPL3_OR_LATER "gpl3_or_later" +#define LIC_GPL3 "gpl3" +#define LIC_LGPL3 "lgpl3" +#define LIC_GPL "gpl" +#define LIC_LGPL "lgpl" +#define LIC_HISTORICAL "historical" +#define LIC_I9 "i9_license" +#define LIC_IBM_PUBLIC "ibm_public" +#define LIC_INTEL_OPEN_SOURCE "intel_open_source" +#define LIC_JABBER_OPEN_SOURCE "jabber_open_source" +#define LIC_LUCENT_PLAN9 "lucent_plan9" +#define LIC_LUCENT_PUBLIC "lucent_public" +#define LIC_MIT "mit" +#define LIC_MITRE "mitre" +#define LIC_MOTOSOTO "motosoto" +#define LIC_MOZILLA_PUBLIC1 "mozilla_public_1" +#define LIC_MOZILLA_PUBLIC11 "mozilla_public_1_1" +#define LIC_NASA_OPEN "nasa_open" +#define LIC_NAUMEN "naumen" +#define LIC_NETHACK "nethack" +#define LIC_NOKIA_OPEN_SOURCE "nokia_open_source" +#define LIC_OCLC_RESEARCH "oclc_research" +#define LIC_OPEN_GROUP_TEST "open_group_test" +#define LIC_OPEN_SOFTWARE "open_software" +#define LIC_PHP_LICENSE "php_license" +#define LIC_PYTHON_LICENSE "python_license" +#define LIC_PYTHON_SOFTWARE_FOUNDATION "python_software_foundation" +#define LIC_QT_PUBLIC "qt_public" +#define LIC_REALNETWORKS_PUBLIC_SOURCE "realnetworks_public_source" +#define LIC_RECIPROCAL_PUBLIC "reciprocal_public" +#define LIC_RICOH_SOURCE "ricoh_source" +#define LIC_SLEEPYCAT "sleepycat" +#define LIC_SUGARCRM113 "sugarcrm_1_1_3" +#define LIC_SUN_INDUSTRY_STANDARDS "sun_industry_standards" +#define LIC_SUN_PUBLIC "sun_public" +#define LIC_SYBASE_OPEN_WATCOM "sybase_open_watcom" +#define LIC_U_OF_I_NCSA "u_of_i_ncsa" +#define LIC_VOVIDA_SOFTWARE "vovida_software" +#define LIC_W3C "w3c" +#define LIC_WXWINDOWS "wx_windows" +#define LIC_XNET "x_net" +#define LIC_ZOPE "zope" +#define LIC_ZLIB_LIBPNG "zlib_libpng" +#define LIC_APACHE_ISH "apache_ish" +#define LIC_BSD_ISH "bsd_ish" +#define LIC_BSD_2CLAUSE_ISH "bsd_2clause_ish" + +/** + * Attempts to detect the source code licenses for a given file. + * It searches comment text in source files for any mention of known licenses, + * but unfortunately catches things like: "I find the GNU Public License dumb". + * @param sourcefile A SourceFile created by ohcount_sourcefile_new(). + * @return LicenseList + */ +LicenseList *ohcount_detect_license(SourceFile *sourcefile); + +/** + * Creates a new LicenseList that is initially empty. + * @return LicenseList + */ +LicenseList *ohcount_license_list_new(); + +/** + * Frees the memory allocated for the given LicenseList. + * @param list A LicenseList created from ohcount_license_list_new(). + */ +void ohcount_license_list_free(LicenseList *list); + +#endif diff --git a/src/loc.c b/src/loc.c new file mode 100644 index 0000000..bd43934 --- /dev/null +++ b/src/loc.c @@ -0,0 +1,419 @@ +// loc.c written by Mitchell Foral. mitchellcaladbolg.net. +// See COPYING for license information. + +#include +#include + +#include "loc.h" + +// Loc + +Loc *ohcount_loc_new(const char *language, int code, int comments, int blanks, + int filecount) { + Loc *loc = malloc(sizeof(Loc)); + loc->language = language; + loc->code = code; + loc->comments = comments; + loc->blanks = blanks; + loc->filecount = filecount; + return loc; +} + +int ohcount_loc_total(Loc *loc) { + return loc->code + loc->comments + loc->blanks; +} + +void ohcount_loc_add_loc(Loc *loc, Loc *other) { + if (strcmp(loc->language, other->language) == 0) { + loc->code += other->code; + loc->comments += other->comments; + loc->blanks += other->blanks; + loc->filecount += other->filecount; + } +} + +int ohcount_loc_is_equal(Loc *loc, Loc *other) { + return strcmp(loc->language, other->language) == 0 && + loc->code == other->code && loc->comments == other->comments && + loc->blanks == other->blanks && loc->filecount == other->filecount; +} + +void ohcount_loc_free(Loc *loc) { + free(loc); +} + +// LocList + +LocList *ohcount_loc_list_new() { + LocList *list = malloc(sizeof(LocList)); + list->loc = NULL; + list->next = NULL; + list->head = NULL; + list->tail = NULL; + return list; +} + +void ohcount_loc_list_add_loc(LocList *list, Loc *loc) { + if (list->head == NULL) { // empty list + list->head = list; + list->tail = list; + list->head->loc = ohcount_loc_new(loc->language, loc->code, loc->comments, + loc->blanks, loc->filecount); + list->head->next = NULL; + } else { + LocList *iter = list->head; + while (iter) { + if (iter->loc && strcmp(iter->loc->language, loc->language) == 0) break; + iter = iter->next; + } + if (iter == NULL) { // new language + LocList *item = ohcount_loc_list_new(); + item->loc = ohcount_loc_new(loc->language, loc->code, loc->comments, + loc->blanks, loc->filecount); + list->tail->next = item; + list->tail = item; + } else ohcount_loc_add_loc(iter->loc, loc); // existing language + } +} + +void ohcount_loc_list_add_loc_list(LocList *list, LocList *other) { + LocList *iter = other->head; + while (iter) { + ohcount_loc_list_add_loc(list, iter->loc); + iter = iter->next; + } +} + +Loc *ohcount_loc_list_get_loc(LocList *list, const char *language) { + LocList *iter = list->head; + while (iter) { + if (strcmp(iter->loc->language, language) == 0) return iter->loc; + iter = iter->next; + } + return NULL; +} + +int ohcount_loc_list_code(LocList *list) { + int sum = 0; + LocList *iter = list->head; + while (iter) { + sum += iter->loc->code; + iter = iter->next; + } + return sum; +} + +int ohcount_loc_list_comments(LocList *list) { + int sum = 0; + LocList *iter = list->head; + while (iter) { + sum += iter->loc->comments; + iter = iter->next; + } + return sum; +} + +int ohcount_loc_list_blanks(LocList *list) { + int sum = 0; + LocList *iter = list->head; + while (iter) { + sum += iter->loc->blanks; + iter = iter->next; + } + return sum; +} + +int ohcount_loc_list_total(LocList *list) { + int sum = 0; + LocList *iter = list->head; + while (iter) { + sum += ohcount_loc_total(iter->loc); + iter = iter->next; + } + return sum; +} + +int ohcount_loc_list_filecount(LocList *list) { + int sum = 0; + LocList *iter = list->head; + while (iter) { + sum += iter->loc->filecount; + iter = iter->next; + } + return sum; +} + +LocList *ohcount_loc_list_new_compact(LocList *list) { + LocList *new_list = ohcount_loc_list_new(); + LocList *iter = list->head; + while (iter) { + if (ohcount_loc_total(iter->loc) != 0) + ohcount_loc_list_add_loc(new_list, iter->loc); + iter = iter->next; + } + return new_list; +} + +void ohcount_loc_list_free(LocList *list) { + if (list->head) { + LocList *iter = list->head; + while (iter) { + LocList *next = iter->next; + ohcount_loc_free(iter->loc); + free(iter); + iter = next; + } + } else free(list); +} + +// LocDelta + +LocDelta *ohcount_loc_delta_new(const char *language, int code_added, + int code_removed, int comments_added, + int comments_removed, int blanks_added, + int blanks_removed) { + LocDelta *delta = malloc(sizeof(LocDelta)); + delta->language = language; + delta->code_added = code_added; + delta->code_removed = code_removed; + delta->comments_added = comments_added; + delta->comments_removed = comments_removed; + delta->blanks_added = blanks_added; + delta->blanks_removed = blanks_removed; + return delta; +} + +int ohcount_loc_delta_net_code(LocDelta *delta) { + return delta->code_added - delta->code_removed; +} + +int ohcount_loc_delta_net_comments(LocDelta *delta) { + return delta->comments_added - delta->comments_removed; +} + +int ohcount_loc_delta_net_blanks(LocDelta *delta) { + return delta->blanks_added - delta->blanks_removed; +} + +int ohcount_loc_delta_net_total(LocDelta *delta) { + return ohcount_loc_delta_net_code(delta) + + ohcount_loc_delta_net_comments(delta) + + ohcount_loc_delta_net_blanks(delta); +} + +void ohcount_loc_delta_add_loc_delta(LocDelta *delta, LocDelta *other) { + if (strcmp(delta->language, other->language) == 0) { + delta->code_added += other->code_added; + delta->code_removed += other->code_removed; + delta->comments_added += other->comments_added; + delta->comments_removed += other->comments_removed; + delta->blanks_added += other->blanks_added; + delta->blanks_removed += other->blanks_removed; + } +} + +int ohcount_loc_delta_is_changed(LocDelta *delta) { + return delta->code_added != 0 || delta->code_removed != 0 || + delta->comments_added != 0 || delta->comments_removed != 0 || + delta->blanks_added != 0 || delta->blanks_removed != 0; +} + +int ohcount_loc_delta_is_equal(LocDelta *delta, LocDelta *other) { + return strcmp(delta->language, other->language) == 0 && + delta->code_added == other->code_added && + delta->code_removed == other->code_removed && + delta->comments_added == other->comments_added && + delta->comments_removed == other->comments_removed && + delta->blanks_added == other->blanks_added && + delta->blanks_removed == other->blanks_removed; +} + +void ohcount_loc_delta_free(LocDelta *delta) { + free(delta); +} + +// LocDeltaList + +LocDeltaList *ohcount_loc_delta_list_new() { + LocDeltaList *list = malloc(sizeof(LocDeltaList)); + list->delta = NULL; + list->next = NULL; + list->head = NULL; + list->tail = NULL; + return list; +} + +void ohcount_loc_delta_list_add_loc_delta(LocDeltaList *list, LocDelta *delta) { + if (list->head == NULL) { // empty list + list->head = list; + list->tail = list; + list->head->delta = ohcount_loc_delta_new(delta->language, + delta->code_added, + delta->code_removed, + delta->comments_added, + delta->comments_removed, + delta->blanks_added, + delta->blanks_removed); + list->head->next = NULL; + } else { + LocDeltaList *iter = list->head; + while (iter) { + if (list->delta && strcmp(list->delta->language, delta->language) == 0) break; + iter = iter->next; + } + if (iter == NULL) { // new language + LocDeltaList *item = ohcount_loc_delta_list_new(); + item->delta = ohcount_loc_delta_new(delta->language, + delta->code_added, + delta->code_removed, + delta->comments_added, + delta->comments_removed, + delta->blanks_added, + delta->blanks_removed); + list->tail->next = item; + list->tail = item; + } else ohcount_loc_delta_add_loc_delta(iter->delta, delta); // existing + } +} + +void ohcount_loc_delta_list_add_loc_delta_list(LocDeltaList *list, + LocDeltaList *loc_delta_list) { + LocDeltaList *iter = loc_delta_list->head; + while (iter) { + ohcount_loc_delta_list_add_loc_delta(list, iter->delta); + iter = iter->next; + } +} + +LocDelta *ohcount_loc_delta_list_get_loc_delta(LocDeltaList *list, + const char *language) { + LocDeltaList *iter = list->head; + while (iter) { + if (strcmp(iter->delta->language, language) == 0) return iter->delta; + iter = iter->next; + } + return NULL; +} + +int ohcount_loc_delta_list_code_added(LocDeltaList *list) { + int sum = 0; + LocDeltaList *iter = list->head; + while (iter) { + sum += iter->delta->code_added; + iter = iter->next; + } + return sum; +} + +int ohcount_loc_delta_list_code_removed(LocDeltaList *list) { + int sum = 0; + LocDeltaList *iter = list->head; + while (iter) { + sum += iter->delta->code_removed; + iter = iter->next; + } + return sum; +} + +int ohcount_loc_delta_list_comments_added(LocDeltaList *list) { + int sum = 0; + LocDeltaList *iter = list->head; + while (iter) { + sum += iter->delta->comments_added; + iter = iter->next; + } + return sum; +} + +int ohcount_loc_delta_list_comments_removed(LocDeltaList *list) { + int sum = 0; + LocDeltaList *iter = list->head; + while (iter) { + sum += iter->delta->comments_removed; + iter = iter->next; + } + return sum; +} + +int ohcount_loc_delta_list_blanks_added(LocDeltaList *list) { + int sum = 0; + LocDeltaList *iter = list->head; + while (iter) { + sum += iter->delta->blanks_added; + iter = iter->next; + } + return sum; +} + +int ohcount_loc_delta_list_blanks_removed(LocDeltaList *list) { + int sum = 0; + LocDeltaList *iter = list->head; + while (iter) { + sum += iter->delta->blanks_removed; + iter = iter->next; + } + return sum; +} + +int ohcount_loc_delta_list_net_code(LocDeltaList *list) { + int sum = 0; + LocDeltaList *iter = list->head; + while (iter) { + sum += ohcount_loc_delta_net_code(iter->delta); + iter = iter->next; + } + return sum; +} + +int ohcount_loc_delta_list_net_comments(LocDeltaList *list) { + int sum = 0; + LocDeltaList *iter = list->head; + while (iter) { + sum += ohcount_loc_delta_net_comments(iter->delta); + iter = iter->next; + } + return sum; +} + +int ohcount_loc_delta_list_net_blanks(LocDeltaList *list) { + int sum = 0; + LocDeltaList *iter = list->head; + while (iter) { + sum += ohcount_loc_delta_net_blanks(iter->delta); + iter = iter->next; + } + return sum; +} + +int ohcount_loc_delta_list_net_total(LocDeltaList *list) { + int sum = 0; + LocDeltaList *iter = list->head; + while (iter) { + sum += ohcount_loc_delta_net_total(iter->delta); + iter = iter->next; + } + return sum; +} + +LocDeltaList *ohcount_loc_delta_list_new_compact(LocDeltaList *list) { + LocDeltaList *new_list = ohcount_loc_delta_list_new(); + LocDeltaList *iter = list->head; + while (iter) { + if (ohcount_loc_delta_is_changed(iter->delta)) + ohcount_loc_delta_list_add_loc_delta(new_list, iter->delta); + iter = iter->next; + } + return new_list; +} + +void ohcount_loc_delta_list_free(LocDeltaList *list) { + if (list->head) { + LocDeltaList *iter = list->head; + while (iter) { + LocDeltaList *next = iter->next; + ohcount_loc_delta_free(iter->delta); + free(iter); + iter = next; + } + } else free(list); +} diff --git a/src/loc.h b/src/loc.h new file mode 100644 index 0000000..943ed54 --- /dev/null +++ b/src/loc.h @@ -0,0 +1,310 @@ +// loc.h written by Mitchell Foral. mitchellcaladbolg.net. +// See COPYING for license information. + +#ifndef OHCOUNT_LOC_H +#define OHCOUNT_LOC_H + +#include "structs.h" + +/** + * Creates a new Loc from the given language, lines of code, comments, and + * blanks, and number of files counted. + * The given language is not copied and may not be 'free'd. Use a language + * defined in src/languages.h. + * @param language The language being counted. + * @param code The number of lines of code counted. + * @param comments The number of lines of comments counted. + * @param blanks The number of blank lines counted. + * @param filecount The number of files counted for this set. + * @return Loc + */ +Loc *ohcount_loc_new(const char *language, int code, int comments, int blanks, + int filecount); + +/** + * Returns the total number of lines counted for a given Loc. + * @param loc A Loc created from ohcount_loc_new(). + */ +int ohcount_loc_total(Loc *loc); + +/** + * Adds a Loc to another, provided they use the same language. + * The results are stored in the first Loc given. The second Loc may be 'free'd + * immediately. + * @param loc A Loc created from ohcount_loc_new(). + * @param other Another Loc. + */ +void ohcount_loc_add_loc(Loc *loc, Loc *other); + +/** + * Returns whether or not two given Locs are equivalent. + * @param loc A Loc created from ohcount_loc_new(). + * @param other Another Loc. + */ +int ohcount_loc_is_equal(Loc *loc, Loc *other); + +/** + * Frees the memory allocated for a given Loc. + * @param loc A Loc created from ohcount_loc_new(). + */ +void ohcount_loc_free(Loc *loc); + +/** + * Creates a new LocList that is initially empty. + * Locs can be added using ohcount_loc_list_add_loc(). + * @return LocList + */ +LocList *ohcount_loc_list_new(); + +/** + * Adds a given Loc to a LocList. + * The given Loc is copied and may be 'free'd immediately. + * @param list a LocList created from ohcount_loc_list_new(). + * @param loc A Loc created from ohcount_loc_new(). + */ +void ohcount_loc_list_add_loc(LocList *list, Loc *loc); + +/** + * Adds a given LocList to another LocList. + * The results are stored in the first LocList given. The second LocList may be + * 'free'd immediately. + * @param list A LocList created from ohcount_loc_list_new(). + * @param loc_list Another LocList. + */ +void ohcount_loc_list_add_loc_list(LocList *list, LocList *loc_list); + +/** + * Returns a Loc from a given LocList and language. + * The returned pointer is used internally and may not be 'free'd. + * @param list A LocList created from ohcount_loc_list_new(). + * @param language The language of the Loc to retrieve. + * @return Loc or NULL. + */ +Loc *ohcount_loc_list_get_loc(LocList *list, const char *language); + +/** + * Returns the number of lines of code for all Locs in this LocList. + * @param list A LocList created from ohcount_loc_list_new(). + */ +int ohcount_loc_list_code(LocList *list); + +/** + * Returns the number of lines of commentsfor all Locs in this LocList. + * @param list A LocList created from ohcount_loc_list_new(). + */ +int ohcount_loc_list_comments(LocList *list); + +/** + * Returns the number of blank lines for all Locs in this LocList. + * @param list A LocList created from ohcount_loc_list_new(). + */ +int ohcount_loc_list_blanks(LocList *list); + +/** + * Returns the total number of lines for all Locs in this LocList. + * @param list A LocList created from ohcount_loc_list_new(). + */ +int ohcount_loc_list_total(LocList *list); + +/** + * Returns the number of files counted for all Locs in this LocList. + * @param list A LocList created from ohcount_loc_list_new(). + */ +int ohcount_loc_list_filecount(LocList *list); + +/** + * Creates a new LocList from a given one, excluding all Locs with no counted + * lines. + * The given list may be 'free'd immediately. + * @param list A LocList created from ohcount_loc_list_new(). + */ +LocList *ohcount_loc_list_new_compact(LocList *list); + +/** + * Frees the memory allocated for a given LocList. + * @param list A LocList created from ohcount_loc_list_new(). + */ +void ohcount_loc_list_free(LocList *list); + +/** + * Creates a new LocDelta from the given language and lines of code, comments, + * and blanks added and removed. + * The given language is not copied and may not be 'free'd. Use a language + * defined in src/languages.h. + * @param language The language being counted. + * @param code_added The number of lines of code added in this delta. + * @param code_removed The number of lines of code removed in this delta. + * @param comments_added The number of lines of comments added in this delta. + * @param comments_removed The number of lines of comments removed in this + * delta. + * @param blanks_added The number of blank lines added in this delta. + * @param blanks_removed The number of blank lines removed in this delta. + * @return LocDelta + */ +LocDelta *ohcount_loc_delta_new(const char *language, int code_added, + int code_removed, int comments_added, + int comments_removed, int blanks_added, + int blanks_removed); + +/** + * Returns the net number of lines of code in a given LocDelta. + * @param delta A LocDelta created from ohcount_loc_delta_new(). + */ +int ohcount_loc_delta_net_code(LocDelta *delta); + +/** + * Returns the net number of lines of comments in a given LocDelta. + * @param delta A LocDelta created from ohcount_loc_delta_new(). + */ +int ohcount_loc_delta_net_comments(LocDelta *delta); + +/** + * Returns the net number of blank lines in a given LocDelta. + * @param delta A LocDelta created from ohcount_loc_delta_new(). + */ +int ohcount_loc_delta_net_blanks(LocDelta *delta); + +/** + * Returns the net number of lines in a given LocDelta. + * @param delta A LocDelta created from ohcount_loc_delta_new(). + */ +int ohcount_loc_delta_net_total(LocDelta *delta); + +/** + * Adds a LocDelta to another, provided they use the same language. + * The results are stored in the first LocDelta given. The second LocDelta may + * be 'free'd immediately. + * @param delta A LocDelta created from ohcount_loc_delta_new(). + * @param other Another LocDelta. + */ +void ohcount_loc_delta_add_loc_delta(LocDelta *delta, LocDelta *other); + +/** + * Returns whether or not a given LocDelta has any line changes. + * @param delta A LocDelta created from ohcount_loc_delta_new(). + */ +int ohcount_loc_delta_is_changed(LocDelta *delta); + +/** + * Returns whether or not two given LocDeltas are equivalent. + * @param delta A LocDelta created from ohcount_loc_delta_new(). + * @param other Another LocDelta. + */ +int ohcount_loc_delta_is_equal(LocDelta *delta, LocDelta *other); + +/** + * Frees the memory allocated for a given LocDelta. + * @param delta A LocDelta created from ohcount_loc_delta_new(). + */ +void ohcount_loc_delta_free(LocDelta *delta); + +/** + * Creates a new LocDeltaList that is initially empty. + * LocDeltas can be added using ohcount&oc_delta_list_add_loc_delta(). + * @return LocDeltaList + */ +LocDeltaList *ohcount_loc_delta_list_new(); + +/** + * Adds a given LocDelta to a LocDeltaList. + * The given LocDelta is copied and may be 'free'd immediately. + * @param list A LocDeltaList created from ohcount_loc_delta_list_new(). + * @param delta A LocDelta created from ohcount_loc_delta_new(). + */ +void ohcount_loc_delta_list_add_loc_delta(LocDeltaList *list, LocDelta *delta); + +/** + * Adds a given LocDeltaList to another LocDeltaList. + * The results are stored in the first LocDeltaList given. The second + * LocDeltaList may be 'free'd immediately. + * @param list A LocDeltaList created from ohcount_loc_delta_list_new(). + * @param loc_delta_list Another LocDeltaList. + */ +void ohcount_loc_delta_list_add_loc_delta_list(LocDeltaList *list, + LocDeltaList *loc_delta_list); + +/** + * Returns a LocDelta from a given LocDeltaList and language. + * The returned pointer is used internally and may not be 'free'd. + * @param list A LocDeltaList created from ohcount_loc_delta_list_new(). + * @param language The language of the LocDelta to retrieve. + * @return LocDelta or NULL. + */ +LocDelta *ohcount_loc_delta_list_get_loc_delta(LocDeltaList *list, + const char *language); + +/** + * Returns the number of lines of code added for the given LocDeltaList. + * @param list A LocDeltaList created from ohcount_loc_delta_list_new(). + */ +int ohcount_loc_delta_list_code_added(LocDeltaList *list); + +/** + * Returns the number of lines of code removed for the given LocDeltaList. + * @param list A LocDeltaList created from ohcount_loc_delta_list_new(). + */ +int ohcount_loc_delta_list_code_removed(LocDeltaList *list); + +/** + * Returns the number of lines of comments added for the given LocDeltaList. + * @param list A LocDeltaList created from ohcount_loc_delta_list_new(). + */ +int ohcount_loc_delta_list_comments_added(LocDeltaList *list); + +/** + * Returns the number of lines of comments removed for the given LocDeltaList. + * @param list A LocDeltaList created from ohcount_loc_delta_list_new(). + */ +int ohcount_loc_delta_list_comments_removed(LocDeltaList *list); + +/** + * Returns the number of blank lines added for the given LocDeltaList. + * @param list A LocDeltaList created from ohcount_loc_delta_list_new(). + */ +int ohcount_loc_delta_list_blanks_added(LocDeltaList *list); + +/** + * Returns the number of blank lines removed for the given LocDeltaList. + * @param list A LocDeltaList created from ohcount_loc_delta_list_new(). + */ +int ohcount_loc_delta_list_blanks_removed(LocDeltaList *list); + +/** + * Returns the net number of lines of code for the given LocDeltaList. + * @param list A LocDeltaList created from ohcount_loc_delta_list_new(). + */ +int ohcount_loc_delta_list_net_code(LocDeltaList *list); + +/** + * Returns the net number of lines of comments for the given LocDeltaList. + * @param list A LocDeltaList created from ohcount_loc_delta_list_new(). + */ +int ohcount_loc_delta_list_net_comments(LocDeltaList *list); + +/** + * Returns the net number of blank lines for the given LocDeltaList. + * @param list A LocDeltaList created from ohcount_loc_delta_list_new(). + */ +int ohcount_loc_delta_list_net_blanks(LocDeltaList *list); + +/** + * Returns the net number of lines for the given LocDeltaList. + * @param list A LocDeltaList created from ohcount_loc_delta_list_new(). + */ +int ohcount_loc_delta_list_net_total(LocDeltaList *list); + +/** + * Creates a new LocDeltaList from a given one, excluding all LocDeltas with no + * counted lines. + * The given list may be 'free'd immediately. + * @param list A LocDeltaList created from ohcount_loc_delta_list_new(). + */ +LocDeltaList *ohcount_loc_delta_list_new_compact(LocDeltaList *list); + +/** + * Frees the memory allocated for a given LocDeltaList. + * @param list A LocDeltaList created from ohcount_loc_delta_list_new(). + */ +void ohcount_loc_delta_list_free(LocDeltaList *list); + +#endif diff --git a/src/ohcount.c b/src/ohcount.c new file mode 100644 index 0000000..4b7d528 --- /dev/null +++ b/src/ohcount.c @@ -0,0 +1,316 @@ +// ohcount.c written by Mitchell Foral. mitchellcaladbolg.net. +// See COPYING for license information. + +#include +#include +#include + +#include "hash/option_hash.h" +#include "sourcefile.h" +#include "ohcount.h" + +void annotate_callback(const char *language, const char *entity, int start, + int end, void *userdata) { + SourceFile *sf = (SourceFile *)userdata; + int length = end - start; + char buf[length]; + strncpy(buf, (const char*)sf->contents + start, length); // field exists + buf[length] = '\0'; + printf("%s\t%s\t%s", language, entity, buf); +} + +void annotate(SourceFileList *list) { + SourceFileList *iter = list->head; + while (iter) { + ohcount_sourcefile_parse_with_callback(iter->sf, annotate_callback, + iter->sf); + iter = iter->next; + } +} + +void detect(SourceFileList *list) { + SourceFileList *iter = list->head; + while (iter) { + printf("%s\t%s\n", ohcount_sourcefile_get_language(iter->sf), + iter->sf->filepath); + iter = iter->next; + } +} + +void licenses(SourceFileList *list) { + SourceFileList *iter = list->head; + while (iter) { + LicenseList *liter = ohcount_sourcefile_get_license_list(iter->sf)->head; + while (liter) { + printf("%s%s ", liter->lic->name, (liter->next != NULL) ? "," : ""); + printf("%s\n", iter->sf->filename); + liter = liter->next; + } + iter = iter->next; + } +} + +void raw_entities_callback(const char *language, const char *entity, int start, + int end, void *userdata) { + printf("%s\t%s\t%i\t%i\n", language, entity, start, end); +} + +void raw_entities(SourceFileList *list) { + SourceFileList *iter = list->head; + while (iter) { + ohcount_sourcefile_parse_entities_with_callback(iter->sf, + raw_entities_callback, + NULL); + iter = iter->next; + } +} + +void help() { + printf( + "Usage: ohcount [option] [paths...]\n" + "\n" + "Ohloh source code line counter command line tool.\n" + " http://www.ohloh.net/\n" + "\n" + "[option] can be one of the following:\n" + " -a, --annotate\n" + " -d, --detect\n" + " -h, --help\n" + " -g, --gestalt\n" + " -i, --individual\n" + " -l, --license\n" + " -re\n" + " -s, --summary\n" + "\n" + "-a, --annotate Show annotated source code\n" + "\n" + " The contents of all source code files found within the given\n" + " paths will be emitted to stdout. Each line will be prefixed with\n" + " a tab-delimited language name and semantic categorization (code,\n" + " comment, or blank).\n" + "\n" + "-d, --detect Find source code files\n" + "\n" + " Recursively find all source code files within the given paths.\n" + " For each source code file found, the file name will be emitted to\n" + " stdout prefixed with a tab-delimited language name.\n" + "\n" + "-h, --help Display this message\n" + "\n" + "-g, --gestalt Project Properties\n" + "\n" + " Inspects project contents to determine what platform(s) the project\n" + " runs on, as well as any detected tools/IDEs used to develop it.\n" + "\n" + "-i, --individual Count lines of code per file\n" + "\n" + " Count lines in all source code files within the given paths, and\n" + " emit a report of the lines of code, comments, and blanks in each\n" + " language per file.\n" + "\n" + "-l, --license\n" + "\n" + " Displays detected licensing information contained in each source\n" + " code file.\n" + "\n" + "-re\n" + "\n" + " Prints raw entity information to the screen (mainly for debugging).\n" + "\n" + "-s, --summary Count lines of code (default)\n" + "\n" + " Count lines in all source code files within the given paths, and\n" + " emit a report of the total number of lines of code, comments,\n" + " and blanks in each language. This is the default action.\n" + "\n" + "[paths] can refer to any number of individual files or directories.\n" + " Directories will be probed recursively. If no path is given,\n" + " the current directory will be used.\n" + ); +} + +void sort_loc_list_by_language(LocList *list) { + LocList *iter = list->head; + while (iter) { + LocList *min = iter; + LocList *iter2 = iter->next; + while (iter2) { + if (strcmp(iter2->loc->language, min->loc->language) < 0) + min = iter2; + iter2 = iter2->next; + } + if (iter != min) { + Loc *temp = iter->loc; + iter->loc = min->loc; + min->loc = temp; + } + iter = iter->next; + } +} + +void individual(SourceFileList *list) { + int count = 0; + SourceFileList *titer = list->head; + while (titer) { + count++; + titer = titer->next; + } + printf( + "Examining %i file(s)\n" + " Ohloh Line Count \n" + "Language Code Comment Comment %% Blank Total File\n" + "---------------- --------- --------- --------- --------- --------- -----------------------------------------------\n" + , count); + SourceFileList *iter = list->head; + while (iter) { + LocList *loc_list = ohcount_sourcefile_get_loc_list(iter->sf); + sort_loc_list_by_language(loc_list); + LocList *liter = loc_list->head; + while (liter) { + printf("%-16s", liter->loc->language); + printf(" %10d", liter->loc->code); + printf(" %10d", liter->loc->comments); + if (liter->loc->comments + liter->loc->code > 0) + printf(" %9.1f%%", + (float)liter->loc->comments / (liter->loc->comments + + liter->loc->code) * 100); + else + printf(" "); + printf(" %10d", liter->loc->blanks); + printf(" %10d", + liter->loc->code + liter->loc->comments + liter->loc->blanks); + printf(" %s\n", iter->sf->filename); + liter = liter->next; + } + iter = iter->next; + } +} + +void sort_loc_list_by_code(LocList *list) { + LocList *iter = list->head; + while (iter) { + LocList *max = iter; + LocList *iter2 = iter->next; + while (iter2) { + if (iter2->loc->code > max->loc->code) + max = iter2; + iter2 = iter2->next; + } + if (iter != max) { + Loc *temp = iter->loc; + iter->loc = max->loc; + max->loc = temp; + } + iter = iter->next; + } +} + +void summary(SourceFileList *list) { + int count = 0; + SourceFileList *tmpiter = list->head; + while (tmpiter) { + count++; + tmpiter = tmpiter->next; + } + printf("Examining %i file(s)\n", count); + LocList *loc_list = ohcount_sourcefile_list_analyze_languages(list); + sort_loc_list_by_code(loc_list); + printf( + "\n" + " Ohloh Line Count Summary \n" + "\n" + "Language Files Code Comment Comment %% Blank Total\n" + "---------------- ----- --------- --------- --------- --------- ---------\n"); + LocList *iter = loc_list->head; + while (iter) { + printf("%-16s", iter->loc->language); + printf(" %6d", iter->loc->filecount); + printf(" %10d", iter->loc->code); + printf(" %10d", iter->loc->comments); + if (iter->loc->comments + iter->loc->code > 0) + printf(" %9.1f%%", + (float)iter->loc->comments / (iter->loc->comments + + iter->loc->code) * 100); + else + printf(" 0.0%%"); + printf(" %10d", iter->loc->blanks); + printf(" %10d\n", + iter->loc->code + iter->loc->comments + iter->loc->blanks); + iter = iter->next; + } + printf("---------------- ----- --------- --------- --------- --------- ---------\n"); + int code = ohcount_loc_list_code(loc_list); + int comments = ohcount_loc_list_comments(loc_list); + int blanks = ohcount_loc_list_blanks(loc_list); + printf("%-16s", "Total"); + printf(" %6d", ohcount_loc_list_filecount(loc_list)); + printf(" %10d", code); + printf(" %10d", comments); + if (comments + code > 0) + printf(" %9.1f%%", (float)comments / (comments + code) * 100); + else + printf(" 0.0%%"); + printf(" %10d", blanks); + printf(" %10d\n", code + comments + blanks); + ohcount_loc_list_free(loc_list); +} + +int main(int argc, char *argv[]) { + int command = 0; + if (argc > 1) { + struct OhcountOption *opt = ohcount_hash_command_from_flag(argv[1], + strlen(argv[1])); + if (opt) + command = opt->value; + } + int i = 1; + if (command == 0) + command = COMMAND_SUMMARY; + else + i = 2; // parameter is not a file or directory + + SourceFileList *list = ohcount_sourcefile_list_new(); + if (i == argc) + ohcount_sourcefile_list_add_directory(list, "."); + for (; i < argc; i++) { + DIR *dir = opendir(argv[i]); + if (dir) { + ohcount_sourcefile_list_add_directory(list, argv[i]); + closedir(dir); + } else { + FILE *f = fopen(argv[i], "r"); + if (f) { + ohcount_sourcefile_list_add_file(list, argv[i]); + fclose(f); + } else printf("Bad argument: %s\n", argv[i]); + } + } + switch (command) { + case COMMAND_ANNOTATE: + annotate(list); + break; + case COMMAND_DETECT: + detect(list); + break; + case COMMAND_HELP: + help(); + break; + case COMMAND_GESTALT: + break; + case COMMAND_INDIVIDUAL: + individual(list); + break; + case COMMAND_LICENSES: + licenses(list); + break; + case COMMAND_RAWENTITIES: + raw_entities(list); + break; + case COMMAND_SUMMARY: + summary(list); + break; + } + ohcount_sourcefile_list_free(list); + + return 0; +} diff --git a/src/ohcount.h b/src/ohcount.h new file mode 100644 index 0000000..485cb90 --- /dev/null +++ b/src/ohcount.h @@ -0,0 +1,129 @@ +// ohcount.h written by Mitchell Foral. mitchellcaladbolg.net. +// See COPYING for license information. + +#ifndef OHCOUNT_H +#define OHCOUNT_H + +/** + * @mainpage Ohcount + * + * The Ohloh source code line counter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 as + * published by the Free Software Foundation. + * + * Ohcount is specifically licensed under GPL v2.0, and no later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @section overview Overview + * + * Ohcount is a program for counting lines of source code. It was originally + * developed at Ohloh and used to generate the reports at www.ohloh.net + * + * Ohcount supports multiple languages within a single file: for example a + * complex HTML document might include regions of both CSS and Javascript. + * + * Ohcount has 4 main components: + * + * @li A detector which determines the primary language family used by a + * particular source file. + * @li A parser which provides a line-by-line breakdown of the contents of a + * source file. + * @li Another detector which tries to determine the license(s) the source file + * is licensed under. + * @li A final detector for gestalts. + * + * The command line tool allows you to profile individual files or whole + * directory trees. + * + * @section requirements System Requirements + * + * Ohcount is supported on Mac OSX 10.5 and Ubuntu 6.06 LTS. Other Linux + * environments should also work, but your mileage may vary. Windows is not + * supported. + * + * @section download Download + * + * Ohcount source code is available as a Git repository: + * + * git clone http://git.ohloh.net/git/ohcount.git + * + * @section build Building Ohcount + * + * In order to build Ohcount, the following is required: + * + * @li GNU C compiler - http://gcc.gnu.org/ + * @li Ragel 6.3 or later - http://research.cs.queensu.ca/~thurston/ragel/ + * @li GNU gperf - http://www.gnu.org/software/gperf/ + * @li PCRE - http://pcre.sourceforge.net/ + * + * Run the 'build' script to build Ohcount. + * + * @code + * $ ./build + * @endcode + * + * You may then link or copy 'bin/ohcount' to your system's PATH. + * + * @section start First Steps + * + * To measure lines of code, simply pass file or directory names to the + * bin/ohcount executable: + * + * @code + * $ ohcount helloworld.c + * @endcode + * + * Directories will be probed recursively. If you do not pass any parameters, + * the current directory tree will be counted. + * + * You can use the ohcount 'detect' option to simply determine the language + * family of each source file. The files will not be parsed or counted. For + * example, to find all of the Ruby files in the current directory tree: + * + * @code + * $ ohcount --detect | grep ^ruby + * @endcode + * + * The 'annotate' option presents a line-by-line accounting of the languages + * used in a source code file. For example: + * + * @code + * $ ohcount --annotate ./test/src_dir/php1.php + * @endcode + * + * More options can be found by typing: + * + * @code + * $ ohcount --help + * @endcode + * + * @section docs Additional Documentation + * + * See the Related Pages tab at the top of the page. + * + * @section contact Contact Ohloh + * + * For more information visit the Ohloh website: http://labs.ohloh.net + * + * You can reach Ohloh via email at: info@ohloh.net + */ + +#define COMMAND_ANNOTATE 1 +#define COMMAND_DETECT 2 +#define COMMAND_HELP 3 +#define COMMAND_GESTALT 4 +#define COMMAND_INDIVIDUAL 5 +#define COMMAND_LICENSES 6 +#define COMMAND_RAWENTITIES 7 +#define COMMAND_SUMMARY 8 + +#endif diff --git a/src/parsed_language.c b/src/parsed_language.c new file mode 100644 index 0000000..70092cf --- /dev/null +++ b/src/parsed_language.c @@ -0,0 +1,73 @@ +// parsed_language.c written by Mitchell Foral. mitchellcaladbolg.net. +// See COPYING for license information. + +#include +#include + +#include "parsed_language.h" + +ParsedLanguage *ohcount_parsed_language_new(const char *language, + int buffer_size) { + ParsedLanguage *pl = malloc(sizeof(ParsedLanguage)); + pl->language = language; + pl->buffer_size = buffer_size; + pl->code = malloc(buffer_size + 5); + pl->code_p = pl->code; + *pl->code_p = '\0'; + pl->code_count = 0; + pl->comments = malloc(buffer_size + 5); + pl->comments_p = pl->comments; + *pl->comments_p = '\0'; + pl->comments_count = 0; + pl->blanks_count = 0; + return pl; +} + +void ohcount_parsed_language_add_code(ParsedLanguage *parsed_language, + char *p, int length) { + if (parsed_language->code_p + length < + parsed_language->code + parsed_language->buffer_size + 5) { + strncpy(parsed_language->code_p, p, length); + parsed_language->code_p += length; + *parsed_language->code_p = '\0'; + parsed_language->code_count++; + } +} + +void ohcount_parsed_language_add_comment(ParsedLanguage *parsed_language, + char *p, int length) { + if (parsed_language->comments_p + length < + parsed_language->comments + parsed_language->buffer_size + 5) { + strncpy(parsed_language->comments_p, p, length); + parsed_language->comments_p += length; + *parsed_language->comments_p = '\0'; + parsed_language->comments_count++; + } +} + +void ohcount_parsed_language_free(ParsedLanguage *parsed_language) { + free(parsed_language->code); + free(parsed_language->comments); + free(parsed_language); +} + +ParsedLanguageList *ohcount_parsed_language_list_new() { + ParsedLanguageList *list = malloc(sizeof(ParsedLanguageList)); + list->pl = NULL; + list->next = NULL; + list->head = NULL; + list->tail = NULL; + return list; +} + +void ohcount_parsed_language_list_free(ParsedLanguageList *list) { + if (list->head) { + ParsedLanguageList *iter = list->head; + while (iter) { + ParsedLanguageList *next = iter->next; + ohcount_parsed_language_free(iter->pl); + free(iter); + iter = next; + } + } else free(list); +} diff --git a/src/parsed_language.h b/src/parsed_language.h new file mode 100644 index 0000000..9c9db72 --- /dev/null +++ b/src/parsed_language.h @@ -0,0 +1,60 @@ +// parsed_language.h written by Mitchell Foral. mitchellcaladbolg.net. +// See COPYING for license information. + +#ifndef OHCOUNT_PARSED_LANGUAGE_H +#define OHCOUNT_PARSED_LANGUAGE_H + +#include "structs.h" + +/** + * Creates a new ParsedLanguage for the given language and buffer size. + * The given language is not copied and may not be 'free'd. Use a language + * defined in src/languages.h. + * @param language The parsed language. + * @param buffer_size The size of the buffers to store parsed code and comment + * text. + * @return ParsedLanguage + */ +ParsedLanguage *ohcount_parsed_language_new(const char *language, + int buffer_size); + +/** + * Adds some code to the code buffer for the given ParsedLanguage. + * @param parsed_language A ParsedLanguage created from + * ohcount_parsed_language_new(). + * @param p A pointer in memory to start copying code from. + * @param length The number of characters to copy from p. + */ +void ohcount_parsed_language_add_code(ParsedLanguage *parsed_language, + char *p, int length); + +/** + * Adds a comment to the comment buffer for the given ParsedLanguage. + * @param parsed_language A ParsedLanguage created from + * ohcount_parsed_language_new(). + * @param p A pointer in memory to start copying the comment from. + * @param length The number of characters to copy from p. + */ +void ohcount_parsed_language_add_comment(ParsedLanguage *parsed_language, + char *p, int length); + +/** + * Frees the memory allocated for the given ParsedLanguage. + * @param parsed_language A ParsedLanguage created from + * ohcount_parsed_language_new(). + */ +void ohcount_parsed_language_free(ParsedLanguage *parsed_language); + +/** + * Creates a new ParsedLanguageList that is initially empty. + * @return ParsedLanguageList + */ +ParsedLanguageList *ohcount_parsed_language_list_new(); + +/** + * Frees the memory allocated for the given ParsedLanguageList. + * @param list A ParsedLanguage created from ohcount_parsed_language_list_new(). + */ +void ohcount_parsed_language_list_free(ParsedLanguageList *list); + +#endif diff --git a/src/parser.c b/src/parser.c new file mode 100644 index 0000000..2911af7 --- /dev/null +++ b/src/parser.c @@ -0,0 +1,27 @@ +// parser.c written by Mitchell Foral. mitchellcaladbolg.net. +// See COPYING for license information. + +#include + +#include "sourcefile.h" +#include "hash/parser_hash.h" + +int ohcount_parse(SourceFile *sourcefile, int count, + void (*callback) (const char *, const char *, int, int, + void *), + void *userdata) { + const char *language = ohcount_sourcefile_get_language(sourcefile); + if (language) { + struct ParserMap *rp = + ohcount_hash_parser_from_language(language, strlen(language)); + if (rp) { + char *buffer = ohcount_sourcefile_get_contents(sourcefile); + int buffer_len = ohcount_sourcefile_get_contents_size(sourcefile); + if (callback) + rp->parser(buffer, buffer_len, count, callback, userdata); + return 1; + } + } + + return 0; +} diff --git a/src/parser.h b/src/parser.h new file mode 100644 index 0000000..370fbe5 --- /dev/null +++ b/src/parser.h @@ -0,0 +1,303 @@ +// parser.h written by Mitchell Foral. mitchellcaladbolg.net. +// See COPYING for license information. + +#ifndef OHCOUNT_PARSER_H +#define OHCOUNT_PARSER_H + +#include "sourcefile.h" + +/** + * @page parser_doc Parser Documentation + * @author Mitchell Foral + * + * @section overview Overview + * + * I will assume the reader has a decent knowledge of how Ragel works and the + * Ragel syntax. If not, please review the Ragel manual found at: + * http://research.cs.queensu.ca/~thurston/ragel/ + * + * All parsers must at least: + * + * @li Call a callback function when a line of code is parsed. + * @li Call a callback function when a line of comment is parsed. + * @li Call a callback function when a blank line is parsed. + * + * Additionally a parser can call the callback function for each position of + * entities parsed. + * + * Take a look at 'c.rl' and even keep it open for reference when reading this + * document to better understand how parsers work and how to write one. + * + * @section writing Writing a Parser + * + * First create your parser in 'src/parsers/'. Its name should be the language + * you are parsing with a '.rl' extension. You will not have to manually compile + * any parsers, as this is automatically for you. However, you do need to add + * your parser to 'hash/parsers.gperf'. + * + * Every parser must have the following at the top: + * + * @include parser_doc_1 + * + * And the following at the bottom: + * + * @include parser_doc_2 + * + * (Your parser will go between these two blocks.) + * + * The code can be found in the existing 'c.rl' parser. You will need to change: + * @li OHCOUNT_[lang]_PARSER_H - Replace [lang] with your language name. So if + * you are writing a C parser, it would be OHCOUNT_C_PARSER_H. + * @li [lang]_LANG - Set the variable name to be [lang]_LANG and its value to be + * the name of your language to parse as defined in languages.h. [lang] is + * your language name. For C it would be C_LANG. + * @li [lang]_entities - Set the variable name to be [lang]_entities (e.g. + * c_entries) The value is an array of string entities your language has. For + * example C has comment, string, number, etc. entities. You should definately + * have "space", and "any" entities. "any" entities are typically used for + * entity machines (discussed later) and match any character that is not + * recognized so the parser does not do something unpredictable. + * @li enum - Change the value of the enum to correspond with your entities. So + * if in your parser you look up [lang]_entities[ENTITY], you will get the + * associated entity's string name. + * @li parse_[lang] - Set the function name to parse_[lang] where again, [lang] + * is the name of your language. In the case of C, it is parse_c. + * @li [lang]_en_[lang]_line - The line counting machine. + * @li [lang]_en_[lang]_entity - The entity machine. + * + * You may be asking why you have to rename variables and functions. Well if + * variables have the same name in header files (which is what parsers are), the + * compiler complains. Also, when you have languages embedded inside each other, + * any identifiers with the same name can easily be mixed up. It is also + * important to prefix your Ragel definitions with your language to avoid + * conflicts with other parsers. + * + * Additional variables available to parsers are in the parser_macros.h file. + * Take a look at it and try to understand what the variables are used for. They + * will make more sense later on. + * + * Now you can define your Ragel parser. Name your machine after your language, + * "write data", and include 'common.rl', a file with common Ragel definitions, + * actions, etc. For example: + * + * @include parser_doc_3 + * + * Before you begin to write patterns for each entity in your language, you need + * to understand how the parser should work. + * + * Each parser has two machines: one optimized for counting lines of code, + * comments, and blanks; the other for identifying entity positions in the + * buffer. + * + * @section line Line Counting Machine + * + * This machine should be written as a line-by-line parser for multiple lines. + * This means you match any combination of entities except a newline up until + * you do reach a newline. If the line contains only spaces, or nothing at all, + * it is blank. If the line contains spaces at first, but then a comment, or + * just simply a comment, the line is a comment. If the line contains anything + * but a comment after spaces (if there are any), it is a line of code. You + * will do this using a Ragel scanner. The callback function will be called for + * each line parsed. + * + * @subsection line_scanner Scanner Parser Structure + * + * A scanner parser will look like this: + * + * @include parser_doc_4 + * + * (As usual, replace [lang] with your language name.) + * + * Each entity is the pattern for an entity to match, the last one typically + * being the newline entity. For each match, the variable is set to a constant + * defined in the enum, and the main action is called (you will need to create + * this action above the scanner). + * + * When you detect whether or not a line is code or comment, you should call the + * appropriate \@code or \@comment action defined in 'common.rl' as soon as + * possible. It is not necessary to worry about whether or not these actions are + * called more than once for a given line; the first call to either sets the + * status of the line permanently. Sometimes you cannot call \@code or \@comment + * for one reason or another. Do not worry, as this is discussed later. + * + * When you reach a newline, you will need to decide whether the current line is + * a line of code, comment, or blank. This is easy. Simply check if the + * #line_contains_code or #whole_line_comment variables are set to 1. If neither + * of them are, the line is blank. Then call the callback function (not action) + * with an "lcode", "lcomment", or "lblank" string, and the start and end + * positions of that line (including the newline). The start position of the + * line is in the #line_start variable. It should be set at the beginning of + * every line either through the \@code or \@comment actions, or manually in the + * main action. Finally the #line_contains_code, #whole_line_comment, and + * #line_start state variables must be reset. All this should be done within the + * main action shown below. Note: For most parsers, the std_newline(lang) macro + * is sufficient and does everything in the main action mentioned above. The + * lang parameter is the [lang]_LANG string. + * + * @subsection line_action Main Action Structure + * + * The main action looks like this: + * + * @include parser_doc_5 + * + * @subsection line_entity_patterns Defining Patterns for Entities + * + * Now it is time to write patterns for each entity in your language. That does + * not seem very hard, except when your entity can cover multiple lines. + * Comments and strings in particular can do this. To make an accurate line + * counter, you will need to count the lines covered by multi-line entities. + * When you detect a newline inside your multi-line entity, you should set the + * entity variable to be #INTERNAL_NL and call the main action. The main action + * should have a case for #INTERNAL_NL separate from the newline entity. In it, + * you will check if the current line is code or comment and call the callback + * function with the appropriate string ("lcode" or "lcomment") and beginning + * and end of the line (including the newline). Afterwards, you will reset the + * #line_contains_code and #whole_line_comment state variables. Then set the + * #line_start variable to be #p, the current Ragel buffer position. Because + * #line_contains_code and #whole_line_comment have been reset, any non-newline + * and non-space character in the multi-line pattern should set + * #line_contains_code or #whole_line_comment back to 1. Otherwise you would count + * the line as blank. + * + * Note: For most parsers, the std_internal_newline(lang) macro is sufficient + * and does everything in the main action mentioned above. The lang parameter + * is the [lang]_LANG string. + * + * For multi-line matches, it is important to call the \@code or \@comment + * actions (mentioned earlier) before an internal newline is detected so the + * #line_contains_code and #whole_line_comment variables are properly set. For + * other entities, you can use the #code macro inside the main action which + * executes the same code as the Ragel \@code action. Other C macros are + * #comment and #ls, the latter is typically used for the SPACE entity when + * defining #line_start. + * + * Also for multi-line matches, it may be necessary to use the \@enqueue and + * \@commit actions. If it is possible that a multi-line entity will not have an + * ending delimiter (for example a string), use the \@enqueue action as soon as + * the start delimitter has been detected, and the \@commit action as soon as + * the end delimitter has been detected. This will eliminate the potential for + * any counting errors. + * + * @subsection line_notes Notes + * + * You can be a bit sloppy with the line counting machine. For example the only + * C entities that can contain newlines are strings and comments, so + * #INTERNAL_NL would only be necessary inside them. Other than those, anything + * other than spaces is considered code, so do not waste your time defining + * specific patterns for other entities. + * + * @subsection line_embedded Parsers with Embedded Languages + * + * Notation: [lang] is the parent language, [elang] is the embedded language. + * + * To write a parser with embedded languages (such as HTML with embedded CSS and + * Javascript), you should first \#include the parser(s) above your Ragel code. + * The header file is "[elang]_parser.h". + * + * Next, after the inclusion of 'common.rl', add "#EMBED([elang])" on separate + * lines for each embedded language. The build process looks for these special + * comments to embed the language for you automatically. + * + * In your main action, you need to add another entity #CHECK_BLANK_ENTRY. It + * should call the #check_blank_entry([lang]_LANG) macro. Blank entries are an + * entry into an embedded language, but the rest of the line is blank before a + * newline. For example, a CSS entry in HTML is something like: + * + * @code + * "), + "comment", "/*comment*/" + ); + test_parser_verify_entity( + test_parser_sourcefile("html", ""), + "comment", "//comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("html", ""), + "comment", "/*comment*/" + ); +} + +void all_html_tests() { + test_html_comment_entities(); +} diff --git a/test/unit/parsers/test_java.h b/test/unit/parsers/test_java.h new file mode 100644 index 0000000..e46afd8 --- /dev/null +++ b/test/unit/parsers/test_java.h @@ -0,0 +1,23 @@ + +void test_java_comments() { + test_parser_verify_parse( + test_parser_sourcefile("java", " //comment"), + "java", "", "//comment", 0 + ); +} + +void test_java_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("java", " //comment"), + "comment", "//comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("java", " /*comment*/"), + "comment", "/*comment*/" + ); +} + +void all_java_tests() { + test_java_comments(); + test_java_comment_entities(); +} diff --git a/test/unit/parsers/test_javascript.h b/test/unit/parsers/test_javascript.h new file mode 100644 index 0000000..766bb09 --- /dev/null +++ b/test/unit/parsers/test_javascript.h @@ -0,0 +1,23 @@ + +void test_javascript_comments() { + test_parser_verify_parse( + test_parser_sourcefile("javascript", " //comment"), + "javascript", "", "//comment", 0 + ); +} + +void test_javascript_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("javascript", " //comment"), + "comment", "//comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("javascript", " /*comment*/"), + "comment", "/*comment*/" + ); +} + +void all_javascript_tests() { + test_javascript_comments(); + test_javascript_comment_entities(); +} diff --git a/test/unit/parsers/test_jsp.h b/test/unit/parsers/test_jsp.h new file mode 100644 index 0000000..0aada71 --- /dev/null +++ b/test/unit/parsers/test_jsp.h @@ -0,0 +1,31 @@ + +void test_jsp_comment() { + test_parser_verify_parse2( + test_parser_sourcefile("jsp", " <% //comment\n%>"), + "java", "", "<% //comment\n", 0, + "html", "%>", "", 0 + ); +} + +void test_jsp_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("jsp", " "), + "comment", "" + ); + test_parser_verify_entity( + test_parser_sourcefile("jsp", ""), + "comment", "/*comment*/" + ); + test_parser_verify_entity( + test_parser_sourcefile("jsp", "<%\n//comment\n%>"), + "comment", "//comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("jsp", "<%\n/*comment*/\n%>"), + "comment", "/*comment*/" + ); +} + +void all_jsp_tests() { + test_jsp_comment_entities(); +} diff --git a/test/unit/parsers/test_lisp.h b/test/unit/parsers/test_lisp.h new file mode 100644 index 0000000..abbc21c --- /dev/null +++ b/test/unit/parsers/test_lisp.h @@ -0,0 +1,51 @@ + +void test_lisp_comment() { + test_parser_verify_parse( + test_parser_sourcefile("lisp", " ;;; comment"), + "lisp", "", ";;; comment", 0 + ); +} + +void test_lisp_doc_string() { + test_parser_verify_parse( + test_parser_sourcefile("lisp", " \"\"\" comment \"\"\""), + "lisp", "", "\"\"\" comment \"\"\"", 0 + ); +} + +void test_lisp_doc_string_blank() { + test_parser_verify_parse( + test_parser_sourcefile("lisp", " \"\"\"\"\"\""), + "lisp", "", "\"\"\"\"\"\"", 0 + ); +} + +void test_lisp_empty_string() { + test_parser_verify_parse( + test_parser_sourcefile("lisp", "\"\""), + "lisp", "\"\"", "", 0 + ); +} + +void test_lisp_char_string() { + test_parser_verify_parse( + test_parser_sourcefile("lisp", " \"a\""), + "lisp", "\"a\"", "", 0 + ); +} + +void test_lisp_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("lisp", " ;comment"), + "comment", ";comment" + ); +} + +void all_lisp_tests() { + test_lisp_comment(); + test_lisp_doc_string(); + test_lisp_doc_string_blank(); + test_lisp_empty_string(); + test_lisp_char_string(); + test_lisp_comment_entities(); +} diff --git a/test/unit/parsers/test_lua.h b/test/unit/parsers/test_lua.h new file mode 100644 index 0000000..0f3bf97 --- /dev/null +++ b/test/unit/parsers/test_lua.h @@ -0,0 +1,23 @@ + +void test_lua_comments() { + test_parser_verify_parse( + test_parser_sourcefile("lua", " -- comment"), + "lua", "", "-- comment", 0 + ); +} + +void test_lua_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("lua", " --comment"), + "comment", "--comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("lua", " --[[comment\ncomment]]"), + "comment", "--[[comment\ncomment]]" + ); +} + +void all_lua_tests() { + test_lua_comments(); + test_lua_comment_entities(); +} diff --git a/test/unit/parsers/test_make.h b/test/unit/parsers/test_make.h new file mode 100644 index 0000000..b4b4e2a --- /dev/null +++ b/test/unit/parsers/test_make.h @@ -0,0 +1,11 @@ + +void test_make_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("make", " #comment"), + "comment", "#comment" + ); +} + +void all_make_tests() { + test_make_comment_entities(); +} diff --git a/test/unit/parsers/test_matlab.h b/test/unit/parsers/test_matlab.h new file mode 100644 index 0000000..47c8cbd --- /dev/null +++ b/test/unit/parsers/test_matlab.h @@ -0,0 +1,43 @@ + +void test_matlab_line_comment_1() { + test_parser_verify_parse( + test_parser_sourcefile("matlab", " %comment"), + "matlab", "", "%comment", 0 + ); +} + +void test_matlab_ancient_syntax_comment() { + test_parser_verify_parse( + test_parser_sourcefile("matlab", " ... comment"), + "matlab", "", "... comment", 0 + ); +} + +void test_matlab_false_line_comment() { + test_parser_verify_parse( + test_parser_sourcefile("matlab", " %{block%} code"), + "matlab", "%{block%} code", "", 0 + ); +} + +void test_matlab_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("matlab", " %comment"), + "comment", "%comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("matlab", " ... comment"), + "comment", "... comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("matlab", " %{comment%}"), + "comment", "%{comment%}" + ); +} + +void all_matlab_tests() { + test_matlab_line_comment_1(); + test_matlab_ancient_syntax_comment(); + test_matlab_false_line_comment(); + test_matlab_comment_entities(); +} diff --git a/test/unit/parsers/test_metafont.h b/test/unit/parsers/test_metafont.h new file mode 100644 index 0000000..d9f68a4 --- /dev/null +++ b/test/unit/parsers/test_metafont.h @@ -0,0 +1,19 @@ + +void test_metafont_comments() { + test_parser_verify_parse( + test_parser_sourcefile("metafont", " % comment"), + "metafont", "", "% comment", 0 + ); +} + +void test_metafont_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("metafont", " %comment"), + "comment", "%comment" + ); +} + +void all_metafont_tests() { + test_metafont_comments(); + test_metafont_comment_entities(); +} diff --git a/test/unit/parsers/test_metapost.h b/test/unit/parsers/test_metapost.h new file mode 100644 index 0000000..9982b06 --- /dev/null +++ b/test/unit/parsers/test_metapost.h @@ -0,0 +1,23 @@ + +void test_metapost_comments() { + test_parser_verify_parse( + test_parser_sourcefile("metapost", " % comment"), + "metapost", "", "% comment", 0 + ); +} + +void test_metapost_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("metapost", " %comment"), + "comment", "%comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("metapost", "verbatim\n%comment\netex"), + "comment", "%comment" + ); +} + +void all_metapost_tests() { + test_metapost_comments(); + test_metapost_comment_entities(); +} diff --git a/test/unit/parsers/test_mxml.h b/test/unit/parsers/test_mxml.h new file mode 100644 index 0000000..f32bdda --- /dev/null +++ b/test/unit/parsers/test_mxml.h @@ -0,0 +1,23 @@ + +void test_mxml_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("mxml", " "), + "comment", "" + ); + test_parser_verify_entity( + test_parser_sourcefile("mxml", "\n/*comment*/\n"), + "comment", "/*comment*/" + ); + test_parser_verify_entity( + test_parser_sourcefile("mxml", "\n//comment\n"), + "comment", "//comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("mxml", "\n/*comment*/\n"), + "comment", "/*comment*/" + ); +} + +void all_mxml_tests() { + test_mxml_comment_entities(); +} diff --git a/test/unit/parsers/test_nix.h b/test/unit/parsers/test_nix.h new file mode 100644 index 0000000..26aefb2 --- /dev/null +++ b/test/unit/parsers/test_nix.h @@ -0,0 +1,11 @@ + +void test_nix_line_comments() { + test_parser_verify_parse( + test_parser_sourcefile("nix", "# comment"), + "nix", "", "# comment", 0 + ); +} + +void all_nix_tests() { + test_nix_line_comments(); +} diff --git a/test/unit/parsers/test_objective_j.h b/test/unit/parsers/test_objective_j.h new file mode 100644 index 0000000..818e422 --- /dev/null +++ b/test/unit/parsers/test_objective_j.h @@ -0,0 +1,23 @@ + +void test_objective_j_comments() { + test_parser_verify_parse( + test_parser_sourcefile("objective_j", " //comment"), + "objective_j", "", "//comment", 0 + ); +} + +void test_objective_j_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("objective_j", " //comment"), + "comment", "//comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("objective_j", " /*comment*/"), + "comment", "/*comment*/" + ); +} + +void all_objective_j_tests() { + test_objective_j_comments(); + test_objective_j_comment_entities(); +} diff --git a/test/unit/parsers/test_ocaml.h b/test/unit/parsers/test_ocaml.h new file mode 100644 index 0000000..1293e05 --- /dev/null +++ b/test/unit/parsers/test_ocaml.h @@ -0,0 +1,19 @@ + +void test_ocaml_comments() { + test_parser_verify_parse( + test_parser_sourcefile("ocaml", " (* comment *)"), + "ocaml", "", "(* comment *)", 0 + ); +} + +void test_ocaml_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("ocaml", " (*comment*)"), + "comment", "(*comment*)" + ); +} + +void all_ocaml_tests() { + test_ocaml_comments(); + test_ocaml_comment_entities(); +} diff --git a/test/unit/parsers/test_octave.h b/test/unit/parsers/test_octave.h new file mode 100644 index 0000000..3ca84a6 --- /dev/null +++ b/test/unit/parsers/test_octave.h @@ -0,0 +1,39 @@ + +void test_octave_line_comment_1() { + test_parser_verify_parse( + test_parser_sourcefile("octave", " %comment"), + "octave", "", "%comment", 0 + ); +} + +void test_octave_syntax_comment() { + test_parser_verify_parse( + test_parser_sourcefile("octave", " # comment"), + "octave", "", "# comment", 0 + ); +} + +void test_octave_false_line_comment() { + test_parser_verify_parse( + test_parser_sourcefile("octave", " %{block%} code"), + "octave", "%{block%} code", "", 0 + ); +} + +void test_octave_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("octave", " %comment"), + "comment", "%comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("octave", " # comment"), + "comment", "# comment" + ); +} + +void all_octave_tests() { + test_octave_line_comment_1(); + test_octave_syntax_comment(); + test_octave_false_line_comment(); + test_octave_comment_entities(); +} diff --git a/test/unit/parsers/test_pascal.h b/test/unit/parsers/test_pascal.h new file mode 100644 index 0000000..65fea37 --- /dev/null +++ b/test/unit/parsers/test_pascal.h @@ -0,0 +1,27 @@ + +void test_pascal_comments() { + test_parser_verify_parse( + test_parser_sourcefile("pascal", " //comment"), + "pascal", "", "//comment", 0 + ); +} + +void test_pascal_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("pascal", " //comment"), + "comment", "//comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("pascal", " (*comment*)"), + "comment", "(*comment*)" + ); + test_parser_verify_entity( + test_parser_sourcefile("pascal", " {comment}"), + "comment", "{comment}" + ); +} + +void all_pascal_tests() { + test_pascal_comments(); + test_pascal_comment_entities(); +} diff --git a/test/unit/parsers/test_perl.h b/test/unit/parsers/test_perl.h new file mode 100644 index 0000000..8dd5ba2 --- /dev/null +++ b/test/unit/parsers/test_perl.h @@ -0,0 +1,23 @@ + +void test_perl_comments() { + test_parser_verify_parse( + test_parser_sourcefile("perl", " #comment"), + "perl", "", "#comment", 0 + ); +} + +void test_perl_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("perl", " #comment"), + "comment", "#comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("perl", "=head1\ncomment\n=cut"), + "comment", "=head1\ncomment\n=cut" + ); +} + +void all_perl_tests() { + test_perl_comments(); + test_perl_comment_entities(); +} diff --git a/test/unit/parsers/test_pike.h b/test/unit/parsers/test_pike.h new file mode 100644 index 0000000..62e3297 --- /dev/null +++ b/test/unit/parsers/test_pike.h @@ -0,0 +1,23 @@ + +void test_pike_comments() { + test_parser_verify_parse( + test_parser_sourcefile("pike", " //comment"), + "pike", "", "//comment", 0 + ); +} + +void test_pike_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("pike", " //comment"), + "comment", "//comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("pike", " /*comment*/"), + "comment", "/*comment*/" + ); +} + +void all_pike_tests() { + test_pike_comments(); + test_pike_comment_entities(); +} diff --git a/test/unit/parsers/test_python.h b/test/unit/parsers/test_python.h new file mode 100644 index 0000000..28ba7cd --- /dev/null +++ b/test/unit/parsers/test_python.h @@ -0,0 +1,39 @@ + +void test_python_comment() { + test_parser_verify_parse( + test_parser_sourcefile("python", " #comment"), + "python", "", "#comment", 0 + ); +} + +void test_python_doc_string() { + test_parser_verify_parse( + test_parser_sourcefile("python", " '''\n doc comment\n '''"), + "python", "", "'''\ndoc comment\n'''", 0 + ); +} + +void test_python_strings() { + test_parser_verify_parse( + test_parser_sourcefile("python", "\"abc#not a 'comment\""), + "python", "\"abc#not a 'comment\"", "", 0 + ); +} + +void test_python_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("python", " #comment"), + "comment", "#comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("python", " \"\"\"comment\"\"\""), + "comment", "\"\"\"comment\"\"\"" + ); +} + +void all_python_tests() { + test_python_comment(); + test_python_doc_string(); + test_python_strings(); + test_python_comment_entities(); +} diff --git a/test/unit/parsers/test_r.h b/test/unit/parsers/test_r.h new file mode 100644 index 0000000..350b310 --- /dev/null +++ b/test/unit/parsers/test_r.h @@ -0,0 +1,19 @@ + +void test_r_comments() { + test_parser_verify_parse( + test_parser_sourcefile("r", " #comment"), + "r", "", "#comment", 0 + ); +} + +void test_r_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("r", " #comment"), + "comment", "#comment" + ); +} + +void all_r_tests() { + test_r_comments(); + test_r_comment_entities(); +} diff --git a/test/unit/parsers/test_rexx.h b/test/unit/parsers/test_rexx.h new file mode 100644 index 0000000..a458f3c --- /dev/null +++ b/test/unit/parsers/test_rexx.h @@ -0,0 +1,19 @@ + +void test_rexx_comment() { + test_parser_verify_parse( + test_parser_sourcefile("rexx", " /*comment*/"), + "rexx", "", "/*comment*/", 0 + ); +} + +void test_rexx_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("rexx", " /*comment*/"), + "comment", "/*comment*/" + ); +} + +void all_rexx_tests() { + test_rexx_comment(); + test_rexx_comment_entities(); +} diff --git a/test/unit/parsers/test_rhtml.h b/test/unit/parsers/test_rhtml.h new file mode 100644 index 0000000..eb119f6 --- /dev/null +++ b/test/unit/parsers/test_rhtml.h @@ -0,0 +1,12 @@ + +void test_rhtml_comment() { + test_parser_verify_parse2( + test_parser_sourcefile("rhtml", "<%\n #comment\n%>"), + "html", "<%\n%>", "", 0, + "ruby", "", "#comment\n", 0 + ); +} + +void all_rhtml_tests() { + test_rhtml_comment(); +} diff --git a/test/unit/parsers/test_ruby.h b/test/unit/parsers/test_ruby.h new file mode 100644 index 0000000..e29843b --- /dev/null +++ b/test/unit/parsers/test_ruby.h @@ -0,0 +1,23 @@ + +void test_ruby_comments() { + test_parser_verify_parse( + test_parser_sourcefile("ruby", " #comment"), + "ruby", "", "#comment", 0 + ); +} + +void test_ruby_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("ruby", " #comment"), + "comment", "#comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("ruby", "=begin\ncomment\n=end"), + "comment", "=begin\ncomment\n=end" + ); +} + +void all_ruby_tests() { + test_ruby_comments(); + test_ruby_comment_entities(); +} diff --git a/test/unit/parsers/test_scala.h b/test/unit/parsers/test_scala.h new file mode 100644 index 0000000..5a124ee --- /dev/null +++ b/test/unit/parsers/test_scala.h @@ -0,0 +1,15 @@ + +void test_scala_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("scala", " //comment"), + "comment", "//comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("scala", " /*comment*/"), + "comment", "/*comment*/" + ); +} + +void all_scala_tests() { + test_scala_comment_entities(); +} diff --git a/test/unit/parsers/test_scheme.h b/test/unit/parsers/test_scheme.h new file mode 100644 index 0000000..9ba6062 --- /dev/null +++ b/test/unit/parsers/test_scheme.h @@ -0,0 +1,19 @@ + +void test_scheme_comments() { + test_parser_verify_parse( + test_parser_sourcefile("scheme", " ;;; comment"), + "scheme", "", ";;; comment", 0 + ); +} + +void test_scheme_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("scheme", " ;comment"), + "comment", ";comment" + ); +} + +void all_scheme_tests() { + test_scheme_comments(); + test_scheme_comment_entities(); +} diff --git a/test/unit/parsers/test_scilab.h b/test/unit/parsers/test_scilab.h new file mode 100644 index 0000000..f6bd60b --- /dev/null +++ b/test/unit/parsers/test_scilab.h @@ -0,0 +1,19 @@ + +void test_scilab_comments() { + test_parser_verify_parse( + test_parser_sourcefile("scilab", " //comment"), + "scilab", "", "//comment", 0 + ); +} + +void test_scilab_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("scilab", " //comment"), + "comment", "//comment" + ); +} + +void all_scilab_tests() { + test_scilab_comments(); + test_scilab_comment_entities(); +} diff --git a/test/unit/parsers/test_shell.h b/test/unit/parsers/test_shell.h new file mode 100644 index 0000000..2797532 --- /dev/null +++ b/test/unit/parsers/test_shell.h @@ -0,0 +1,19 @@ + +void test_shell_comments() { + test_parser_verify_parse( + test_parser_sourcefile("shell", " #comment"), + "shell", "", "#comment", 0 + ); +} + +void test_shell_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("shell", " #comment"), + "comment", "#comment" + ); +} + +void all_shell_tests() { + test_shell_comments(); + test_shell_comment_entities(); +} diff --git a/test/unit/parsers/test_smalltalk.h b/test/unit/parsers/test_smalltalk.h new file mode 100644 index 0000000..cbdc285 --- /dev/null +++ b/test/unit/parsers/test_smalltalk.h @@ -0,0 +1,19 @@ + +void test_smalltalk_comments() { + test_parser_verify_parse( + test_parser_sourcefile("smalltalk", " \"comment\\\""), + "smalltalk", "", "\"comment\\\"", 0 + ); +} + +void test_smalltalk_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("smalltalk", " \"comment\""), + "comment", "\"comment\"" + ); +} + +void all_smalltalk_tests() { + test_smalltalk_comments(); + test_smalltalk_comment_entities(); +} diff --git a/test/unit/parsers/test_sql.h b/test/unit/parsers/test_sql.h new file mode 100644 index 0000000..a6e85ed --- /dev/null +++ b/test/unit/parsers/test_sql.h @@ -0,0 +1,51 @@ + +void test_sql_comments() { + test_parser_verify_parse( + test_parser_sourcefile("sql", " --comment"), + "sql", "", "--comment", 0 + ); +} + +void test_sql_empty_comments() { + test_parser_verify_parse( + test_parser_sourcefile("sql", " --\n"), + "sql", "", "--\n", 0 + ); +} + +void test_sql_block_comment() { + test_parser_verify_parse( + test_parser_sourcefile("sql", " {sql}"), + "sql", "", "{sql}", 0 + ); +} + +void test_sql_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("sql", " --comment"), + "comment", "--comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("sql", " #comment"), + "comment", "#comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("sql", " //comment"), + "comment", "//comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("sql", " /*comment*/"), + "comment", "/*comment*/" + ); + test_parser_verify_entity( + test_parser_sourcefile("sql", " {comment}"), + "comment", "{comment}" + ); +} + +void all_sql_tests() { + test_sql_comments(); + test_sql_empty_comments(); + test_sql_block_comment(); + test_sql_comment_entities(); +} diff --git a/test/unit/parsers/test_stratego.h b/test/unit/parsers/test_stratego.h new file mode 100644 index 0000000..93aad0e --- /dev/null +++ b/test/unit/parsers/test_stratego.h @@ -0,0 +1,30 @@ + +void test_stratego_comments() { + test_parser_verify_parse( + test_parser_sourcefile("stratego", " // comment"), + "stratego", "", "// comment", 0 + ); +} + +void test_stratego_char_string_entities() { + test_parser_verify_entity( + test_parser_sourcefile("stratego", " 'c'"), + "string", "'c'" + ); + // single quote can be used in identifiers + // weak case + test_parser_verify_entity( + test_parser_sourcefile("stratego", " c'"), + "string", "" + ); + // strong case + test_parser_verify_entity( + test_parser_sourcefile("stratego", " c' = e'"), + "string", "" + ); +} + +void all_stratego_tests() { + test_stratego_comments(); + test_stratego_char_string_entities(); +} diff --git a/test/unit/parsers/test_tcl.h b/test/unit/parsers/test_tcl.h new file mode 100644 index 0000000..2fa10d8 --- /dev/null +++ b/test/unit/parsers/test_tcl.h @@ -0,0 +1,19 @@ + +void test_tcl_comments() { + test_parser_verify_parse( + test_parser_sourcefile("tcl", " #comment"), + "tcl", "", "#comment", 0 + ); +} + +void test_tcl_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("tcl", " #comment"), + "comment", "#comment" + ); +} + +void all_tcl_tests() { + test_tcl_comments(); + test_tcl_comment_entities(); +} diff --git a/test/unit/parsers/test_tex.h b/test/unit/parsers/test_tex.h new file mode 100644 index 0000000..de0f02b --- /dev/null +++ b/test/unit/parsers/test_tex.h @@ -0,0 +1,19 @@ + +void test_tex_comments() { + test_parser_verify_parse( + test_parser_sourcefile("tex", " %comment"), + "tex", "", "%comment", 0 + ); +} + +void test_tex_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("tex", " %comment"), + "comment", "%comment" + ); +} + +void all_tex_tests() { + test_tex_comments(); + test_tex_comment_entities(); +} diff --git a/test/unit/parsers/test_vala.h b/test/unit/parsers/test_vala.h new file mode 100644 index 0000000..8811e0e --- /dev/null +++ b/test/unit/parsers/test_vala.h @@ -0,0 +1,23 @@ + +void test_vala_comments() { + test_parser_verify_parse( + test_parser_sourcefile("vala", " //comment"), + "vala", "", "//comment", 0 + ); +} + +void test_vala_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("vala", " //comment"), + "comment", "//comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("vala", " /*comment*/"), + "comment", "/*comment*/" + ); +} + +void all_vala_tests() { + test_vala_comments(); + test_vala_comment_entities(); +} diff --git a/test/unit/parsers/test_vb_aspx.h b/test/unit/parsers/test_vb_aspx.h new file mode 100644 index 0000000..f6971b6 --- /dev/null +++ b/test/unit/parsers/test_vb_aspx.h @@ -0,0 +1,12 @@ + +void test_vb_aspx_comment() { + test_parser_verify_parse2( + test_parser_sourcefile("vb_aspx", "<%\n 'comment\n%>"), + "html", "<%\n%>", "", 0, + "visualbasic", "", "'comment\n", 0 + ); +} + +void all_vb_aspx_tests() { + test_vb_aspx_comment(); +} diff --git a/test/unit/parsers/test_vhdl.h b/test/unit/parsers/test_vhdl.h new file mode 100644 index 0000000..d40ba96 --- /dev/null +++ b/test/unit/parsers/test_vhdl.h @@ -0,0 +1,19 @@ + +void test_vhdl_comments() { + test_parser_verify_parse( + test_parser_sourcefile("vhdl", " -- comment"), + "vhdl", "", "-- comment", 0 + ); +} + +void test_vhdl_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("vhdl", " --comment"), + "comment", "--comment" + ); +} + +void all_vhdl_tests() { + test_vhdl_comments(); + test_vhdl_comment_entities(); +} diff --git a/test/unit/parsers/test_visualbasic.h b/test/unit/parsers/test_visualbasic.h new file mode 100644 index 0000000..b86f7a2 --- /dev/null +++ b/test/unit/parsers/test_visualbasic.h @@ -0,0 +1,23 @@ + +void test_visualbasic_comments() { + test_parser_verify_parse( + test_parser_sourcefile("visualbasic", " 'comment"), + "visualbasic", "", "'comment", 0 + ); +} + +void test_visualbasic_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("visualbasic", " 'comment"), + "comment", "'comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("visualbasic", " Rem comment"), + "comment", "Rem comment" + ); +} + +void all_visualbasic_tests() { + test_visualbasic_comments(); + test_visualbasic_comment_entities(); +} diff --git a/test/unit/parsers/test_xaml.h b/test/unit/parsers/test_xaml.h new file mode 100644 index 0000000..ce11b52 --- /dev/null +++ b/test/unit/parsers/test_xaml.h @@ -0,0 +1,19 @@ + +void test_xaml_comments() { + test_parser_verify_parse( + test_parser_sourcefile("xaml", " "), + "xaml", "", "", 0 + ); +} + +void test_xaml_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("xaml", " "), + "comment", "" + ); +} + +void all_xaml_tests() { + test_xaml_comments(); + test_xaml_comment_entities(); +} diff --git a/test/unit/parsers/test_xml.h b/test/unit/parsers/test_xml.h new file mode 100644 index 0000000..4cf9e35 --- /dev/null +++ b/test/unit/parsers/test_xml.h @@ -0,0 +1,19 @@ + +void test_xml_comments() { + test_parser_verify_parse( + test_parser_sourcefile("xml", " "), + "xml", "", "", 0 + ); +} + +void test_xml_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("xml", " "), + "comment", "" + ); +} + +void all_xml_tests() { + test_xml_comments(); + test_xml_comment_entities(); +} diff --git a/test/unit/parsers/test_xmlschema.h b/test/unit/parsers/test_xmlschema.h new file mode 100644 index 0000000..afad0b8 --- /dev/null +++ b/test/unit/parsers/test_xmlschema.h @@ -0,0 +1,19 @@ + +void test_xmlschema_comments() { + test_parser_verify_parse( + test_parser_sourcefile("xmlschema", " "), + "xmlschema", "", "", 0 + ); +} + +void test_xmlschema_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("xmlschema", " "), + "comment", "" + ); +} + +void all_xmlschema_tests() { + test_xmlschema_comments(); + test_xmlschema_comment_entities(); +} diff --git a/test/unit/parsers/test_xslt.h b/test/unit/parsers/test_xslt.h new file mode 100644 index 0000000..3bde5a3 --- /dev/null +++ b/test/unit/parsers/test_xslt.h @@ -0,0 +1,19 @@ + +void test_xslt_comments() { + test_parser_verify_parse( + test_parser_sourcefile("xslt", " "), + "xslt", "", "", 0 + ); +} + +void test_xslt_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("xslt", " "), + "comment", "" + ); +} + +void all_xslt_tests() { + test_xslt_comments(); + test_xslt_comment_entities(); +} diff --git a/test/unit/sourcefile_test.h b/test/unit/sourcefile_test.h new file mode 100644 index 0000000..fee7b4a --- /dev/null +++ b/test/unit/sourcefile_test.h @@ -0,0 +1,218 @@ +// sourcefile_test.h written by Mitchell Foral. mitchellcaladbolg.net. +// See COPYING for license information. + +#include +#include + +#include "../../src/sourcefile.h" +#include "../../src/diff.h" +#include "../../src/loc.h" + +void test_sourcefile_initialize() { + SourceFile *sf = ohcount_sourcefile_new("foo.rb"); + assert(strcmp("foo.rb", sf->filepath) == 0); + assert(strcmp("rb", sf->ext) == 0); + assert(strcmp("foo.rb", sf->filename) == 0); + assert(strncmp("", sf->filepath, sf->dirpath) == 0); + assert(sf->contents == NULL); + ohcount_sourcefile_free(sf); + + sf = ohcount_sourcefile_new("foo/bar.rb"); + assert(strcmp("foo/bar.rb", sf->filepath) == 0); + assert(strcmp("rb", sf->ext) == 0); + assert(strcmp("bar.rb", sf->filename) == 0); + assert(strncmp("foo/", sf->filepath, sf->dirpath) == 0); + assert(sf->contents == NULL); + ohcount_sourcefile_free(sf); +} + +void test_sourcefile_language_breakdowns() { + SourceFile *sf = ohcount_sourcefile_new("foo.rb"); + ohcount_sourcefile_set_contents(sf, "x = 5"); + ParsedLanguageList *list = ohcount_sourcefile_get_parsed_language_list(sf); + assert(strcmp("ruby", list->head->pl->language) == 0); + assert(strcmp("x = 5", list->head->pl->code) == 0); + ohcount_sourcefile_free(sf); +} + +void test_sourcefile_parse() { + // This was a Ruby-specific test case. +} + +void test_sourcefile_realize_file() { + +} + +void test_sourcefile_diff() { + SourceFile *old = ohcount_sourcefile_new("foo.c"); + ohcount_sourcefile_set_contents(old, "int i;"); + SourceFile *new = ohcount_sourcefile_new("foo.c"); + ohcount_sourcefile_set_contents(new, "int j;"); + LocDelta *delta1 = ohcount_loc_delta_new("c", 1, 1, 0, 0, 0, 0); + LocDelta *delta2 = ohcount_sourcefile_calc_loc_delta(old, "c", new); + assert(ohcount_loc_delta_is_equal(delta1, delta2)); + LocDeltaList *list1 = ohcount_loc_delta_list_new(); + ohcount_loc_delta_list_add_loc_delta(list1, delta1); + LocDeltaList *list2 = ohcount_sourcefile_diff(old, new); + assert(list1->head != NULL); + assert(list2->head != NULL); + assert(list1->head->next == NULL); + assert(list2->head->next == NULL); + assert(ohcount_loc_delta_is_equal(list1->head->delta, list2->head->delta)); + ohcount_sourcefile_free(old); + ohcount_sourcefile_free(new); + ohcount_loc_delta_free(delta1); + ohcount_loc_delta_free(delta2); + ohcount_loc_delta_list_free(list1); + ohcount_loc_delta_list_free(list2); +} + +void test_sourcefile_calc_diff2() { + SourceFile *old = ohcount_sourcefile_new("foo.html"); + ohcount_sourcefile_set_contents(old, + "\n" + " \n" + " \n" + "" + ); + SourceFile *new = ohcount_sourcefile_new("foo.html"); + ohcount_sourcefile_set_contents(new, + "\n" + " \n" + " \n" + "" + ); + LocDeltaList *list = ohcount_sourcefile_diff(old, new); + assert(strcmp(list->head->delta->language, "html") == 0); + assert(strcmp(list->head->next->delta->language, "javascript") == 0); + assert(strcmp(list->head->next->next->delta->language, "css") == 0); + LocDelta *delta1 = ohcount_loc_delta_new("javascript", 1, 1, 0, 0, 0, 0); + LocDelta *delta2 = ohcount_loc_delta_list_get_loc_delta(list, "javascript"); + assert(ohcount_loc_delta_is_equal(delta1, delta2)); + ohcount_loc_delta_free(delta1); + delta1 = ohcount_loc_delta_new("css", 0, 0, 1, 1, 0, 0); + delta2 = ohcount_loc_delta_list_get_loc_delta(list, "css"); + assert(ohcount_loc_delta_is_equal(delta1, delta2)); + ohcount_sourcefile_free(old); + ohcount_sourcefile_free(new); + ohcount_loc_delta_list_free(list); + ohcount_loc_delta_free(delta1); +} + +void test_sourcefile_diff_longer() { + SourceFile *old = ohcount_sourcefile_new("foo.c"); + ohcount_sourcefile_set_contents(old, + "int = 1;\n" + "int = 2;\n" + "int = 3;\n" + "int = 4;\n" + ); + SourceFile *new = ohcount_sourcefile_new("foo.c"); + ohcount_sourcefile_set_contents(new, + "int = 1;\n" + "int = 5;\n" + "int = 6;\n" + "int = 4;\n" + ); + LocDeltaList *list = ohcount_sourcefile_diff(old, new); + LocDelta *delta1 = ohcount_loc_delta_new("c", 2, 2, 0, 0, 0, 0); + LocDelta *delta2 = ohcount_loc_delta_list_get_loc_delta(list, "c"); + assert(ohcount_loc_delta_is_equal(delta1, delta2)); + ohcount_sourcefile_free(old); + ohcount_sourcefile_free(new); + ohcount_loc_delta_list_free(list); + ohcount_loc_delta_free(delta1); +} + +void test_sourcefile_calc_diff() { + int added, removed; + ohcount_calc_diff("", "", &added, &removed); + assert(added == 0); + assert(removed == 0); + ohcount_calc_diff("a", "a", &added, &removed); + assert(added == 0); + assert(removed == 0); + ohcount_calc_diff("a\n", "a\n", &added, &removed); + assert(added == 0); + assert(removed == 0); + ohcount_calc_diff("", "a\n", &added, &removed); + assert(added == 1); + assert(removed == 0); + ohcount_calc_diff("a\n", "", &added, &removed); + assert(added == 0); + assert(removed == 1); + ohcount_calc_diff("a\n", "b\n", &added, &removed); + assert(added = 1); + assert(removed == 1); + ohcount_calc_diff("a\nb\nc\n", "a\nc\nd\n", &added, &removed); + assert(added == 1); + assert(removed == 1); + + ohcount_calc_diff( + "Hello, World!\n" + "Hello, World!\n" + "Hello, World!\n" + "Hello, World!\n" + "Hello, World!\n" + "Hello, World!\n" + "Hello, World!\n" + "Hello, World!\n" + "Hello, World!\n" + "Hello, World!\n", // 10 times + "Hello, World!\n" + "Hello, World!\n" + "Hello, World!\n" + "Hello, World!\n" + "Hello, World!\n" + "Hello, World!\n" + "Hello, World!\n" + "Hello, World!\n" + "Hello, World!\n" + "Hello, World!\n" + "Hello, World!\n", // 11 times + &added, &removed + ); + assert(added == 1); + assert(removed == 0); +} + +void test_sourcefile_list_language_facts() { + SourceFileList *sfl = ohcount_sourcefile_list_new(); + ohcount_sourcefile_list_add_directory(sfl, "../gestalt_files/win32_enough/"); + LocList *list = ohcount_sourcefile_list_analyze_languages(sfl); + assert(ohcount_loc_list_filecount(list) == 2); + Loc *loc = ohcount_loc_list_get_loc(list, "c"); + assert(loc->code == 2); + assert(loc->comments == 2); + assert(loc->blanks == 2); + ohcount_sourcefile_list_free(sfl); + ohcount_loc_list_free(list); +} + +void test_sourcefile_list_gestalt_facts() { + +} + +void all_sourcefile_tests() { + test_sourcefile_initialize(); + test_sourcefile_language_breakdowns(); + test_sourcefile_parse(); + test_sourcefile_realize_file(); + test_sourcefile_diff(); + test_sourcefile_calc_diff2(); + test_sourcefile_diff_longer(); + test_sourcefile_calc_diff(); + + test_sourcefile_list_language_facts(); + test_sourcefile_list_gestalt_facts(); +} From e63780eb3705155cd1bdcae4e4858ccaedb96921 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 17 May 2009 14:24:42 -0400 Subject: [PATCH 136/387] Modified existing test/expected_licenses for C code. --- test/expected_licenses/gpl3_t2 | 2 +- test/expected_licenses/i9_license_t1 | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/test/expected_licenses/gpl3_t2 b/test/expected_licenses/gpl3_t2 index 9beb717..1754a00 100644 --- a/test/expected_licenses/gpl3_t2 +++ b/test/expected_licenses/gpl3_t2 @@ -1,2 +1,2 @@ -gpl3 bsd +gpl3 diff --git a/test/expected_licenses/i9_license_t1 b/test/expected_licenses/i9_license_t1 index 740b253..ac0b8e1 100644 --- a/test/expected_licenses/i9_license_t1 +++ b/test/expected_licenses/i9_license_t1 @@ -1 +1,2 @@ -i9_license mit +i9_license +mit From d1eea116f5fc18e59f042fa956ac86780fe70be6 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 17 May 2009 14:25:14 -0400 Subject: [PATCH 137/387] Initial import of build script. --- build | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100755 build diff --git a/build b/build new file mode 100755 index 0000000..d837da2 --- /dev/null +++ b/build @@ -0,0 +1,90 @@ +#!/bin/sh +# Build script for Ohcount. +# Written by Mitchell Foral. mitchellcaladbolg.net. + +# C compiler and flags +cc="gcc -g -Wall -Wno-pointer-to-int-cast -Wno-parentheses" + +# Ohcount source files +files="src/sourcefile.c \ + src/detector.c \ + src/licenses.c \ + src/parser.o \ + src/loc.c \ + src/diff.c \ + src/parsed_language.c" + +success="Build successful; ohcount is in bin/" + +# If any src/hash/*.gperf file is newer than the header files (which were +# presumably generated together), regenerate the headers. +build_hash_headers() +{ + if [[ -z `ls src/hash/` || + ! -z `find src/hash/*.gperf -newer src/hash/parser_hash.h` ]] + then + echo "Generating hash headers" + sh -c "cd src/hash/ && ./generate_headers" || exit 1 + fi +} + +# If src/parser.o does not exist, or if there are Ragel parsers or parser +# header files newer than the existing parser.o, recompile parser.o. +build_parser_o() +{ + if [[ ! -f src/parser.o || + ! -z `find src/parsers/*.{h,rl} -newer src/parser.o` ]] + then + sh -c "cd src/parsers/ && ./compile" || exit 1 + echo "Building src/parser.c (will take a while)" + gcc -c src/parser.c -o src/parser.o || exit 1 + fi +} + +build_ohcount() +{ + build_hash_headers + build_parser_o + echo "Building Ohcount" + sh -c "$cc src/ohcount.c $files -o bin/ohcount -lpcre" || exit 1 +} + +build_test_suite() +{ + build_hash_headers + build_parser_o + echo "Building test suite" + sh -c "$cc test/unit/all_tests.c $files -o test/unit/run_tests -lpcre" \ + || exit 1 +} + +run_test_suite() +{ + echo "Running test suite" + sh -c "cd test/unit/ && ./run_tests" +} + +if [ $# -eq 0 ] || [ $1 == "all" ] +then + build_ohcount + build_test_suite + run_test_suite + echo $success +elif [ $1 == "ohcount" ] +then + build_ohcount + echo $success +elif [ $1 == "tests" ] +then + build_test_suite + run_test_suite +elif [ $1 == "clean" ] +then + rm bin/ohcount + rm test/unit/run_tests + rm src/parser.o + rm src/parsers/*.h + rm src/hash/*.h +else + echo "Usage: build [all|ohcount|tests|clean]" +fi From 638431ca1e9c7a8893e1af0a2d5b97db5fa87535 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 17 May 2009 14:29:03 -0400 Subject: [PATCH 138/387] Initial import of files for generating Doxygen documentation. --- doc/Doxyfile | 1473 +++++++++++++++++++++++++++++++++++++++++++++ doc/examples/parser_doc_1 | 22 + doc/examples/parser_doc_2 | 31 + doc/examples/parser_doc_3 | 7 + doc/examples/parser_doc_4 | 6 + doc/examples/parser_doc_5 | 14 + doc/examples/parser_doc_6 | 2 + doc/examples/parser_doc_7 | 1 + doc/examples/parser_doc_8 | 6 + doc/examples/parser_doc_9 | 4 + 10 files changed, 1566 insertions(+) create mode 100644 doc/Doxyfile create mode 100644 doc/examples/parser_doc_1 create mode 100644 doc/examples/parser_doc_2 create mode 100644 doc/examples/parser_doc_3 create mode 100644 doc/examples/parser_doc_4 create mode 100644 doc/examples/parser_doc_5 create mode 100644 doc/examples/parser_doc_6 create mode 100644 doc/examples/parser_doc_7 create mode 100644 doc/examples/parser_doc_8 create mode 100644 doc/examples/parser_doc_9 diff --git a/doc/Doxyfile b/doc/Doxyfile new file mode 100644 index 0000000..9493685 --- /dev/null +++ b/doc/Doxyfile @@ -0,0 +1,1473 @@ +# Doxyfile 1.5.7.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = ohcount + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, +# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, +# Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = YES + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../src/ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = examples/ + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# Qt Help Project / Namespace. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# Qt Help Project / Virtual Folders. + +QHP_VIRTUAL_FOLDER = doc + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file . + +QHG_LOCATION = + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to FRAME, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. Other possible values +# for this tag are: HIERARCHIES, which will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list; +# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which +# disables this behavior completely. For backwards compatibility with previous +# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE +# respectively. + +GENERATE_TREEVIEW = NONE + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/doc/examples/parser_doc_1 b/doc/examples/parser_doc_1 new file mode 100644 index 0000000..fb7a4f9 --- /dev/null +++ b/doc/examples/parser_doc_1 @@ -0,0 +1,22 @@ +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_C_PARSER_H +#define OHCOUNT_C_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *C_LANG = LANG_C; + +// the languages entities +const char *c_entities[] = { + "space", "comment", "string", "number", "preproc", + "keyword", "identifier", "operator", "any" +}; + +// constants associated with the entities +enum { + C_SPACE = 0, C_COMMENT, C_STRING, C_NUMBER, C_PREPROC, + C_KEYWORD, C_IDENTIFIER, C_OPERATOR, C_ANY +}; + +/*****************************************************************************/ diff --git a/doc/examples/parser_doc_2 b/doc/examples/parser_doc_2 new file mode 100644 index 0000000..d0571a7 --- /dev/null +++ b/doc/examples/parser_doc_2 @@ -0,0 +1,31 @@ +/************************* Required for every parser *************************/ + +/* Parses a string buffer with C/C++ code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_c(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + %% write init; + cs = (count) ? c_en_c_line : c_en_c_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(C_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/doc/examples/parser_doc_3 b/doc/examples/parser_doc_3 new file mode 100644 index 0000000..f72667f --- /dev/null +++ b/doc/examples/parser_doc_3 @@ -0,0 +1,7 @@ +%%{ + machine c; + write data; + include "common.rl"; + + ... +}%% diff --git a/doc/examples/parser_doc_4 b/doc/examples/parser_doc_4 new file mode 100644 index 0000000..966dbd8 --- /dev/null +++ b/doc/examples/parser_doc_4 @@ -0,0 +1,6 @@ +[lang]_line := |* + entity1 ${ entity = ENTITY1; } => [lang]_ccallback; + entity2 ${ entity = ENTITY2; } => [lang]_ccallback; + ... + entityn ${ entity = ENTITYN; } => [lang]_ccallback; +*|; diff --git a/doc/examples/parser_doc_5 b/doc/examples/parser_doc_5 new file mode 100644 index 0000000..2d57ebd --- /dev/null +++ b/doc/examples/parser_doc_5 @@ -0,0 +1,14 @@ +action [lang]_ccallback { + switch(entity) { + when ENTITY1: + ... + break; + when ENTITY2: + ... + break; + ... + when ENTITYN: + ... + break; + } +} diff --git a/doc/examples/parser_doc_6 b/doc/examples/parser_doc_6 new file mode 100644 index 0000000..6358220 --- /dev/null +++ b/doc/examples/parser_doc_6 @@ -0,0 +1,2 @@ +[lang]_[elang]_entry @{ entity = CHECK_BLANK_ENTRY; } @[lang]_callback + @{ saw([elang]_LANG)} => { fcall [lang]_[elang]_line; }; diff --git a/doc/examples/parser_doc_7 b/doc/examples/parser_doc_7 new file mode 100644 index 0000000..ab02cc0 --- /dev/null +++ b/doc/examples/parser_doc_7 @@ -0,0 +1 @@ +@{ p = ts; fret; }; diff --git a/doc/examples/parser_doc_8 b/doc/examples/parser_doc_8 new file mode 100644 index 0000000..66ce8d6 --- /dev/null +++ b/doc/examples/parser_doc_8 @@ -0,0 +1,6 @@ +[lang]_entity := |* + entity1 ${ entity = ENTITY1; } => [lang]_ecallback; + entity2 ${ entity = ENTITY2; } => [lang]_ecallback; + ... + entityn ${ entity = ENTITYN; } => [lang]_ecallback; +*|; diff --git a/doc/examples/parser_doc_9 b/doc/examples/parser_doc_9 new file mode 100644 index 0000000..09368c4 --- /dev/null +++ b/doc/examples/parser_doc_9 @@ -0,0 +1,4 @@ +action [lang]_ecallback { + callback([lang]_LANG, [lang]_entities[entity], cint(ts), cint(te), + userdata); +} From 1bbfc6fbe294a10b991e670b747503c07b6f4b6d Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 17 May 2009 14:31:07 -0400 Subject: [PATCH 139/387] Modified .gitignore to not ignore doc/ directory. --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index dbfa000..6995014 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ pkg -doc lib/i[3-9]86* lib/x86* *.swp From 2353f8d6992e20a223062520e4bc4857c33b1e98 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 17 May 2009 14:34:29 -0400 Subject: [PATCH 140/387] Removed all Ruby parts of Ohcount. --- PARSER_DOC | 314 ------ README | 130 --- Rakefile | 139 --- bin/ohcount | 326 ------ ext/ohcount_native/.gitignore | 5 - ext/ohcount_native/common.h | 45 - ext/ohcount_native/extconf.rb | 14 - ext/ohcount_native/language_breakdown.c | 92 -- ext/ohcount_native/language_breakdown.h | 26 - ext/ohcount_native/ragel_parser.c | 283 ----- ext/ohcount_native/ragel_parser.h | 15 - ext/ohcount_native/ragel_parser_macros.h | 313 ------ ext/ohcount_native/ragel_parsers/.gitignore | 1 - ext/ohcount_native/ragel_parsers/actionscript.rl | 123 --- ext/ohcount_native/ragel_parsers/ada.rl | 103 -- ext/ohcount_native/ragel_parsers/assembler.rl | 116 -- ext/ohcount_native/ragel_parsers/autoconf.rl | 120 --- ext/ohcount_native/ragel_parsers/automake.rl | 105 -- ext/ohcount_native/ragel_parsers/awk.rl | 105 -- ext/ohcount_native/ragel_parsers/bat.rl | 100 -- ext/ohcount_native/ragel_parsers/blitzmax.rl | 123 --- ext/ohcount_native/ragel_parsers/boo.rl | 143 --- ext/ohcount_native/ragel_parsers/c.rl | 208 ---- ext/ohcount_native/ragel_parsers/classic_basic.rl | 101 -- ext/ohcount_native/ragel_parsers/clearsilver.rl | 103 -- .../ragel_parsers/clearsilverhtml.rl | 236 ----- ext/ohcount_native/ragel_parsers/cmake.rl | 123 --- ext/ohcount_native/ragel_parsers/common.rl | 82 -- ext/ohcount_native/ragel_parsers/cs_aspx.rl | 238 ----- ext/ohcount_native/ragel_parsers/css.rl | 132 --- ext/ohcount_native/ragel_parsers/d.rl | 177 ---- ext/ohcount_native/ragel_parsers/dcl.rl | 105 -- ext/ohcount_native/ragel_parsers/dylan.rl | 116 -- ext/ohcount_native/ragel_parsers/ebuild.rl | 105 -- ext/ohcount_native/ragel_parsers/eiffel.rl | 101 -- ext/ohcount_native/ragel_parsers/erlang.rl | 105 -- ext/ohcount_native/ragel_parsers/exheres.rl | 105 -- ext/ohcount_native/ragel_parsers/factor.rl | 102 -- ext/ohcount_native/ragel_parsers/fortranfixed.rl | 101 -- ext/ohcount_native/ragel_parsers/fortranfree.rl | 115 -- ext/ohcount_native/ragel_parsers/glsl.rl | 183 ---- ext/ohcount_native/ragel_parsers/groovy.rl | 138 --- ext/ohcount_native/ragel_parsers/haml.rl | 217 ---- ext/ohcount_native/ragel_parsers/haskell.rl | 143 --- ext/ohcount_native/ragel_parsers/haxe.rl | 123 --- ext/ohcount_native/ragel_parsers/html.rl | 179 ---- ext/ohcount_native/ragel_parsers/java.rl | 118 --- ext/ohcount_native/ragel_parsers/javascript.rl | 134 --- ext/ohcount_native/ragel_parsers/jsp.rl | 236 ----- ext/ohcount_native/ragel_parsers/limbo.rl | 144 --- ext/ohcount_native/ragel_parsers/lisp.rl | 145 --- ext/ohcount_native/ragel_parsers/lua.rl | 170 --- ext/ohcount_native/ragel_parsers/makefile.rl | 105 -- ext/ohcount_native/ragel_parsers/matlab.rl | 120 --- ext/ohcount_native/ragel_parsers/metafont.rl | 103 -- ext/ohcount_native/ragel_parsers/metapost.rl | 103 -- .../ragel_parsers/metapost_with_tex.rl | 138 --- ext/ohcount_native/ragel_parsers/mxml.rl | 197 ---- ext/ohcount_native/ragel_parsers/nix.rl | 175 ---- ext/ohcount_native/ragel_parsers/objective_c.rl | 123 --- ext/ohcount_native/ragel_parsers/objective_j.rl | 124 --- ext/ohcount_native/ragel_parsers/ocaml.rl | 126 --- ext/ohcount_native/ragel_parsers/octave.rl | 120 --- ext/ohcount_native/ragel_parsers/pascal.rl | 134 --- ext/ohcount_native/ragel_parsers/perl.rl | 153 --- ext/ohcount_native/ragel_parsers/php.rl | 135 --- ext/ohcount_native/ragel_parsers/phphtml.rl | 236 ----- ext/ohcount_native/ragel_parsers/pike.rl | 116 -- ext/ohcount_native/ragel_parsers/python.rl | 141 --- ext/ohcount_native/ragel_parsers/r.rl | 107 -- ext/ohcount_native/ragel_parsers/rexx.rl | 128 --- ext/ohcount_native/ragel_parsers/rhtml.rl | 236 ----- ext/ohcount_native/ragel_parsers/ruby.rl | 185 ---- ext/ohcount_native/ragel_parsers/scala.rl | 116 -- ext/ohcount_native/ragel_parsers/scilab.rl | 107 -- ext/ohcount_native/ragel_parsers/shell.rl | 124 --- ext/ohcount_native/ragel_parsers/smalltalk.rl | 110 -- ext/ohcount_native/ragel_parsers/sql.rl | 126 --- ext/ohcount_native/ragel_parsers/stratego.rl | 141 --- .../ragel_parsers/structured_basic.rl | 101 -- ext/ohcount_native/ragel_parsers/tcl.rl | 119 --- ext/ohcount_native/ragel_parsers/tex.rl | 100 -- ext/ohcount_native/ragel_parsers/vb_aspx.rl | 235 ----- ext/ohcount_native/ragel_parsers/vhdl.rl | 105 -- ext/ohcount_native/ragel_parsers/vim.rl | 100 -- ext/ohcount_native/ragel_parsers/visual_basic.rl | 103 -- ext/ohcount_native/ragel_parsers/xaml.rl | 123 --- ext/ohcount_native/ragel_parsers/xml.rl | 125 --- ext/ohcount_native/ragel_parsers/xmlschema.rl | 126 --- ext/ohcount_native/ragel_parsers/xslt.rl | 125 --- ext/ohcount_native/ruby_binding.c | 276 ----- lib/gestalt/base.rb | 37 - lib/gestalt/definition.rb | 72 -- lib/gestalt/definitions.rb | 207 ---- lib/gestalt/gestalt_engine.rb | 129 --- lib/gestalt/gestalt_facts.rb | 82 -- lib/gestalt/platform.rb | 44 - lib/gestalt/platforms.rb | 194 ---- lib/gestalt/rules/and_rule.rb | 16 - lib/gestalt/rules/c_header_rule.rb | 31 - lib/gestalt/rules/c_keyword_rule.rb | 18 - lib/gestalt/rules/file_rule.rb | 53 - lib/gestalt/rules/filename_rule.rb | 25 - lib/gestalt/rules/find_filenames_rule.rb | 33 - lib/gestalt/rules/find_java_imports_rule.rb | 47 - lib/gestalt/rules/gestalt_rule.rb | 22 - lib/gestalt/rules/java_import_rule.rb | 28 - lib/gestalt/rules/keyword_rule.rb | 28 - lib/gestalt/rules/language_rule.rb | 26 - lib/gestalt/rules/logical_rule.rb | 80 -- lib/gestalt/rules/or_rule.rb | 14 - lib/gestalt/rules/rule.rb | 47 - lib/gestalt/rules/xml_keyword_rule.rb | 15 - lib/gestalt/tool.rb | 31 - lib/gestalt/tools.rb | 18 - lib/gestalt/trigger.rb | 13 - lib/licenses/license.rb | 15 - lib/licenses/license_map.rb | 387 ------- lib/licenses/license_sniffer.rb | 55 - lib/ohcount.rb | 37 - lib/ohcount/detector.rb | 709 ------------- lib/ohcount/gestalt_facts.rb | 71 -- lib/ohcount/helpers.rb | 12 - lib/ohcount/language.rb | 111 -- lib/ohcount/language_breakdown.rb | 11 - lib/ohcount/loc.rb | 26 - lib/ohcount/loc_delta.rb | 58 - lib/ohcount/loc_delta_list.rb | 102 -- lib/ohcount/loc_list.rb | 95 -- lib/ohcount/scratch_dir.rb | 59 -- lib/ohcount/source_file.rb | 239 ----- lib/ohcount/source_file_list.rb | 102 -- log/.gitignore | 1 - test/parser_test.rb | 12 - test/test_helper.rb | 92 -- test/unit/blitzmax_test.rb | 16 - test/unit/detector_test.rb | 139 --- test/unit/gestalt/definitions_test.rb | 205 ---- test/unit/gestalt/file_rule_test.rb | 53 - test/unit/gestalt/filename_rule_test.rb | 18 - test/unit/gestalt/keyword_rule_test.rb | 19 - test/unit/gestalt/rule_test.rb | 10 - test/unit/glsl_test.rb | 31 - test/unit/language_breakdown_test.rb | 12 - test/unit/language_test.rb | 13 - test/unit/license_sniffer_test.rb | 48 - test/unit/loc_delta_list_test.rb | 126 --- test/unit/loc_delta_test.rb | 60 -- test/unit/loc_list_test.rb | 149 --- test/unit/loc_test.rb | 45 - test/unit/nix_test.rb | 13 - test/unit/parsers/actionscript_test.rb | 17 - test/unit/parsers/ada_test.rb | 20 - test/unit/parsers/assembler_test.rb | 21 - test/unit/parsers/autoconf_test.rb | 12 - test/unit/parsers/automake_test.rb | 12 - test/unit/parsers/awk_test.rb | 22 - test/unit/parsers/basic_test.rb | 26 - test/unit/parsers/bat_test.rb | 16 - test/unit/parsers/boo_test.rb | 37 - test/unit/parsers/c_test.rb | 35 - test/unit/parsers/clearsilver_template_test.rb | 20 - test/unit/parsers/clearsilver_test.rb | 14 - test/unit/parsers/cmake_test.rb | 23 - test/unit/parsers/cs_aspx_test.rb | 15 - test/unit/parsers/csharp_test.rb | 19 - test/unit/parsers/css_test.rb | 16 - test/unit/parsers/d_test.rb | 43 - test/unit/parsers/dcl_test.rb | 32 - test/unit/parsers/dylan_test.rb | 18 - test/unit/parsers/ebuild_test.rb | 11 - test/unit/parsers/eiffel_test.rb | 17 - test/unit/parsers/emacs_lisp.rb | 20 - test/unit/parsers/erlang_test.rb | 18 - test/unit/parsers/exheres_test.rb | 12 - test/unit/parsers/factor_test.rb | 18 - test/unit/parsers/fortran_test.rb | 15 - test/unit/parsers/groovy_test.rb | 18 - test/unit/parsers/haml_test.rb | 23 - test/unit/parsers/haskell_test.rb | 25 - test/unit/parsers/haxe_test.rb | 17 - test/unit/parsers/html_test.rb | 14 - test/unit/parsers/java_test.rb | 21 - test/unit/parsers/javascript_test.rb | 22 - test/unit/parsers/jsp_test.rb | 20 - test/unit/parsers/limbo_test.rb | 24 - test/unit/parsers/lisp_test.rb | 38 - test/unit/parsers/lua_test.rb | 19 - test/unit/parsers/make_test.rb | 13 - test/unit/parsers/matlab_test.rb | 30 - test/unit/parsers/metafont_test.rb | 16 - test/unit/parsers/metapost_test.rb | 17 - test/unit/parsers/mxml_test.rb | 14 - test/unit/parsers/objective_j_test.rb | 18 - test/unit/parsers/ocaml_test.rb | 17 - test/unit/parsers/octave_test.rb | 30 - test/unit/parsers/pascal_test.rb | 19 - test/unit/parsers/perl_test.rb | 23 - test/unit/parsers/php_test.rb | 18 - test/unit/parsers/pike_test.rb | 26 - test/unit/parsers/python_test.rb | 27 - test/unit/parsers/r_test.rb | 18 - test/unit/parsers/rexx_test.rb | 18 - test/unit/parsers/rhtml_test.rb | 24 - test/unit/parsers/ruby_test.rb | 19 - test/unit/parsers/scala_test.rb | 14 - test/unit/parsers/scheme_test.rb | 18 - test/unit/parsers/scilab_test.rb | 18 - test/unit/parsers/shell_test.rb | 16 - test/unit/parsers/smalltalk_test.rb | 19 - test/unit/parsers/sql_test.rb | 32 - test/unit/parsers/stratego_test.rb | 22 - test/unit/parsers/tcl_test.rb | 16 - test/unit/parsers/tex_test.rb | 17 - test/unit/parsers/vala_test.rb | 18 - test/unit/parsers/vb_aspx_test.rb | 15 - test/unit/parsers/vhdl_test.rb | 16 - test/unit/parsers/vim_test.rb | 7 - test/unit/parsers/visual_basic_test.rb | 17 - test/unit/parsers/xaml_test.rb | 16 - test/unit/parsers/xml_test.rb | 16 - test/unit/parsers/xmlschema_test.rb | 16 - test/unit/parsers/xslt_test.rb | 16 - test/unit/source_file_list_test.rb | 26 - test/unit/source_file_test.rb | 123 --- vendor/gems/diff-lcs-1.1.2/ChangeLog | 46 - vendor/gems/diff-lcs-1.1.2/Install | 6 - vendor/gems/diff-lcs-1.1.2/README | 76 -- vendor/gems/diff-lcs-1.1.2/Rakefile | 116 -- vendor/gems/diff-lcs-1.1.2/bin/htmldiff | 112 -- vendor/gems/diff-lcs-1.1.2/bin/ldiff | 45 - vendor/gems/diff-lcs-1.1.2/diff-lcs.gemspec | 40 - vendor/gems/diff-lcs-1.1.2/install.rb | 262 ----- vendor/gems/diff-lcs-1.1.2/lib/diff/lcs.rb | 1106 -------------------- vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/array.rb | 21 - vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/block.rb | 51 - .../gems/diff-lcs-1.1.2/lib/diff/lcs/callbacks.rb | 322 ------ vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/change.rb | 172 --- vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/hunk.rb | 257 ----- vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/ldiff.rb | 226 ---- vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/string.rb | 19 - vendor/gems/diff-lcs-1.1.2/tests/00test.rb | 626 ----------- 242 files changed, 21932 deletions(-) delete mode 100644 PARSER_DOC delete mode 100644 README delete mode 100644 Rakefile delete mode 100755 bin/ohcount delete mode 100644 ext/ohcount_native/.gitignore delete mode 100644 ext/ohcount_native/common.h delete mode 100644 ext/ohcount_native/extconf.rb delete mode 100644 ext/ohcount_native/language_breakdown.c delete mode 100644 ext/ohcount_native/language_breakdown.h delete mode 100644 ext/ohcount_native/ragel_parser.c delete mode 100644 ext/ohcount_native/ragel_parser.h delete mode 100644 ext/ohcount_native/ragel_parser_macros.h delete mode 100644 ext/ohcount_native/ragel_parsers/.gitignore delete mode 100644 ext/ohcount_native/ragel_parsers/actionscript.rl delete mode 100644 ext/ohcount_native/ragel_parsers/ada.rl delete mode 100644 ext/ohcount_native/ragel_parsers/assembler.rl delete mode 100644 ext/ohcount_native/ragel_parsers/autoconf.rl delete mode 100644 ext/ohcount_native/ragel_parsers/automake.rl delete mode 100644 ext/ohcount_native/ragel_parsers/awk.rl delete mode 100644 ext/ohcount_native/ragel_parsers/bat.rl delete mode 100644 ext/ohcount_native/ragel_parsers/blitzmax.rl delete mode 100644 ext/ohcount_native/ragel_parsers/boo.rl delete mode 100644 ext/ohcount_native/ragel_parsers/c.rl delete mode 100644 ext/ohcount_native/ragel_parsers/classic_basic.rl delete mode 100644 ext/ohcount_native/ragel_parsers/clearsilver.rl delete mode 100644 ext/ohcount_native/ragel_parsers/clearsilverhtml.rl delete mode 100644 ext/ohcount_native/ragel_parsers/cmake.rl delete mode 100644 ext/ohcount_native/ragel_parsers/common.rl delete mode 100644 ext/ohcount_native/ragel_parsers/cs_aspx.rl delete mode 100644 ext/ohcount_native/ragel_parsers/css.rl delete mode 100644 ext/ohcount_native/ragel_parsers/d.rl delete mode 100644 ext/ohcount_native/ragel_parsers/dcl.rl delete mode 100644 ext/ohcount_native/ragel_parsers/dylan.rl delete mode 100644 ext/ohcount_native/ragel_parsers/ebuild.rl delete mode 100644 ext/ohcount_native/ragel_parsers/eiffel.rl delete mode 100644 ext/ohcount_native/ragel_parsers/erlang.rl delete mode 100644 ext/ohcount_native/ragel_parsers/exheres.rl delete mode 100644 ext/ohcount_native/ragel_parsers/factor.rl delete mode 100644 ext/ohcount_native/ragel_parsers/fortranfixed.rl delete mode 100644 ext/ohcount_native/ragel_parsers/fortranfree.rl delete mode 100644 ext/ohcount_native/ragel_parsers/glsl.rl delete mode 100644 ext/ohcount_native/ragel_parsers/groovy.rl delete mode 100644 ext/ohcount_native/ragel_parsers/haml.rl delete mode 100644 ext/ohcount_native/ragel_parsers/haskell.rl delete mode 100644 ext/ohcount_native/ragel_parsers/haxe.rl delete mode 100644 ext/ohcount_native/ragel_parsers/html.rl delete mode 100644 ext/ohcount_native/ragel_parsers/java.rl delete mode 100644 ext/ohcount_native/ragel_parsers/javascript.rl delete mode 100644 ext/ohcount_native/ragel_parsers/jsp.rl delete mode 100644 ext/ohcount_native/ragel_parsers/limbo.rl delete mode 100644 ext/ohcount_native/ragel_parsers/lisp.rl delete mode 100644 ext/ohcount_native/ragel_parsers/lua.rl delete mode 100644 ext/ohcount_native/ragel_parsers/makefile.rl delete mode 100644 ext/ohcount_native/ragel_parsers/matlab.rl delete mode 100644 ext/ohcount_native/ragel_parsers/metafont.rl delete mode 100644 ext/ohcount_native/ragel_parsers/metapost.rl delete mode 100644 ext/ohcount_native/ragel_parsers/metapost_with_tex.rl delete mode 100644 ext/ohcount_native/ragel_parsers/mxml.rl delete mode 100644 ext/ohcount_native/ragel_parsers/nix.rl delete mode 100644 ext/ohcount_native/ragel_parsers/objective_c.rl delete mode 100644 ext/ohcount_native/ragel_parsers/objective_j.rl delete mode 100644 ext/ohcount_native/ragel_parsers/ocaml.rl delete mode 100644 ext/ohcount_native/ragel_parsers/octave.rl delete mode 100644 ext/ohcount_native/ragel_parsers/pascal.rl delete mode 100644 ext/ohcount_native/ragel_parsers/perl.rl delete mode 100644 ext/ohcount_native/ragel_parsers/php.rl delete mode 100644 ext/ohcount_native/ragel_parsers/phphtml.rl delete mode 100644 ext/ohcount_native/ragel_parsers/pike.rl delete mode 100644 ext/ohcount_native/ragel_parsers/python.rl delete mode 100644 ext/ohcount_native/ragel_parsers/r.rl delete mode 100644 ext/ohcount_native/ragel_parsers/rexx.rl delete mode 100644 ext/ohcount_native/ragel_parsers/rhtml.rl delete mode 100644 ext/ohcount_native/ragel_parsers/ruby.rl delete mode 100644 ext/ohcount_native/ragel_parsers/scala.rl delete mode 100644 ext/ohcount_native/ragel_parsers/scilab.rl delete mode 100644 ext/ohcount_native/ragel_parsers/shell.rl delete mode 100644 ext/ohcount_native/ragel_parsers/smalltalk.rl delete mode 100644 ext/ohcount_native/ragel_parsers/sql.rl delete mode 100644 ext/ohcount_native/ragel_parsers/stratego.rl delete mode 100644 ext/ohcount_native/ragel_parsers/structured_basic.rl delete mode 100644 ext/ohcount_native/ragel_parsers/tcl.rl delete mode 100644 ext/ohcount_native/ragel_parsers/tex.rl delete mode 100644 ext/ohcount_native/ragel_parsers/vb_aspx.rl delete mode 100644 ext/ohcount_native/ragel_parsers/vhdl.rl delete mode 100644 ext/ohcount_native/ragel_parsers/vim.rl delete mode 100644 ext/ohcount_native/ragel_parsers/visual_basic.rl delete mode 100644 ext/ohcount_native/ragel_parsers/xaml.rl delete mode 100644 ext/ohcount_native/ragel_parsers/xml.rl delete mode 100644 ext/ohcount_native/ragel_parsers/xmlschema.rl delete mode 100644 ext/ohcount_native/ragel_parsers/xslt.rl delete mode 100644 ext/ohcount_native/ruby_binding.c delete mode 100644 lib/gestalt/base.rb delete mode 100644 lib/gestalt/definition.rb delete mode 100644 lib/gestalt/definitions.rb delete mode 100644 lib/gestalt/gestalt_engine.rb delete mode 100644 lib/gestalt/gestalt_facts.rb delete mode 100644 lib/gestalt/platform.rb delete mode 100644 lib/gestalt/platforms.rb delete mode 100644 lib/gestalt/rules/and_rule.rb delete mode 100644 lib/gestalt/rules/c_header_rule.rb delete mode 100644 lib/gestalt/rules/c_keyword_rule.rb delete mode 100644 lib/gestalt/rules/file_rule.rb delete mode 100644 lib/gestalt/rules/filename_rule.rb delete mode 100644 lib/gestalt/rules/find_filenames_rule.rb delete mode 100644 lib/gestalt/rules/find_java_imports_rule.rb delete mode 100644 lib/gestalt/rules/gestalt_rule.rb delete mode 100644 lib/gestalt/rules/java_import_rule.rb delete mode 100644 lib/gestalt/rules/keyword_rule.rb delete mode 100644 lib/gestalt/rules/language_rule.rb delete mode 100644 lib/gestalt/rules/logical_rule.rb delete mode 100644 lib/gestalt/rules/or_rule.rb delete mode 100644 lib/gestalt/rules/rule.rb delete mode 100644 lib/gestalt/rules/xml_keyword_rule.rb delete mode 100644 lib/gestalt/tool.rb delete mode 100644 lib/gestalt/tools.rb delete mode 100644 lib/gestalt/trigger.rb delete mode 100644 lib/licenses/license.rb delete mode 100644 lib/licenses/license_map.rb delete mode 100644 lib/licenses/license_sniffer.rb delete mode 100644 lib/ohcount.rb delete mode 100644 lib/ohcount/detector.rb delete mode 100644 lib/ohcount/gestalt_facts.rb delete mode 100644 lib/ohcount/helpers.rb delete mode 100644 lib/ohcount/language.rb delete mode 100644 lib/ohcount/language_breakdown.rb delete mode 100644 lib/ohcount/loc.rb delete mode 100644 lib/ohcount/loc_delta.rb delete mode 100644 lib/ohcount/loc_delta_list.rb delete mode 100644 lib/ohcount/loc_list.rb delete mode 100644 lib/ohcount/scratch_dir.rb delete mode 100644 lib/ohcount/source_file.rb delete mode 100644 lib/ohcount/source_file_list.rb delete mode 100644 log/.gitignore delete mode 100644 test/parser_test.rb delete mode 100644 test/test_helper.rb delete mode 100644 test/unit/blitzmax_test.rb delete mode 100644 test/unit/detector_test.rb delete mode 100644 test/unit/gestalt/definitions_test.rb delete mode 100644 test/unit/gestalt/file_rule_test.rb delete mode 100644 test/unit/gestalt/filename_rule_test.rb delete mode 100644 test/unit/gestalt/keyword_rule_test.rb delete mode 100644 test/unit/gestalt/rule_test.rb delete mode 100644 test/unit/glsl_test.rb delete mode 100644 test/unit/language_breakdown_test.rb delete mode 100644 test/unit/language_test.rb delete mode 100644 test/unit/license_sniffer_test.rb delete mode 100644 test/unit/loc_delta_list_test.rb delete mode 100644 test/unit/loc_delta_test.rb delete mode 100644 test/unit/loc_list_test.rb delete mode 100644 test/unit/loc_test.rb delete mode 100644 test/unit/nix_test.rb delete mode 100644 test/unit/parsers/actionscript_test.rb delete mode 100644 test/unit/parsers/ada_test.rb delete mode 100644 test/unit/parsers/assembler_test.rb delete mode 100644 test/unit/parsers/autoconf_test.rb delete mode 100644 test/unit/parsers/automake_test.rb delete mode 100644 test/unit/parsers/awk_test.rb delete mode 100644 test/unit/parsers/basic_test.rb delete mode 100644 test/unit/parsers/bat_test.rb delete mode 100644 test/unit/parsers/boo_test.rb delete mode 100644 test/unit/parsers/c_test.rb delete mode 100644 test/unit/parsers/clearsilver_template_test.rb delete mode 100644 test/unit/parsers/clearsilver_test.rb delete mode 100644 test/unit/parsers/cmake_test.rb delete mode 100644 test/unit/parsers/cs_aspx_test.rb delete mode 100644 test/unit/parsers/csharp_test.rb delete mode 100644 test/unit/parsers/css_test.rb delete mode 100644 test/unit/parsers/d_test.rb delete mode 100644 test/unit/parsers/dcl_test.rb delete mode 100644 test/unit/parsers/dylan_test.rb delete mode 100644 test/unit/parsers/ebuild_test.rb delete mode 100644 test/unit/parsers/eiffel_test.rb delete mode 100644 test/unit/parsers/emacs_lisp.rb delete mode 100644 test/unit/parsers/erlang_test.rb delete mode 100644 test/unit/parsers/exheres_test.rb delete mode 100644 test/unit/parsers/factor_test.rb delete mode 100644 test/unit/parsers/fortran_test.rb delete mode 100644 test/unit/parsers/groovy_test.rb delete mode 100644 test/unit/parsers/haml_test.rb delete mode 100644 test/unit/parsers/haskell_test.rb delete mode 100644 test/unit/parsers/haxe_test.rb delete mode 100644 test/unit/parsers/html_test.rb delete mode 100644 test/unit/parsers/java_test.rb delete mode 100644 test/unit/parsers/javascript_test.rb delete mode 100644 test/unit/parsers/jsp_test.rb delete mode 100644 test/unit/parsers/limbo_test.rb delete mode 100644 test/unit/parsers/lisp_test.rb delete mode 100644 test/unit/parsers/lua_test.rb delete mode 100644 test/unit/parsers/make_test.rb delete mode 100644 test/unit/parsers/matlab_test.rb delete mode 100644 test/unit/parsers/metafont_test.rb delete mode 100644 test/unit/parsers/metapost_test.rb delete mode 100644 test/unit/parsers/mxml_test.rb delete mode 100644 test/unit/parsers/objective_j_test.rb delete mode 100644 test/unit/parsers/ocaml_test.rb delete mode 100644 test/unit/parsers/octave_test.rb delete mode 100644 test/unit/parsers/pascal_test.rb delete mode 100644 test/unit/parsers/perl_test.rb delete mode 100644 test/unit/parsers/php_test.rb delete mode 100644 test/unit/parsers/pike_test.rb delete mode 100644 test/unit/parsers/python_test.rb delete mode 100644 test/unit/parsers/r_test.rb delete mode 100644 test/unit/parsers/rexx_test.rb delete mode 100644 test/unit/parsers/rhtml_test.rb delete mode 100644 test/unit/parsers/ruby_test.rb delete mode 100644 test/unit/parsers/scala_test.rb delete mode 100644 test/unit/parsers/scheme_test.rb delete mode 100644 test/unit/parsers/scilab_test.rb delete mode 100644 test/unit/parsers/shell_test.rb delete mode 100644 test/unit/parsers/smalltalk_test.rb delete mode 100644 test/unit/parsers/sql_test.rb delete mode 100644 test/unit/parsers/stratego_test.rb delete mode 100644 test/unit/parsers/tcl_test.rb delete mode 100644 test/unit/parsers/tex_test.rb delete mode 100644 test/unit/parsers/vala_test.rb delete mode 100644 test/unit/parsers/vb_aspx_test.rb delete mode 100644 test/unit/parsers/vhdl_test.rb delete mode 100644 test/unit/parsers/vim_test.rb delete mode 100644 test/unit/parsers/visual_basic_test.rb delete mode 100644 test/unit/parsers/xaml_test.rb delete mode 100644 test/unit/parsers/xml_test.rb delete mode 100644 test/unit/parsers/xmlschema_test.rb delete mode 100644 test/unit/parsers/xslt_test.rb delete mode 100644 test/unit/source_file_list_test.rb delete mode 100644 test/unit/source_file_test.rb delete mode 100644 vendor/gems/diff-lcs-1.1.2/ChangeLog delete mode 100644 vendor/gems/diff-lcs-1.1.2/Install delete mode 100644 vendor/gems/diff-lcs-1.1.2/README delete mode 100644 vendor/gems/diff-lcs-1.1.2/Rakefile delete mode 100755 vendor/gems/diff-lcs-1.1.2/bin/htmldiff delete mode 100755 vendor/gems/diff-lcs-1.1.2/bin/ldiff delete mode 100644 vendor/gems/diff-lcs-1.1.2/diff-lcs.gemspec delete mode 100644 vendor/gems/diff-lcs-1.1.2/install.rb delete mode 100644 vendor/gems/diff-lcs-1.1.2/lib/diff/lcs.rb delete mode 100644 vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/array.rb delete mode 100644 vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/block.rb delete mode 100644 vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/callbacks.rb delete mode 100644 vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/change.rb delete mode 100644 vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/hunk.rb delete mode 100644 vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/ldiff.rb delete mode 100644 vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/string.rb delete mode 100644 vendor/gems/diff-lcs-1.1.2/tests/00test.rb diff --git a/PARSER_DOC b/PARSER_DOC deleted file mode 100644 index 94bf652..0000000 --- a/PARSER_DOC +++ /dev/null @@ -1,314 +0,0 @@ -PARSER_DOC written by Mitchell Foral - -Overview: - I will assume the reader has a decent knowledge of how Ragel works and the - Ragel syntax. If not, please review the Ragel manual found at: - http://research.cs.queensu.ca/~thurston/ragel/ - - All parsers must at least: - * Call a callback function when a line of code is parsed. - * Call a callback function when a line of comment is parsed. - * Call a callback function when a blank line is parsed. - Additionally a parser can call the callback function for each position of - entities parsed. - - Take a look at c.rl and even keep it open for reference when reading this - document to better understand how parsers work and how to write one. - -Writing a Parser: - First create your parser in ext/ohcount_native/ragel_parsers/. Its name - should be the language you are parsing with a '.rl' extension. You will not - have to manually compile any parsers, as the Rakefile does this automatically - for you. However, you do need to add appropriate clauses manually to - ext/ohcount_native/ragel_parser.c to find your new parser. - - Every parser must have the following at the top: - -/************************* Required for every parser *************************/ -#ifndef RAGEL_C_PARSER -#define RAGEL_C_PARSER - -#include "ragel_parser_macros.h" - -// the name of the language -const char *C_LANG = "c"; - -// the languages entities -const char *c_entities[] = { - "space", "comment", "string", "number", "preproc", - "keyword", "identifier", "operator", "any" -}; - -// constants associated with the entities -enum { - C_SPACE = 0, C_COMMENT, C_STRING, C_NUMBER, C_PREPROC, - C_KEYWORD, C_IDENTIFIER, C_OPERATOR, C_ANY -}; - -/*****************************************************************************/ - - And the following at the bottom: - -/************************* Required for every parser *************************/ - -/* Parses a string buffer with C/C++ code. - * - * @param *buffer The string to parse. - * @param length The length of the string to parse. - * @param count Integer flag specifying whether or not to count lines. If yes, - * uses the Ragel machine optimized for counting. Otherwise uses the Ragel - * machine optimized for returning entity positions. - * @param *callback Callback function. If count is set, callback is called for - * every line of code, comment, or blank with 'lcode', 'lcomment', and - * 'lblank' respectively. Otherwise callback is called for each entity found. - */ -void parse_c(char *buffer, int length, int count, - void (*callback) (const char *lang, const char *entity, int start, int end) - ) { - init - - %% write init; - cs = (count) ? c_en_c_line : c_en_c_entity; - %% write exec; - - // if no newline at EOF; callback contents of last line - if (count) { process_last_line(C_LANG) } -} - -#endif - -/*****************************************************************************/ - - (Your parser will go between these two blocks.) - - The code can be found in the existing c.rl parser. You will need to change: - * RAGEL_[lang]_PARSER - Replace [lang] with your language name. So if you - are writing a C parser, it would be RAGEL_C_PARSER. - * [lang]_LANG - Set the variable name to be [lang]_LANG and its value to be - the name of your language to parse. [lang] is your language name. For C it - would be C_LANG. - * [lang]_entities - Set the variable name to be [lang]_entities (e.g. - c_entries) The value is an array of string entities your language has. - For example C has comment, string, number, etc. entities. You should - definately have "space", and "any" entities. "any" entities are typically - used for entity machines (discussed later) and match any character that - is not recognized so the parser does not do something unpredictable. - * enum - Change the value of the enum to correspond with your entities. So - if in your parser you look up [lang]_entities[ENTITY], you will get the - associated entity's string name. - * parse_[lang] - Set the function name to parse_[lang] where again, [lang] - is the name of your language. In the case of C, it is parse_c. - * [lang]_en_[lang]_line - The line counting machine. - * [lang]_en_[lang]_entity - The entity machine. - - You may be asking why you have to rename variables and functions. Well if - variables have the same name in header files (which is what parsers are), - the compiler complains. Also, when you have languages embedded inside each - other, any identifiers with the same name can easily be mixed up. It is also - important to prefix your Ragel definitions with your language to avoid - conflicts with other parsers. - - Additional variables available to parsers are in the "ragel_parser_macros.h" - file. Take a look at it and try to understand what the variables are used for. - They will make more sense later on. - - Now you can define your Ragel parser. Name your machine after your language, - 'write data', and include 'common.rl', a file with common Ragel definitions, - actions, etc. For example: - %%{ - machine c; - write data; - include "common.rl"; - - ... - }%% - - Before you begin to write patterns for each entity in your language, you need - to understand how the parser should work. - - Each parser has two machines: one optimized for counting lines of code, - comments, and blanks; the other for identifying entity positions in the - buffer. - - Line Counting Machine: - This machine should be written as a line-by-line parser for multiple lines. - This means you match any combination of entities except a newline up until - you do reach a newline. If the line contains only spaces, or nothing at all, - it is blank. If the line contains spaces at first, but then a comment, or - just simply a comment, the line is a comment. If the line contains anything - but a comment after spaces (if there are any), it is a line of code. You - will do this using a Ragel scanner. - The callback function will be called for each line parsed. - - Scanner Parser Structure: - A scanner parser will look like this: - [lang]_line := |* - entity1 ${ entity = ENTITY1; } => [lang]_ccallback; - entity2 ${ entity = ENTITY2; } => [lang]_ccallback; - ... - entityn ${ entity = ENTITYN; } => [lang]_ccallback; - *|; - (As usual, replace [lang] with your language name.) - Each entity is the pattern for an entity to match, the last one typically - being the newline entity. For each match, the variable is set to a - constant defined in the enum, and the main action is called (you will need - to create this action above the scanner). - - When you detect whether or not a line is code or comment, you should call - the appropriate 'code' or 'comment' action defined in common.rl as soon - as possible. It is not necessary to worry about whether or not these - actions are called more than once for a given line; the first call to - either sets the status of the line permanently. Sometimes you cannot call - 'code' or 'comment' for one reason or another. Do not worry, as this is - discussed later. - - When you reach a newline, you will need to decide whether the current line - is a line of code, comment, or blank. This is easy. Simply check if the - line_contains_code or whole_line_comment variables are set to 1. If - neither of them are, the line is blank. Then call the callback function - (not action) with an "lcode", "lcomment", or "lblank" string, and the - start and end positions of that line (including the newline). The start - position of the line is in the line_start variable. It should be set at - the beginning of every line either through the 'code' or 'comment' - actions, or manually in the main action. Finally the line_contains_code, - whole_line_comment, and line_start state variables must be reset. All this - should be done within the main action shown below. - Note: For most parsers, the std_newline(lang) macro is sufficient and does - everything in the main action mentioned above. The lang parameter is the - [lang]_LANG string. - - Main Action Structure: - The main action looks like this: - action [lang]_ccallback { - switch(entity) { - when ENTITY1: - ... - break; - when ENTITY2: - ... - break; - ... - when ENTITYN: - ... - break; - } - } - - Defining Patterns for Entities: - Now it is time to write patterns for each entity in your language. That - does not seem very hard, except when your entity can cover multiple lines. - Comments and strings in particular can do this. To make an accurate line - counter, you will need to count the lines covered by multi-line entities. - When you detect a newline inside your multi-line entity, you should set - the entity variable to be INTERNAL_NL (-2) and call the main action. The - main action should have a case for INTERNAL_NL separate from the newline - entity. In it, you will check if the current line is code or comment and - call the callback function with the appropriate string ("lcode" or - "lcomment") and beginning and end of the line (including the newline). - Afterwards, you will reset the line_contains_code and whole_line_comment - state variables. Then set the line_start variable to be p, the current - Ragel buffer position. Because line_contains_code and whole_line_comment - have been reset, any non-newline and non-space character in the multi-line - pattern should set line_contains_code or whole_line_comment back to 1. - Otherwise you would count the line as blank. - Note: For most parsers, the std_internal_newline(lang) macro is sufficient - and does everything in the main action mentioned above. The lang parameter - is the [lang]_LANG string. - - For multi-line matches, it is important to call the 'code' or 'comment' - actions (mentioned earlier) before an internal newline is detected so the - line_contains_code and whole_line_comment variables are properly set. For - other entities, you can use the 'code' macro inside the main action which - executes the same code as the Ragel 'code' action. Other C macros are - 'comment' and 'ls', the latter is typically used for the SPACE entity when - defining line_start. - - Also for multi-line matches, it may be necessary to use the 'enqueue' and - 'commit' actions. If it is possible that a multi-line entity will not have - an ending delimiter (for example a string), use the 'enqueue' action as - soon as the start delimitter has been detected, and the 'commit' action as - soon as the end delimitter has been detected. This will eliminate the - potential for any counting errors. - - Notes: - * You can be a bit sloppy with the line counting machine. For example the - only C entities that can contain newlines are strings and comments, so - INTERNAL_NL would only be necessary inside them. Other than those, - anything other than spaces is considered code, so do not waste your time - defining specific patterns for other entities. - - Parsers with Embedded Languages: - Notation: [lang] is the parent language, [elang] is the embedded language. - - To write a parser with embedded languages (such as HTML with embedded CSS - and Javascript), you should first #include the parser(s) above your Ragel - code. The header file is "[elang]_parser.h". - - Next, after the inclusion of 'common.rl', add '#EMBED([elang])' on - separate lines for each embedded language. The Rakefile looks for these - special comments to embed the language for you automatically. - - In your main action, you need to add another entity CHECK_BLANK_ENTRY. It - should call the 'check_blank_entry([lang]_LANG)' macro. Blank entries are - an entry into an embedded language, but the rest of the line is blank - before a newline. For example, a CSS entry in HTML is something like: - ", 'html', :comment).first) - assert_equal('//comment', entities_array("", 'html', :comment).first) - assert_equal('/*comment*/', entities_array("", 'html', :comment).first) - end -end diff --git a/test/unit/parsers/java_test.rb b/test/unit/parsers/java_test.rb deleted file mode 100644 index 1951b51..0000000 --- a/test/unit/parsers/java_test.rb +++ /dev/null @@ -1,21 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::JavaTest < Ohcount::Test - def test_comments - lb = [Ohcount::LanguageBreakdown.new("java", "", "//comment", 0)] - assert_equal lb, Ohcount::parse(" //comment", "java") - end - - def test_comprehensive - verify_parse("java1.java") - end - - def test_comprehensive_with_carriage_returns - verify_parse("java2.java") - end - - def test_comment_entities - assert_equal('//comment', entities_array(" //comment", 'java', :comment).first) - assert_equal('/*comment*/', entities_array(" /*comment*/", 'java', :comment).first) - end -end diff --git a/test/unit/parsers/javascript_test.rb b/test/unit/parsers/javascript_test.rb deleted file mode 100644 index e655179..0000000 --- a/test/unit/parsers/javascript_test.rb +++ /dev/null @@ -1,22 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::JavascriptTest < Ohcount::Test - def test_comments - lb = [Ohcount::LanguageBreakdown.new("javascript", "", "//comment", 0)] - assert_equal lb, Ohcount::parse(" //comment", "javascript") - end - - def test_comprehensive - verify_parse("js1.js") - end - - def test_comp2 - verify_parse("js2.js") - end - - def test_comment_entities - assert_equal('//comment', entities_array(" //comment", 'javascript', :comment).first) - assert_equal('/*comment*/', entities_array(" /*comment*/", 'javascript', :comment).first) - end - -end diff --git a/test/unit/parsers/jsp_test.rb b/test/unit/parsers/jsp_test.rb deleted file mode 100644 index 1d0e037..0000000 --- a/test/unit/parsers/jsp_test.rb +++ /dev/null @@ -1,20 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::JspTest < Ohcount::Test - def test_comment - html_lb = Ohcount::LanguageBreakdown.new("html", "%>", "", 0) - java_lb = Ohcount::LanguageBreakdown.new("java", "", "<% //comment\n", 0) - assert_equal [java_lb, html_lb], Ohcount::parse(" <% //comment\n%>", "jsp") - end - - def test_comprehensive - verify_parse("jsp1.jsp") - end - - def test_comment_entities - assert_equal('', entities_array(" ", 'jsp', :comment).first) - assert_equal('/*comment*/', entities_array("", 'jsp', :comment).first) - assert_equal('//comment', entities_array("<%\n//comment\n%>", 'jsp', :comment).first) - assert_equal('/*comment*/', entities_array("<%\n/*comment*/\n%>", 'jsp', :comment).first) - end -end diff --git a/test/unit/parsers/limbo_test.rb b/test/unit/parsers/limbo_test.rb deleted file mode 100644 index f41788d..0000000 --- a/test/unit/parsers/limbo_test.rb +++ /dev/null @@ -1,24 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::LimboTest < Ohcount::Test - - def test_comments - lb = [Ohcount::LanguageBreakdown.new("limbo", "", "#comment", 0)] - assert_equal lb, Ohcount::parse(" #comment", "limbo") - end - - def test_empty_comments - lb = [Ohcount::LanguageBreakdown.new("limbo", "","#\n", 0)] - assert_equal lb, Ohcount::parse(" #\n", "limbo") - end - - def test_comprehensive - verify_parse("limbo.b") - verify_parse("limbo.m") - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'limbo', :comment).first) - end - -end diff --git a/test/unit/parsers/lisp_test.rb b/test/unit/parsers/lisp_test.rb deleted file mode 100644 index fb7b8e2..0000000 --- a/test/unit/parsers/lisp_test.rb +++ /dev/null @@ -1,38 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::LispTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("lisp", "", ";;; comment", 0)] - assert_equal lb, Ohcount::parse(" ;;; comment", "lisp") - end - - def test_doc_string - lb = [Ohcount::LanguageBreakdown.new("lisp", "", '""" comment """', 0)] - assert_equal lb, Ohcount::parse(' """ comment """', "lisp") - end - - def test_doc_string_blank - lb = [Ohcount::LanguageBreakdown.new("lisp", "", '""""""', 0)] - assert_equal lb, Ohcount::parse(' """"""', "lisp") - end - - def test_empty_string - lb = [Ohcount::LanguageBreakdown.new("lisp", '""', "", 0)] - assert_equal lb, Ohcount::parse(' ""', "lisp") - end - - def test_char_string - lb = [Ohcount::LanguageBreakdown.new("lisp", '"a"', "", 0)] - assert_equal lb, Ohcount::parse(' "a"', "lisp") - end - - def test_comprehensive - verify_parse("lsp1.lsp") - end - - def test_comment_entities - assert_equal(';comment', entities_array(" ;comment", 'lisp', :comment).first) - end - -end diff --git a/test/unit/parsers/lua_test.rb b/test/unit/parsers/lua_test.rb deleted file mode 100644 index 786f0c9..0000000 --- a/test/unit/parsers/lua_test.rb +++ /dev/null @@ -1,19 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::LuaTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("lua", "", "-- comment", 0)] - assert_equal lb, Ohcount::parse(" -- comment", "lua") - end - - def test_comprehensive - verify_parse("lua1.lua") - end - - def test_comment_entities - assert_equal('--comment', entities_array(" --comment", 'lua', :comment).first) - assert_equal("--[[comment\ncomment]]", entities_array(" --[[comment\ncomment]]", 'lua', :comment).first) - end - -end diff --git a/test/unit/parsers/make_test.rb b/test/unit/parsers/make_test.rb deleted file mode 100644 index fc705fe..0000000 --- a/test/unit/parsers/make_test.rb +++ /dev/null @@ -1,13 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::MakefileTest < Ohcount::Test - def test_comprehensive - verify_parse("Makefile") - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'make', :comment).first) - end - -end - diff --git a/test/unit/parsers/matlab_test.rb b/test/unit/parsers/matlab_test.rb deleted file mode 100644 index 7ff78fc..0000000 --- a/test/unit/parsers/matlab_test.rb +++ /dev/null @@ -1,30 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::MatlabTest < Ohcount::Test - - def test_line_comment_1 - lb = [Ohcount::LanguageBreakdown.new("matlab", "", "%comment", 0)] - assert_equal lb, Ohcount::parse(" %comment", "matlab") - end - - def test_ancient_syntax_comment - lb = [Ohcount::LanguageBreakdown.new("matlab", "", "... comment", 0)] - assert_equal lb, Ohcount::parse(" ... comment", "matlab") - end - - def test_false_line_comment - lb = [Ohcount::LanguageBreakdown.new("matlab", "%{block%} code", "", 0)] - assert_equal lb, Ohcount::parse(" %{block%} code", "matlab") - end - - def test_comprehensive - verify_parse("matlab1.m", 'matlab') - end - - def test_comment_entities - assert_equal('%comment', entities_array(" %comment", 'matlab', :comment).first) - assert_equal('... comment', entities_array(" ... comment", 'matlab', :comment).first) - assert_equal('%{comment%}', entities_array(" %{comment%}", 'matlab', :comment).first) - end - -end diff --git a/test/unit/parsers/metafont_test.rb b/test/unit/parsers/metafont_test.rb deleted file mode 100644 index d316c89..0000000 --- a/test/unit/parsers/metafont_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::MetaFontTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("metafont", "", "% comment", 0)] - assert_equal lb, Ohcount::parse(" % comment", "metafont") - end - - def test_comprehensive - verify_parse("metafont.mf") - end - - def test_comment_entities - assert_equal('%comment', entities_array(" %comment", 'metafont', :comment).first) - end -end diff --git a/test/unit/parsers/metapost_test.rb b/test/unit/parsers/metapost_test.rb deleted file mode 100644 index 45a6c04..0000000 --- a/test/unit/parsers/metapost_test.rb +++ /dev/null @@ -1,17 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::MetaPostTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("metapost", "", "% comment", 0)] - assert_equal lb, Ohcount::parse(" % comment", "metapost") - end - - def test_comprehensive - verify_parse("metapost.mp") - end - - def test_comment_entities - assert_equal('%comment', entities_array(" %comment", 'metapost', :comment).first) - assert_equal('%comment', entities_array("verbatim\n%comment\netex", 'metapost', :comment).first) - end -end diff --git a/test/unit/parsers/mxml_test.rb b/test/unit/parsers/mxml_test.rb deleted file mode 100644 index 09411c8..0000000 --- a/test/unit/parsers/mxml_test.rb +++ /dev/null @@ -1,14 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::MxmlTest < Ohcount::Test - def test_comprehensive - verify_parse("mxml1.mxml") - end - - def test_comment_entities - assert_equal('', entities_array(" ", 'mxml', :comment).first) - assert_equal('/*comment*/', entities_array("\n/*comment*/\n", 'mxml', :comment).first) - assert_equal('//comment', entities_array("\n//comment\n", 'mxml', :comment).first) - assert_equal('/*comment*/', entities_array("\n/*comment*/\n", 'mxml', :comment).first) - end -end diff --git a/test/unit/parsers/objective_j_test.rb b/test/unit/parsers/objective_j_test.rb deleted file mode 100644 index 507f3d6..0000000 --- a/test/unit/parsers/objective_j_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::ObjectiveJTest < Ohcount::Test - def test_comments - lb = [Ohcount::LanguageBreakdown.new("objective_j", "", "//comment", 0)] - assert_equal lb, Ohcount::parse(" //comment", "objective_j") - end - - def test_comprehensive - verify_parse("objj.j") - end - - def test_comment_entities - assert_equal('//comment', entities_array(" //comment", 'objective_j', :comment).first) - assert_equal('/*comment*/', entities_array(" /*comment*/", 'objective_j', :comment).first) - end - -end diff --git a/test/unit/parsers/ocaml_test.rb b/test/unit/parsers/ocaml_test.rb deleted file mode 100644 index 29a0c5b..0000000 --- a/test/unit/parsers/ocaml_test.rb +++ /dev/null @@ -1,17 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::OcamlTest < Ohcount::Test - def test_regular_comments - lb = [Ohcount::LanguageBreakdown.new("ocaml", "", "(* comment *)", 0)] - assert_equal lb, Ohcount::parse(" (* comment *)", "ocaml") - end - - def test_comprehensive - verify_parse("ocaml.ml") - end - - def test_comment_entities - assert_equal('(*comment*)', entities_array(" (*comment*)", 'ocaml', :comment).first) - end - -end diff --git a/test/unit/parsers/octave_test.rb b/test/unit/parsers/octave_test.rb deleted file mode 100644 index 98eb88d..0000000 --- a/test/unit/parsers/octave_test.rb +++ /dev/null @@ -1,30 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::OctaveTest < Ohcount::Test - - def test_line_comment_1 - lb = [Ohcount::LanguageBreakdown.new("octave", "", "%comment", 0)] - assert_equal lb, Ohcount::parse(" %comment", "octave") - end - - def test_octave_syntax_comment - lb = [Ohcount::LanguageBreakdown.new("octave", "", "# comment", 0)] - assert_equal lb, Ohcount::parse(" # comment", "octave") - end - - # Note: GNU Octave doesn't support block comments *yet*, but it might in the future. - def test_false_line_comment - lb = [Ohcount::LanguageBreakdown.new("octave", "%{block%} code", "", 0)] - assert_equal lb, Ohcount::parse(" %{block%} code", "octave") - end - - def test_comprehensive - verify_parse("octave1.m", 'octave') - end - - def test_comment_entities - assert_equal('%comment', entities_array(" %comment", 'octave', :comment).first) - assert_equal('# comment', entities_array(" # comment", 'octave', :comment).first) - end - -end diff --git a/test/unit/parsers/pascal_test.rb b/test/unit/parsers/pascal_test.rb deleted file mode 100644 index 1326282..0000000 --- a/test/unit/parsers/pascal_test.rb +++ /dev/null @@ -1,19 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::PascalTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("pascal", "", "//comment", 0)] - assert_equal lb, Ohcount::parse(" //comment", "pascal") - end - - def test_comprehensive - verify_parse("pascal1.pas") - verify_parse("pascal2.pp") - end - - def test_comment_entities - assert_equal('//comment', entities_array(" //comment", 'pascal', :comment).first) - assert_equal('(*comment*)', entities_array(" (*comment*)", 'pascal', :comment).first) - assert_equal('{comment}', entities_array(" {comment}", 'pascal', :comment).first) - end -end diff --git a/test/unit/parsers/perl_test.rb b/test/unit/parsers/perl_test.rb deleted file mode 100644 index ababb19..0000000 --- a/test/unit/parsers/perl_test.rb +++ /dev/null @@ -1,23 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::PerlTest < Ohcount::Test - def test_comments - lb = [Ohcount::LanguageBreakdown.new("perl", "", "#comment", 0)] - assert_equal lb, Ohcount::parse(" #comment", "perl") - end - - def test_perl_in_cgi - verify_parse("perl.cgi") - end - - def test_comprehensive - verify_parse("perl1.pl") - verify_parse("perl_module.pm") - verify_parse("perl_pod_to_eof.pl") # Verifies ticket #267 - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'perl', :comment).first) - assert_equal("=head1\ncomment\n=cut", entities_array("=head1\ncomment\n=cut", 'perl', :comment).first) - end -end diff --git a/test/unit/parsers/php_test.rb b/test/unit/parsers/php_test.rb deleted file mode 100644 index 78895ce..0000000 --- a/test/unit/parsers/php_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::PhpTest < Ohcount::Test - def test_comment - lbhtml = Ohcount::LanguageBreakdown.new("html", "", "", 0) - lbphp = Ohcount::LanguageBreakdown.new("php", "", "//comment\n", 0) - assert_equal [lbhtml, lbphp], Ohcount::parse("", "php") - end - - def test_comprehensive - verify_parse("php1.php") - end - - def test_comment_entities - assert_equal('// comment', entities_array("\n", 'php', :comment).first) - assert_equal('/* comment */', entities_array("\n", 'php', :comment).first) - end -end diff --git a/test/unit/parsers/pike_test.rb b/test/unit/parsers/pike_test.rb deleted file mode 100644 index c9714c7..0000000 --- a/test/unit/parsers/pike_test.rb +++ /dev/null @@ -1,26 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::PikeTest < Ohcount::Test - def test_comments - lb = [Ohcount::LanguageBreakdown.new("pike", "", "//comment", 0)] - assert_equal lb, Ohcount::parse(" //comment", "pike") - end - - def test_comments2 - lb = [Ohcount::LanguageBreakdown.new("pike", "", "/*comment*/", 0)] - assert_equal lb, Ohcount::parse(" /*comment*/", "pike") - end - - def test_comprehensive - verify_parse("pike1.pike") - end - - def test_comprehensive_pmod - verify_parse("pike2.pmod") - end - - def test_comment_entities - assert_equal('//comment', entities_array(" //comment", 'pike', :comment).first) - assert_equal('/*comment*/', entities_array(" /*comment*/", 'pike', :comment).first) - end -end diff --git a/test/unit/parsers/python_test.rb b/test/unit/parsers/python_test.rb deleted file mode 100644 index 12a04d0..0000000 --- a/test/unit/parsers/python_test.rb +++ /dev/null @@ -1,27 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::PythonTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("python", "", "#comment", 0)] - assert_equal lb, Ohcount::parse(" #comment", "python") - end - - def test_doc_comment - lb = [Ohcount::LanguageBreakdown.new("python", "", "'''\ndoc comment\n'''", 0)] - assert_equal lb, Ohcount::parse(" '''\n doc comment\n '''", "python") - end - - def test_strings - lb = [Ohcount::LanguageBreakdown.new("python", "\"abc#not a 'comment\"", "", 0)] - assert_equal lb, Ohcount::parse("\"abc#not a 'comment\"", "python") - end - - def test_comprehensive - verify_parse("py1.py") - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'python', :comment).first) - assert_equal('"""comment"""', entities_array(" \"\"\"comment\"\"\"", 'python', :comment).first) - end -end diff --git a/test/unit/parsers/r_test.rb b/test/unit/parsers/r_test.rb deleted file mode 100644 index f86f75c..0000000 --- a/test/unit/parsers/r_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::RTest < Ohcount::Test - - def test_line_comment_1 - lb = [Ohcount::LanguageBreakdown.new("r", "", "#comment", 0)] - assert_equal lb, Ohcount::parse(" #comment", "r") - end - - def test_comprehensive - verify_parse("example.R", 'r') - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'r', :comment).first) - end - -end diff --git a/test/unit/parsers/rexx_test.rb b/test/unit/parsers/rexx_test.rb deleted file mode 100644 index 3c7f7f4..0000000 --- a/test/unit/parsers/rexx_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::RexxTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("rexx", "", "/*comment*/", 0)] - assert_equal lb, Ohcount::parse(" /*comment*/", "rexx") - end - - def test_comprehensive - verify_parse("rexx1.rex") - end - - def test_comment_entities - assert_equal('/*comment*/', entities_array(" /*comment*/", 'rexx', :comment).first) - end - -end diff --git a/test/unit/parsers/rhtml_test.rb b/test/unit/parsers/rhtml_test.rb deleted file mode 100644 index 737e8fc..0000000 --- a/test/unit/parsers/rhtml_test.rb +++ /dev/null @@ -1,24 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::RhtmlTest < Ohcount::Test - - def test_comment - html_lb = Ohcount::LanguageBreakdown.new("html", "<%\n%>", "", 0) - ruby_lb = Ohcount::LanguageBreakdown.new("ruby", "", "#comment\n", 0) - assert_equal [html_lb, ruby_lb], Ohcount::parse("<%\n #comment\n%>", "rhtml") - end - - def test_comprehensive - verify_parse("rhtml1.rhtml") - end - - def test_comment_entities - assert_equal('', entities_array(" ", 'rhtml', :comment).first) - assert_equal('/*comment*/', entities_array("", 'rhtml', :comment).first) - assert_equal('//comment', entities_array("", 'rhtml', :comment).first) - assert_equal('/*comment*/', entities_array("", 'rhtml', :comment).first) - assert_equal('#comment', entities_array("<%\n#comment\n%>", 'rhtml', :comment).first) - assert_equal("=begin\ncomment\n=end", entities_array("<%\n=begin\ncomment\n=end\n%>", 'rhtml', :comment).first) - end - -end diff --git a/test/unit/parsers/ruby_test.rb b/test/unit/parsers/ruby_test.rb deleted file mode 100644 index 4d5768f..0000000 --- a/test/unit/parsers/ruby_test.rb +++ /dev/null @@ -1,19 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::RubyTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("ruby", "", "#comment", 0)] - assert_equal lb, Ohcount::parse(" #comment", "ruby") - end - - def test_comprehensive - verify_parse("ruby1.rb") - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'ruby', :comment).first) - assert_equal("=begin\ncomment\n=end", entities_array("=begin\ncomment\n=end", 'ruby', :comment).first) - end - -end diff --git a/test/unit/parsers/scala_test.rb b/test/unit/parsers/scala_test.rb deleted file mode 100644 index 4d5521e..0000000 --- a/test/unit/parsers/scala_test.rb +++ /dev/null @@ -1,14 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::ScalaTest < Ohcount::Test - - def test_comprehensive - verify_parse("scala1.scala") - end - - def test_comment_entities - assert_equal('//comment', entities_array(" //comment", 'scala', :comment).first) - assert_equal('/*comment*/', entities_array(" /*comment*/", 'scala', :comment).first) - end - -end diff --git a/test/unit/parsers/scheme_test.rb b/test/unit/parsers/scheme_test.rb deleted file mode 100644 index 51ae671..0000000 --- a/test/unit/parsers/scheme_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::SchemeTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("scheme", "", ";;; comment", 0)] - assert_equal lb, Ohcount::parse(" ;;; comment", "scheme") - end - - def test_comprehensive - verify_parse("scheme.scm") - end - - def test_comment_entities - assert_equal(';comment', entities_array(" ;comment", 'scheme', :comment).first) - end - -end diff --git a/test/unit/parsers/scilab_test.rb b/test/unit/parsers/scilab_test.rb deleted file mode 100644 index 3920cae..0000000 --- a/test/unit/parsers/scilab_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::ScilabTest < Ohcount::Test - - def test_line_comment_1 - lb = [Ohcount::LanguageBreakdown.new("scilab", "", "//comment", 0)] - assert_equal lb, Ohcount::parse(" //comment", "scilab") - end - - def test_comprehensive - verify_parse("scilab.sci", 'scilab') - end - - def test_comment_entities - assert_equal('//comment', entities_array(" //comment", 'scilab', :comment).first) - end - -end diff --git a/test/unit/parsers/shell_test.rb b/test/unit/parsers/shell_test.rb deleted file mode 100644 index 666be08..0000000 --- a/test/unit/parsers/shell_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::ShellTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("shell", "", "#comment", 0)] - assert_equal lb, Ohcount::parse(" #comment", "shell") - end - - def test_comprehensive - verify_parse("sh1.sh") - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'shell', :comment).first) - end -end diff --git a/test/unit/parsers/smalltalk_test.rb b/test/unit/parsers/smalltalk_test.rb deleted file mode 100644 index 280b77f..0000000 --- a/test/unit/parsers/smalltalk_test.rb +++ /dev/null @@ -1,19 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::SmalltalkTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("smalltalk", "", '"comment\\"', 0)] - assert_equal lb, Ohcount::parse(' "comment\\"', "smalltalk") - end - - def test_comprehensive - verify_parse("smalltalk1.st") - verify_parse("english.st") - end - - def test_comment_entities - assert_equal('"comment"', entities_array(" \"comment\"", 'smalltalk', :comment).first) - end - -end diff --git a/test/unit/parsers/sql_test.rb b/test/unit/parsers/sql_test.rb deleted file mode 100644 index 59e13c5..0000000 --- a/test/unit/parsers/sql_test.rb +++ /dev/null @@ -1,32 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::SqlTest < Ohcount::Test - - def test_comments - lb = [Ohcount::LanguageBreakdown.new("sql", "", "--comment", 0)] - assert_equal lb, Ohcount::parse(" --comment", "sql") - end - - def test_empty_comments - lb = [Ohcount::LanguageBreakdown.new("sql", "","--\n", 0)] - assert_equal lb, Ohcount::parse(" --\n", "sql") - end - - def test_block_comment - lb = [Ohcount::LanguageBreakdown.new("sql", "","{sql}", 0)] - assert_equal lb, Ohcount::parse(" {sql}", "sql") - end - - def test_comprehensive - verify_parse("sql1.sql") - end - - def test_comment_entities - assert_equal('--comment', entities_array(" --comment", 'sql', :comment).first) - assert_equal('#comment', entities_array(" #comment", 'sql', :comment).first) - assert_equal('//comment', entities_array(" //comment", 'sql', :comment).first) - assert_equal('/*comment*/', entities_array(" /*comment*/", 'sql', :comment).first) - assert_equal('{comment}', entities_array(" {comment}", 'sql', :comment).first) - end - -end diff --git a/test/unit/parsers/stratego_test.rb b/test/unit/parsers/stratego_test.rb deleted file mode 100644 index 2d33e67..0000000 --- a/test/unit/parsers/stratego_test.rb +++ /dev/null @@ -1,22 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::StrategoTest < Ohcount::Test - def test_line_comments - lb = [Ohcount::LanguageBreakdown.new("stratego", "", "// comment", 0)] - assert_equal lb, Ohcount::parse("// comment", "stratego") - end - - def test_comprehensive - verify_parse("stratego.str") - end - - def test_char_string_entities - assert_equal("'c'", entities_array(" 'c'", 'stratego', :string).first) - # single quote can be used in identiiers - # weak case - assert_not_equal(" c'", entities_array(" c'", 'stratego', :string).first) - # strong case - assert_not_equal("' = e'", entities_array(" c' = e'", 'stratego', :string).first) - end - -end diff --git a/test/unit/parsers/tcl_test.rb b/test/unit/parsers/tcl_test.rb deleted file mode 100644 index 17c0f1c..0000000 --- a/test/unit/parsers/tcl_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::TclTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("tcl", "", "#comment", 0)] - assert_equal lb, Ohcount::parse(" #comment", "tcl") - end - - def test_comprehensive - verify_parse("tcl1.tcl") - end - - def test_comment_entities - assert_equal('#comment', entities_array(" #comment", 'tcl', :comment).first) - end -end diff --git a/test/unit/parsers/tex_test.rb b/test/unit/parsers/tex_test.rb deleted file mode 100644 index 0d4d436..0000000 --- a/test/unit/parsers/tex_test.rb +++ /dev/null @@ -1,17 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::TeXTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("tex", "", "%comment", 0)] - assert_equal lb, Ohcount::parse(" %comment", "tex") - end - - def test_comprehensive - verify_parse("foo.tex") - end - - def test_comment_entities - assert_equal('%comment', entities_array(" %comment", 'tex', :comment).first) - end -end diff --git a/test/unit/parsers/vala_test.rb b/test/unit/parsers/vala_test.rb deleted file mode 100644 index a80b3fd..0000000 --- a/test/unit/parsers/vala_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::ValaTest < Ohcount::Test - - def test_comment - lb = [Ohcount::LanguageBreakdown.new("vala", "", "//comment", 0)] - assert_equal lb, Ohcount::parse(" //comment", "vala") - end - - def test_comprehensive - verify_parse("vala1.vala") - end - - def test_comment_entities - assert_equal('//comment', entities_array(" //comment", 'vala', :comment).first) - assert_equal('/*comment*/', entities_array(" /*comment*/", 'vala', :comment).first) - end -end diff --git a/test/unit/parsers/vb_aspx_test.rb b/test/unit/parsers/vb_aspx_test.rb deleted file mode 100644 index 1cd10f0..0000000 --- a/test/unit/parsers/vb_aspx_test.rb +++ /dev/null @@ -1,15 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::VbAspxTest < Ohcount::Test - - def test_comment - html_lb = Ohcount::LanguageBreakdown.new("html", "<%\n%>", "", 0) - vb_lb = Ohcount::LanguageBreakdown.new("visualbasic", "", "'comment\n", 0) - assert_equal [html_lb, vb_lb], Ohcount::parse("<%\n 'comment\n%>", "vb_aspx") - end - - def test_comprehensive - verify_parse("vb.aspx") - end - -end diff --git a/test/unit/parsers/vhdl_test.rb b/test/unit/parsers/vhdl_test.rb deleted file mode 100644 index 69d7da2..0000000 --- a/test/unit/parsers/vhdl_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::VHDLTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("vhdl", "", "-- comment", 0)] - assert_equal lb, Ohcount::parse(" -- comment", "vhdl") - end - - def test_comprehensive - verify_parse("vhdl1.vhd") - end - - def test_comment_entities - assert_equal('--comment', entities_array(" --comment", 'vhdl', :comment).first) - end -end diff --git a/test/unit/parsers/vim_test.rb b/test/unit/parsers/vim_test.rb deleted file mode 100644 index 40dd080..0000000 --- a/test/unit/parsers/vim_test.rb +++ /dev/null @@ -1,7 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::VimTest < Ohcount::Test - def test_comprehensive - verify_parse("foo.vim") - end -end diff --git a/test/unit/parsers/visual_basic_test.rb b/test/unit/parsers/visual_basic_test.rb deleted file mode 100644 index 5d99ea0..0000000 --- a/test/unit/parsers/visual_basic_test.rb +++ /dev/null @@ -1,17 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::VisualBasicTest < Ohcount::Test - def test_comments - lb = [Ohcount::LanguageBreakdown.new("visualbasic", "", "'comment", 0)] - assert_equal lb, Ohcount::parse(" 'comment", "visualbasic") - end - - def test_comprehensive - verify_parse("frx1.frx") - end - - def test_comment_entities - assert_equal('\'comment', entities_array(" 'comment", 'visualbasic', :comment).first) - assert_equal('Rem comment', entities_array(" Rem comment", 'visualbasic', :comment).first) - end -end diff --git a/test/unit/parsers/xaml_test.rb b/test/unit/parsers/xaml_test.rb deleted file mode 100644 index c3feb46..0000000 --- a/test/unit/parsers/xaml_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::XamlTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("xaml", "", "", 0)] - assert_equal lb, Ohcount::parse(" ", "xaml") - end - - def test_comprehensive - verify_parse("click_me.xaml") - end - - def test_comment_entities - assert_equal('', entities_array(" ", 'xaml', :comment).first) - end -end diff --git a/test/unit/parsers/xml_test.rb b/test/unit/parsers/xml_test.rb deleted file mode 100644 index 280b782..0000000 --- a/test/unit/parsers/xml_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::XmlTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("xml", "", "", 0)] - assert_equal lb, Ohcount::parse(" ", "xml") - end - - def test_comprehensive - verify_parse("xml1.xml") - end - - def test_comment_entities - assert_equal('', entities_array(" ", 'xml', :comment).first) - end -end diff --git a/test/unit/parsers/xmlschema_test.rb b/test/unit/parsers/xmlschema_test.rb deleted file mode 100644 index 5ff20ca..0000000 --- a/test/unit/parsers/xmlschema_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::XMLSchemaTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("xmlschema", "", "", 0)] - assert_equal lb, Ohcount::parse(" ", "xmlschema") - end - - def test_comprehensive - verify_parse("schema.xsd") - end - - def test_comment_entities - assert_equal('', entities_array(" ", 'xmlschema', :comment).first) - end -end diff --git a/test/unit/parsers/xslt_test.rb b/test/unit/parsers/xslt_test.rb deleted file mode 100644 index b519252..0000000 --- a/test/unit/parsers/xslt_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class Ohcount::XsltTest < Ohcount::Test - def test_comment - lb = [Ohcount::LanguageBreakdown.new("xslt", "", "", 0)] - assert_equal lb, Ohcount::parse(" ", "xslt") - end - - def test_comprehensive - verify_parse("example.xsl") - end - - def test_comment_entities - assert_equal('', entities_array(" ", 'xslt', :comment).first) - end -end diff --git a/test/unit/source_file_list_test.rb b/test/unit/source_file_list_test.rb deleted file mode 100644 index 0abe691..0000000 --- a/test/unit/source_file_list_test.rb +++ /dev/null @@ -1,26 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' -include Ohcount - -class SourceFileListTest < Ohcount::Test - - def test_language_facts - sfl = SourceFileList.new(:path => test_dir('win32_enough')) - sfl.analyze(:language) - assert_equal 2, sfl.loc_list.filecount - assert_equal 2, sfl.loc_list.c.code - assert_equal 2, sfl.loc_list.c.comments - assert_equal 2, sfl.loc_list.c.blanks - end - - protected - - def license_file(f) - File.expand_path(File.dirname(__FILE__) + "/../src_licenses/#{ f }") - end - - def test_dir(d) - File.expand_path(File.dirname(__FILE__) + "/../gestalt_files/#{ d }") - end - -end - diff --git a/test/unit/source_file_test.rb b/test/unit/source_file_test.rb deleted file mode 100644 index c93e957..0000000 --- a/test/unit/source_file_test.rb +++ /dev/null @@ -1,123 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' -include Ohcount - -class SourceFileTest < Ohcount::Test - - def test_initialize - assert SourceFile.new("foo.rb") - end - - def test_contents - contents = "foobar" - f = SourceFile.new("foo.rb", :contents => contents) - assert_equal contents, f.contents - end - - def test_language_breakdowns - contents = "x = 5" - f = SourceFile.new("foo.rb", :contents => contents) - assert_equal 'ruby', f.language_breakdowns[0].name - assert_equal contents, f.language_breakdown('ruby').code - end - - def test_parse - ruby_code = '' - contents = "x = 5" - f = SourceFile.new("foo.rb", :contents => contents) - f.parse do |l, s, line| - ruby_code << line if l == :ruby && s == :code - end - assert_equal contents, ruby_code - end - - def test_realize_file - s = SourceFile.new('foo.c', :contents => 'i') - s.realize_file do |f| - assert_equal 'i', File.new(f).read - end - end - - def test_diff - old = SourceFile.new("foo.c", :contents => 'int i;') - new = SourceFile.new("foo.c", :contents => 'int j;') - - delta = LocDelta.new('c', :code_added => 1, :code_removed => 1) - assert_equal delta, old.calc_loc_delta('c', new) - assert_equal LocDeltaList.new([delta]), old.diff(new) - end - - def test_calc_diff_2 - old = SourceFile.new("foo.html", :contents => <<-INLINE_HTML - - - - - INLINE_HTML - ) - new = SourceFile.new("foo.html", :contents => <<-INLINE_HTML - - - - - INLINE_HTML - ) - loc_delta_list = old.diff(new) - assert_equal ['css', 'javascript'], loc_delta_list.languages - assert_equal LocDelta.new('css', :comments_added => 1, :comments_removed => 1), loc_delta_list.loc_delta('css') - assert_equal LocDelta.new('javascript', :code_added => 1, :code_removed => 1), loc_delta_list.loc_delta('javascript') - end - - def test_calc_diff_longer - old = SourceFile.new("foo.c", :contents => <<-INLINE_C - int = 1; - int = 2; - int = 3; - int = 4; - INLINE_C - ) - new = SourceFile.new("foo.c", :contents => <<-INLINE_C - int = 1; - int = 5; - int = 6; - int = 4; - INLINE_C - ) - assert_equal LocDelta.new('c', :code_added => 2, :code_removed => 2), old.diff(new).loc_delta('c') - end - - def test_calc_small_diff - assert_equal [0,0], SourceFile.new.calc_small_diff("","") - assert_equal [0,0], SourceFile.new.calc_small_diff("a","a") - assert_equal [0,0], SourceFile.new.calc_small_diff("a\n","a\n") - assert_equal [1,0], SourceFile.new.calc_small_diff("","a\n") - assert_equal [0,1], SourceFile.new.calc_small_diff("a\n","") - assert_equal [1,1], SourceFile.new.calc_small_diff("a\n","b\n") - assert_equal [1,1], SourceFile.new.calc_small_diff("a\nb\nc\n","a\nc\nd\n") - end - - def test_calc_large_diff - assert_equal [0,0], SourceFile.new.calc_large_diff("","") - assert_equal [0,0], SourceFile.new.calc_large_diff("a","a") - assert_equal [0,0], SourceFile.new.calc_large_diff("a\n","a\n") - assert_equal [1,0], SourceFile.new.calc_large_diff("","a\n") - assert_equal [0,1], SourceFile.new.calc_large_diff("a\n","") - assert_equal [1,1], SourceFile.new.calc_large_diff("a\n","b\n") - assert_equal [1,1], SourceFile.new.calc_large_diff("a\nb\nc\n","a\nc\nd\n") - end - - def test_calc_diff - assert_equal [1,0], SourceFile.new.calc_diff("Hello, World!\n" * 10, "Hello, World!\n" * 11) - assert_equal [1,0], SourceFile.new.calc_diff("Hello, World!\n" * 10000, "Hello, World!\n" * 10001) - end - -end diff --git a/vendor/gems/diff-lcs-1.1.2/ChangeLog b/vendor/gems/diff-lcs-1.1.2/ChangeLog deleted file mode 100644 index 08d3ee5..0000000 --- a/vendor/gems/diff-lcs-1.1.2/ChangeLog +++ /dev/null @@ -1,46 +0,0 @@ -Revision history for Ruby library Diff::LCS. Unless explicitly noted otherwise, -all changes are produced by Austin Ziegler . - -== Diff::LCS 1.1.2 -* Fixed a problem reported by Mauricio Fernandez in htmldiff. Future versions - of Diff::LCS will be removing this program. - -== Diff::LCS 1.1.1 -* Fixed bug #891: - http://rubyforge.org/tracker/?func=detail&atid=407&aid=891&group_id=84 -* Fixed a problem with callback initialisation code (it assumed that all - callbacks passed as classes can be initialised; now, it rescues - NoMethodError in the event of private :new being called). -* Modified the non-initialisable callbacks to have a private #new method. -* Moved ldiff core code to Diff::LCS::Ldiff (diff/lcs/ldiff.rb). - -== Diff::LCS 1.1.0 -* Eliminated the need for Diff::LCS::Event and removed it. -* Added a contextual diff callback, Diff::LCS::ContextDiffCallback. -* Implemented patching/unpatching for standard Diff callback output formats - with both #diff and #sdiff. -* Extensive documentation changes. - -== Diff::LCS 1.0.4 -* Fixed a problem with bin/ldiff output, especially for unified format. - Newlines that should have been present weren't. -* Changed the .tar.gz installer to generate Windows batch files if ones do not - exist already. Removed the existing batch files as they didn't work. - -== Diff::LCS 1.0.3 -* Fixed a problem with #traverse_sequences where the first difference from the - left sequence might not be appropriately captured. - -== Diff::LCS 1.0.2 -* Fixed an issue with ldiff not working because actions were changed from - symbols to strings. - -== Diff::LCS 1.0.1 -* Minor modifications to the gemspec, the README. -* Renamed the diff program to ldiff (as well as the companion batch file) so as - to not collide with the standard diff program. -* Fixed issues with RubyGEMs. Requires RubyGems > 0.6.1 or >= 0.6.1 with the - latest CVS version. - -== Diff::LCS 1.0 -* Initial release based mostly on Perl's Algorithm::Diff. diff --git a/vendor/gems/diff-lcs-1.1.2/Install b/vendor/gems/diff-lcs-1.1.2/Install deleted file mode 100644 index 794796e..0000000 --- a/vendor/gems/diff-lcs-1.1.2/Install +++ /dev/null @@ -1,6 +0,0 @@ -Installing this package is as simple as: - -% ruby install.rb - -Alternatively, you can use the RubyGem version of Diff::LCS available as -diff-lcs-1.1.2.gem from the usual sources. diff --git a/vendor/gems/diff-lcs-1.1.2/README b/vendor/gems/diff-lcs-1.1.2/README deleted file mode 100644 index 5056466..0000000 --- a/vendor/gems/diff-lcs-1.1.2/README +++ /dev/null @@ -1,76 +0,0 @@ -Diff::LCS README -================ -Diff::LCS is a port of Algorithm::Diff[1] that uses the McIlroy-Hunt -longest common subsequence (LCS) algorithm to compute intelligent -differences between two sequenced enumerable containers[2]. The -implementation is based on Mario I. Wolczko's[3] Smalltalk version (1.2, -1993)[4] and Ned Konz's[5] Perl version (Algorithm::Diff)[6]. - -This release is version 1.1.2, fixing an htmldiff bug in 1.1.1. Version 1.1.0 -added new features, including the ability to #patch and #unpatch changes as -well as a new contextual diff callback, Diff::LCS::ContextDiffCallbacks, that -should improve the context sensitivity of patching. - -Using this module is quite simple. By default, Diff::LCS does not extend -objects with the Diff::LCS interface, but will be called as if it were a -function: - - require 'diff/lcs' - - seq1 = %w(a b c e h j l m n p) - seq2 = %w(b c d e f j k l m r s t) - - lcs = Diff::LCS.LCS(seq1, seq2) - diffs = Diff::LCS.diff(seq1, seq2) - sdiff = Diff::LCS.sdiff(seq1, seq2) - seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - seq2 == Diff::LCS.patch!(seq1, diffs) - seq1 == Diff::LCS.unpatch!(seq2, diffs) - seq2 == Diff::LCS.patch!(seq1, sdiff) - seq1 == Diff::LCS.unpatch!(seq2, sdiff) - -Objects can be extended with Diff::LCS: - - seq1.extend(Diff::LCS) - lcs = seq1.lcs(seq2) - diffs = seq1.diff(seq2) - sdiff = seq1.sdiff(seq2) - seq = seq1.traverse_sequences(seq2, callback_obj) - bal = seq1.traverse_balanced(seq2, callback_obj) - seq2 == seq1.patch!(diffs) - seq1 == seq2.unpatch!(diffs) - seq2 == seq1.patch!(sdiff) - seq1 == seq2.unpatch!(sdiff) - -By requiring 'diff/lcs/array' or 'diff/lcs/string', Array or String will -be extended for use this way. - -Copyright -========= -# Copyright 2004 Austin Ziegler -# adapted from: -# Algorithm::Diff (Perl) by Ned Konz -# Smalltalk by Mario I. Wolczko -# implements McIlroy-Hunt diff algorithm -# -# This program is free software. It may be redistributed and/or modified -# under the terms of the GPL version 2 (or later), the Perl Artistic -# licence, or the Ruby licence. -# -# $Id: README,v 1.7 2004/10/17 20:31:10 austin Exp $ - -Footnotes -========= -[1] This library is called Diff::LCS because there are multiple - Ruby libraries called Algorithm::Diff maintained by other authors. -[2] By sequenced enumerable, I mean that the order of enumeration is - predictable and consistent for the same set of data. While it is - theoretically possible to generate a diff for unordereded hash, it - will only be meaningful if the enumeration of the hashes is - consistent. In general, this will mean that containers that behave - like String or Array will perform best. -[3] mario@wolczko.com -[4] ftp://st.cs.uiuc.edu/pub/Smalltalk/MANCHESTER/manchester/4.0/diff.st -[5] perl@bike-nomad.com -[6] http://search.cpan.org/~nedkonz/Algorithm-Diff-1.15/ diff --git a/vendor/gems/diff-lcs-1.1.2/Rakefile b/vendor/gems/diff-lcs-1.1.2/Rakefile deleted file mode 100644 index 774d435..0000000 --- a/vendor/gems/diff-lcs-1.1.2/Rakefile +++ /dev/null @@ -1,116 +0,0 @@ -#! /usr/bin/env rake -$LOAD_PATH.unshift('lib') - -require 'rubygems' -require 'rake/gempackagetask' -require 'rake/contrib/rubyforgepublisher' -require 'diff/lcs' -require 'archive/tar/minitar' -require 'zlib' - -DISTDIR = "diff-lcs-#{Diff::LCS::VERSION}" -TARDIST = "../#{DISTDIR}.tar.gz" - -DATE_RE = %r<(\d{4})[./-]?(\d{2})[./-]?(\d{2})(?:[\sT]?(\d{2})[:.]?(\d{2})[:.]?(\d{2})?)?> - -if ENV['RELEASE_DATE'] - year, month, day, hour, minute, second = DATE_RE.match(ENV['RELEASE_DATE']).captures - year ||= 0 - month ||= 0 - day ||= 0 - hour ||= 0 - minute ||= 0 - second ||= 0 - ReleaseDate = Time.mktime(year, month, day, hour, minute, second) -else - ReleaseDate = nil -end - -task :test do |t| - require 'test/unit/testsuite' - require 'test/unit/ui/console/testrunner' - - runner = Test::Unit::UI::Console::TestRunner - - $LOAD_PATH.unshift('tests') - $stderr.puts "Checking for test cases:" if t.verbose - Dir['tests/*test*.rb'].each do |testcase| - $stderr.puts "\t#{testcase}" if t.verbose - load testcase - end - - suite = Test::Unit::TestSuite.new - - ObjectSpace.each_object(Class) do |testcase| - suite << testcase.suite if testcase < Test::Unit::TestCase - end - - runner.run(suite) -end - -spec = eval(File.read("diff-lcs.gemspec")) -desc "Build the RubyGem for Diff::LCS." -task :gem => [ :test ] -Rake::GemPackageTask.new(spec) do |g| - g.need_tar = false - g.need_zip = false - g.package_dir = ".." -end - -desc "Build an Diff::LCS .tar.gz distribution." -task :tar => [ TARDIST ] -file TARDIST => [ :test ] do |t| - current = File.basename(Dir.pwd) - Dir.chdir("..") do - begin - files = Dir["#{current}/**/*"].select { |dd| dd !~ %r{(?:/CVS/?|~$)} } - files.map! do |dd| - ddnew = dd.gsub(/^#{current}/, DISTDIR) - mtime = ReleaseDate || File.stat(dd).mtime - if File.directory?(dd) - { :name => ddnew, :mode => 0755, :dir => true, :mtime => mtime } - else - if dd =~ %r{bin/} - mode = 0755 - else - mode = 0644 - end - data = File.read(dd) - { :name => ddnew, :mode => mode, :data => data, :size => data.size, - :mtime => mtime } - end - end - - ff = File.open(t.name.gsub(%r{^\.\./}o, ''), "wb") - gz = Zlib::GzipWriter.new(ff) - tw = Archive::Tar::Minitar::Writer.new(gz) - - files.each do |entry| - if entry[:dir] - tw.mkdir(entry[:name], entry) - else - tw.add_file_simple(entry[:name], entry) { |os| os.write(entry[:data]) } - end - end - ensure - tw.close if tw - gz.close if gz - end - end -end -task TARDIST => [ :test ] - -def sign(file) - sh %("C:\\Program Files\\Windows Privacy Tools\\GnuPG\\Gpg.exe" -ba #{file}) rescue nil -end - -task :signtar => [ :tar ] do - sign TARDIST -end -task :signgem => [ :gem ] do - sign "../#{DISTDIR}.gem" -end - -desc "Build everything." -task :default => [ :signtar, :signgem ] do -end diff --git a/vendor/gems/diff-lcs-1.1.2/bin/htmldiff b/vendor/gems/diff-lcs-1.1.2/bin/htmldiff deleted file mode 100755 index 3d4953f..0000000 --- a/vendor/gems/diff-lcs-1.1.2/bin/htmldiff +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env ruby -#-- -# Copyright 2004 Austin Ziegler -# adapted from: -# Algorithm::Diff (Perl) by Ned Konz -# Smalltalk by Mario I. Wolczko -# implements McIlroy-Hunt diff algorithm -# -# This program is free software. It may be redistributed and/or modified under -# the terms of the GPL version 2 (or later), the Perl Artistic licence, or the -# Ruby licence. -# -# $Id: htmldiff,v 1.6 2004/10/17 19:33:21 austin Exp $ -#++ - -begin - require 'rubygems' - require_gem 'diff-lcs', "1.1.1" - require 'diff/lcs/string' -rescue LoadError - require 'diff/lcs' - require 'diff/lcs/string' -end - -require 'text/format' - -class HTMLDiff #:nodoc: - attr_accessor :output - - def initialize(output) - @output = output - end - - # This will be called with both lines are the same - def match(event) - @output << %Q|
#{event.old_element}
\n| - end - - # This will be called when there is a line in A that isn't in B - def discard_a(event) - @output << %Q|
#{event.old_element}
\n| - end - - # This will be called when there is a line in B that isn't in A - def discard_b(event) - @output << %Q|
#{event.new_element}
\n| - end -end - -if ARGV.size != 2 - puts "usage: #{File.basename($0)} old new > output.html" - exit 255 -end - -hd = HTMLDiff.new($stdout) -tf = Text::Format.new -tf.tabstop = 4 - -preprocess = lambda { |line| tf.expand(line.chomp) } - -a = IO.readlines(ARGV[0]).map(&preprocess) -b = IO.readlines(ARGV[1]).map(&preprocess) - -$stdout.write <<-START - - - diff #{ARGV[0]} #{ARGV[1]} - - - -

diff  - #{ARGV[0]}  - #{ARGV[1]} -

-
-START - -Diff::LCS.traverse_sequences(a, b, hd) - -$stdout.write <<-END -
- - -END diff --git a/vendor/gems/diff-lcs-1.1.2/bin/ldiff b/vendor/gems/diff-lcs-1.1.2/bin/ldiff deleted file mode 100755 index 4437ba5..0000000 --- a/vendor/gems/diff-lcs-1.1.2/bin/ldiff +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env ruby -#-- -# Copyright 2004 Austin Ziegler -# adapted from: -# Algorithm::Diff (Perl) by Ned Konz -# Smalltalk by Mario I. Wolczko -# implements McIlroy-Hunt diff algorithm -# -# This program is free software. It may be redistributed and/or modified under -# the terms of the GPL version 2 (or later), the Perl Artistic licence, or the -# Ruby licence. -# -# $Id: ldiff,v 1.6 2004/09/26 01:35:57 austin Exp $ -#++ - - # 1) Try to load Ruwiki from the gem. - # 2) Try to load Ruwiki from $LOAD_PATH. - # 3) Modify $LOAD_PATH and try to load it from the modified $LOAD_PATH. - # 4) Fail hard. -load_state = 1 - begin - if 1 == load_state - require 'rubygems' - require_gem 'diff-lcs', '= 1.1.1' - else - require 'diff/lcs' - end - rescue LoadError - load_state += 1 - - case load_state - when 3 - $LOAD_PATH.unshift "#{File.dirname($0)}/../lib" - when 4 - $LOAD_PATH.shift - $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib" - when 5 - raise - end - retry - end - -require 'diff/lcs/ldiff' - -exit Diff::LCS::Ldiff.run(ARGV) diff --git a/vendor/gems/diff-lcs-1.1.2/diff-lcs.gemspec b/vendor/gems/diff-lcs-1.1.2/diff-lcs.gemspec deleted file mode 100644 index ba49ed6..0000000 --- a/vendor/gems/diff-lcs-1.1.2/diff-lcs.gemspec +++ /dev/null @@ -1,40 +0,0 @@ -Gem::Specification.new do |s| - s.name = %{diff-lcs} - s.version = %{1.1.2} - s.author = %{Austin Ziegler} - s.email = %{diff-lcs@halostatue.ca} - s.homepage = %{http://rubyforge.org/projects/ruwiki/} - s.rubyforge_project = %{ruwiki} - - s.files = Dir.glob("**/*").delete_if do |item| - item.include?("CVS") or item.include?(".svn") or - item == "install.rb" or item =~ /~$/ or - item =~ /gem(?:spec)?$/ - end - - s.summary = %{Provides a list of changes that represent the difference between two sequenced collections.} - - s.required_ruby_version = %(>=1.8.1) - - s.executables = %w(ldiff htmldiff) - s.bindir = %(bin) - - s.test_files = %w{tests/00test.rb} - - s.autorequire = %{diff/lcs} - s.require_paths = %w{lib} - - description = [] - File.open("README") do |file| - file.each do |line| - line.chomp! - break if line.empty? - description << "#{line.gsub(/\[\d\]/, '')}" - end - end - s.description = description[2..-1].join(" ") - - s.has_rdoc = true - s.rdoc_options = ["--title", "Diff::LCS -- A Diff Algorithm", "--main", "README", "--line-numbers"] - s.extra_rdoc_files = %w(README ChangeLog Install) -end diff --git a/vendor/gems/diff-lcs-1.1.2/install.rb b/vendor/gems/diff-lcs-1.1.2/install.rb deleted file mode 100644 index afa6cb2..0000000 --- a/vendor/gems/diff-lcs-1.1.2/install.rb +++ /dev/null @@ -1,262 +0,0 @@ -#! /usr/bin/env ruby -#-- -# Copyright 2004 Austin Ziegler -# Install utility. Based on the original installation script for rdoc by the -# Pragmatic Programmers. -# -# This program is free software. It may be redistributed and/or modified under -# the terms of the GPL version 2 (or later) or the Ruby licence. -# -# Usage -# ----- -# In most cases, if you have a typical project layout, you will need to do -# absolutely nothing to make this work for you. This layout is: -# -# bin/ # executable files -- "commands" -# lib/ # the source of the library -# tests/ # unit tests -# -# The default behaviour: -# 1) Run all unit test files (ending in .rb) found in all directories under -# tests/. -# 2) Build Rdoc documentation from all files in bin/ (excluding .bat and .cmd), -# all .rb files in lib/, ./README, ./ChangeLog, and ./Install. -# 3) Build ri documentation from all files in bin/ (excluding .bat and .cmd), -# and all .rb files in lib/. This is disabled by default on Win32. -# 4) Install commands from bin/ into the Ruby bin directory. On Windows, if a -# if a corresponding batch file (.bat or .cmd) exists in the bin directory, -# it will be copied over as well. Otherwise, a batch file (always .bat) will -# be created to run the specified command. -# 5) Install all library files ending in .rb from lib/ into Ruby's -# site_lib/version directory. -# -# $Id: install.rb,v 1.9 2004/09/22 16:13:15 austin Exp $ -#++ - -require 'rbconfig' -require 'find' -require 'fileutils' -require 'rdoc/rdoc' -require 'optparse' -require 'ostruct' - -InstallOptions = OpenStruct.new - -def glob(list) - g = list.map { |i| Dir.glob(i) } - g.flatten! - g.compact! - g.reject! { |e| e =~ /CVS/ } - g -end - - # Set these values to what you want installed. -bins = glob(%w{bin/**/*}).reject { |e| e =~ /\.(bat|cmd)$/ } -rdoc = glob(%w{bin/**/* lib/**/*.rb README ChangeLog Install}).reject { |e| e=~ /\.(bat|cmd)$/ } -ri = glob(%w(bin/**/*.rb lib/**/*.rb)).reject { |e| e=~ /\.(bat|cmd)$/ } -libs = glob(%w{lib/**/*.rb}) -tests = glob(%w{tests/**/*.rb}) - -def do_bins(bins, target, strip = 'bin/') - bins.each do |bf| - obf = bf.gsub(/#{strip}/, '') - install_binfile(bf, obf, target) - end -end - -def do_libs(libs, strip = 'lib/') - libs.each do |lf| - olf = File.join(InstallOptions.site_dir, lf.gsub(/#{strip}/, '')) - op = File.dirname(olf) - File.makedirs(op, true) - File.chmod(0755, op) - File.install(lf, olf, 0755, true) - end -end - -## -# Prepare the file installation. -# -def prepare_installation - InstallOptions.rdoc = true - if RUBY_PLATFORM == "i386-mswin32" - InstallOptions.ri = false - else - InstallOptions.ri = true - end - InstallOptions.tests = true - - ARGV.options do |opts| - opts.banner = "Usage: #{File.basename($0)} [options]" - opts.separator "" - opts.on('--[no-]rdoc', 'Prevents the creation of RDoc output.', 'Default on.') do |onrdoc| - InstallOptions.rdoc = onrdoc - end - opts.on('--[no-]ri', 'Prevents the creation of RI output.', 'Default off on mswin32.') do |onri| - InstallOptions.ri = onri - end - opts.on('--[no-]tests', 'Prevents the execution of unit tests.', 'Default on.') do |ontest| - InstallOptions.tests = ontest - end - opts.on('--quick', 'Performs a quick installation. Only the', 'installation is done.') do |quick| - InstallOptions.rdoc = false - InstallOptions.ri = false - InstallOptions.tests = false - end - opts.on('--full', 'Performs a full installation. All', 'optional installation steps are run.') do |full| - InstallOptions.rdoc = true - InstallOptions.ri = true - InstallOptions.tests = true - end - opts.separator("") - opts.on_tail('--help', "Shows this help text.") do - $stderr.puts opts - exit - end - - opts.parse! - end - - bds = [".", ENV['TMP'], ENV['TEMP']] - - version = [Config::CONFIG["MAJOR"], Config::CONFIG["MINOR"]].join(".") - ld = File.join(Config::CONFIG["libdir"], "ruby", version) - - sd = Config::CONFIG["sitelibdir"] - if sd.nil? - sd = $:.find { |x| x =~ /site_ruby/ } - if sd.nil? - sd = File.join(ld, "site_ruby") - elsif sd !~ Regexp.quote(version) - sd = File.join(sd, version) - end - end - - if (destdir = ENV['DESTDIR']) - bd = "#{destdir}#{Config::CONFIG['bindir']}" - sd = "#{destdir}#{sd}" - bds << bd - - FileUtils.makedirs(bd) - FileUtils.makedirs(sd) - else - bds << Config::CONFIG['bindir'] - end - - InstallOptions.bin_dirs = bds.compact - InstallOptions.site_dir = sd - InstallOptions.bin_dir = bd - InstallOptions.lib_dir = ld -end - -## -# Build the rdoc documentation. Also, try to build the RI documentation. -# -def build_rdoc(files) - r = RDoc::RDoc.new - r.document(["--main", "README", "--title", "Diff::LCS -- A Diff Algorithm", - "--line-numbers"] + files) - -rescue RDoc::RDocError => e - $stderr.puts e.message -rescue Exception => e - $stderr.puts "Couldn't build RDoc documentation\n#{e.message}" -end - -def build_ri(files) - ri = RDoc::RDoc.new - ri.document(["--ri-site", "--merge"] + files) -rescue RDoc::RDocError => e - $stderr.puts e.message -rescue Exception => e - $stderr.puts "Couldn't build Ri documentation\n#{e.message}" -end - -def run_tests(test_list) - require 'test/unit/ui/console/testrunner' - $:.unshift "lib" - test_list.each do |test| - next if File.directory?(test) - require test - end - - tests = Test::Unit::TestSuite.new - ObjectSpace.each_object(Class) { |o| tests << o.suite if o < Test::Unit::TestCase } - - Test::Unit::UI::Console::TestRunner.run(tests) - $:.shift -end - -## -# Install file(s) from ./bin to Config::CONFIG['bindir']. Patch it on the way -# to insert a #! line; on a Unix install, the command is named as expected -# (e.g., bin/rdoc becomes rdoc); the shebang line handles running it. Under -# windows, we add an '.rb' extension and let file associations do their stuff. -def install_binfile(from, op_file, target) - tmp_dir = nil - InstallOptions.bin_dirs.each do |t| - if File.directory?(t) and File.writable?(t) - tmp_dir = t - break - end - end - - fail "Cannot find a temporary directory" unless tmp_dir - tmp_file = File.join(tmp_dir, '_tmp') - ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - - File.open(from) do |ip| - File.open(tmp_file, "w") do |op| - ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) - op.puts "#!#{ruby}" - op.write ip.read - end - end - - if Config::CONFIG["target_os"] =~ /win/io - installed_wrapper = false - - if File.exists?("#{from}.bat") - FileUtils.install("#{from}.bat", File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) - installed_wrapper = true - end - - if File.exists?("#{from}.cmd") - FileUtils.install("#{from}.cmd", File.join(target, "#{op_file}.cmd"), :mode => 0755, :verbose => true) - installed_wrapper = true - end - - if not installed_wrapper - tmp_file2 = File.join(tmp_dir, '_tmp_wrapper') - cwn = File.join(Config::CONFIG['bindir'], op_file) - cwv = CMD_WRAPPER.gsub('', ruby.gsub(%r{/}) { "\\" }).gsub!('', cwn.gsub(%r{/}) { "\\" } ) - - File.open(tmp_file2, "wb") { |cw| cw.puts cwv } - FileUtils.install(tmp_file2, File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) - - File.unlink(tmp_file2) - installed_wrapper = true - end - end - FileUtils.install(tmp_file, File.join(target, op_file), :mode => 0755, :verbose => true) - File.unlink(tmp_file) -end - -CMD_WRAPPER = <<-EOS -@echo off -if "%OS%"=="Windows_NT" goto WinNT - -x "" %1 %2 %3 %4 %5 %6 %7 %8 %9 -goto done -:WinNT - -x "" %* -goto done -:done -EOS - -prepare_installation - -run_tests(tests) if InstallOptions.tests -build_rdoc(rdoc) if InstallOptions.rdoc -build_ri(ri) if InstallOptions.ri -do_bins(bins, Config::CONFIG['bindir']) -do_libs(libs) diff --git a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs.rb b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs.rb deleted file mode 100644 index 92c22f1..0000000 --- a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs.rb +++ /dev/null @@ -1,1106 +0,0 @@ -#! /usr/env/bin ruby -#-- -# Copyright 2004 Austin Ziegler -# adapted from: -# Algorithm::Diff (Perl) by Ned Konz -# Smalltalk by Mario I. Wolczko -# implements McIlroy-Hunt diff algorithm -# -# This program is free software. It may be redistributed and/or modified -# under the terms of the GPL version 2 (or later), the Perl Artistic -# licence, or the Ruby licence. -# -# $Id: lcs.rb,v 1.9 2004/10/17 20:31:10 austin Exp $ -#++ -module LCSDiff - module Diff - # = Diff::LCS 1.1.2 - # Computes "intelligent" differences between two sequenced Enumerables. - # This is an implementation of the McIlroy-Hunt "diff" algorithm for - # Enumerable objects that include Diffable. - # - # Based on Mario I. Wolczko's Smalltalk version - # (1.2, 1993) and Ned Konz's Perl version - # (Algorithm::Diff). - # - # == Synopsis - # require 'diff/lcs' - # - # seq1 = %w(a b c e h j l m n p) - # seq2 = %w(b c d e f j k l m r s t) - # - # lcs = Diff::LCS.LCS(seq1, seq2) - # diffs = Diff::LCS.diff(seq1, seq2) - # sdiff = Diff::LCS.sdiff(seq1, seq2) - # seq = Diff::LCS.traverse_sequences(seq1, seq2, callback_obj) - # bal = Diff::LCS.traverse_balanced(seq1, seq2, callback_obj) - # seq2 == Diff::LCS.patch(seq1, diffs) - # seq2 == Diff::LCS.patch!(seq1, diffs) - # seq1 == Diff::LCS.unpatch(seq2, diffs) - # seq1 == Diff::LCS.unpatch!(seq2, diffs) - # seq2 == Diff::LCS.patch(seq1, sdiff) - # seq2 == Diff::LCS.patch!(seq1, sdiff) - # seq1 == Diff::LCS.unpatch(seq2, sdiff) - # seq1 == Diff::LCS.unpatch!(seq2, sdiff) - # - # Alternatively, objects can be extended with Diff::LCS: - # - # seq1.extend(Diff::LCS) - # lcs = seq1.lcs(seq2) - # diffs = seq1.diff(seq2) - # sdiff = seq1.sdiff(seq2) - # seq = seq1.traverse_sequences(seq2, callback_obj) - # bal = seq1.traverse_balanced(seq2, callback_obj) - # seq2 == seq1.patch(diffs) - # seq2 == seq1.patch!(diffs) - # seq1 == seq2.unpatch(diffs) - # seq1 == seq2.unpatch!(diffs) - # seq2 == seq1.patch(sdiff) - # seq2 == seq1.patch!(sdiff) - # seq1 == seq2.unpatch(sdiff) - # seq1 == seq2.unpatch!(sdiff) - # - # Default extensions are provided for Array and String objects through - # the use of 'diff/lcs/array' and 'diff/lcs/string'. - # - # == Introduction (by Mark-Jason Dominus) - # - # The following text is from the Perl documentation. The only - # changes have been to make the text appear better in Rdoc. - # - # I once read an article written by the authors of +diff+; they said - # that they hard worked very hard on the algorithm until they found the - # right one. - # - # I think what they ended up using (and I hope someone will correct me, - # because I am not very confident about this) was the `longest common - # subsequence' method. In the LCS problem, you have two sequences of - # items: - # - # a b c d f g h j q z - # a b c d e f g i j k r x y z - # - # and you want to find the longest sequence of items that is present in - # both original sequences in the same order. That is, you want to find a - # new sequence *S* which can be obtained from the first sequence by - # deleting some items, and from the second sequence by deleting other - # items. You also want *S* to be as long as possible. In this case *S* - # is: - # - # a b c d f g j z - # - # From there it's only a small step to get diff-like output: - # - # e h i k q r x y - # + - + + - + + + - # - # This module solves the LCS problem. It also includes a canned function - # to generate +diff+-like output. - # - # It might seem from the example above that the LCS of two sequences is - # always pretty obvious, but that's not always the case, especially when - # the two sequences have many repeated elements. For example, consider - # - # a x b y c z p d q - # a b c a x b y c z - # - # A naive approach might start by matching up the +a+ and +b+ that - # appear at the beginning of each sequence, like this: - # - # a x b y c z p d q - # a b c a b y c z - # - # This finds the common subsequence +a b c z+. But actually, the LCS is - # +a x b y c z+: - # - # a x b y c z p d q - # a b c a x b y c z - # - # == Author - # This version is by Austin Ziegler . - # - # It is based on the Perl Algorithm::Diff by Ned Konz - # , copyright © 2000 - 2002 and the Smalltalk - # diff version by Mario I. Wolczko , copyright © - # 1993. Documentation includes work by Mark-Jason Dominus. - # - # == Licence - # Copyright © 2004 Austin Ziegler - # This program is free software; you can redistribute it and/or modify it - # under the same terms as Ruby, or alternatively under the Perl Artistic - # licence. - # - # == Credits - # Much of the documentation is taken directly from the Perl - # Algorithm::Diff implementation and was written originally by Mark-Jason - # Dominus and later by Ned Konz. The basic Ruby - # implementation was re-ported from the Smalltalk implementation, available - # at ftp://st.cs.uiuc.edu/pub/Smalltalk/MANCHESTER/manchester/4.0/diff.st - # - # #sdiff and #traverse_balanced were written for the Perl version by Mike - # Schilli . - # - # "The algorithm is described in A Fast Algorithm for Computing Longest - # Common Subsequences, CACM, vol.20, no.5, pp.350-353, May 1977, with - # a few minor improvements to improve the speed." - module LCS - VERSION = '1.1.2' - end - end - - require 'diff/lcs/callbacks' - - module Diff::LCS - # Returns an Array containing the longest common subsequence(s) between - # +self+ and +other+. See Diff::LCS#LCS. - # - # lcs = seq1.lcs(seq2) - def lcs(other, &block) #:yields self[ii] if there are matched subsequences: - Diff::LCS.LCS(self, other, &block) - end - - # Returns the difference set between +self+ and +other+. See - # Diff::LCS#diff. - def diff(other, callbacks = nil, &block) - Diff::LCS::diff(self, other, callbacks, &block) - end - - # Returns the balanced ("side-by-side") difference set between +self+ and - # +other+. See Diff::LCS#sdiff. - def sdiff(other, callbacks = nil, &block) - Diff::LCS::sdiff(self, other, callbacks, &block) - end - - # Traverses the discovered longest common subsequences between +self+ and - # +other+. See Diff::LCS#traverse_sequences. - def traverse_sequences(other, callbacks = nil, &block) - traverse_sequences(self, other, callbacks || Diff::LCS::YieldingCallbacks, - &block) - end - - # Traverses the discovered longest common subsequences between +self+ and - # +other+ using the alternate, balanced algorithm. See - # Diff::LCS#traverse_balanced. - def traverse_balanced(other, callbacks = nil, &block) - traverse_balanced(self, other, callbacks || Diff::LCS::YieldingCallbacks, - &block) - end - - # Attempts to patch a copy of +self+ with the provided +patchset+. See - # Diff::LCS#patch. - def patch(patchset) - Diff::LCS::patch(self.dup, patchset) - end - - # Attempts to unpatch a copy of +self+ with the provided +patchset+. - # See Diff::LCS#patch. - def unpatch(patchset) - Diff::LCS::unpatch(self.dup, patchset) - end - - # Attempts to patch +self+ with the provided +patchset+. See - # Diff::LCS#patch!. Does no autodiscovery. - def patch!(patchset) - Diff::LCS::patch!(self, patchset) - end - - # Attempts to unpatch +self+ with the provided +patchset+. See - # Diff::LCS#unpatch. Does no autodiscovery. - def unpatch!(patchset) - Diff::LCS::unpatch!(self, patchset) - end - end - - module Diff::LCS - class << self - # Given two sequenced Enumerables, LCS returns an Array containing their - # longest common subsequences. - # - # lcs = Diff::LCS.LCS(seq1, seq2) - # - # This array whose contents is such that: - # - # lcs.each_with_index do |ee, ii| - # assert(ee.nil? || (seq1[ii] == seq2[ee])) - # end - # - # If a block is provided, the matching subsequences will be yielded from - # +seq1+ in turn and may be modified before they are placed into the - # returned Array of subsequences. - def LCS(seq1, seq2, &block) #:yields seq1[ii] for each matched: - matches = Diff::LCS.__lcs(seq1, seq2) - ret = [] - matches.each_with_index do |ee, ii| - unless matches[ii].nil? - if block_given? - ret << (yield seq1[ii]) - else - ret << seq1[ii] - end - end - end - ret - end - - # Diff::LCS.diff computes the smallest set of additions and deletions - # necessary to turn the first sequence into the second, and returns a - # description of these changes. - # - # See Diff::LCS::DiffCallbacks for the default behaviour. An alternate - # behaviour may be implemented with Diff::LCS::ContextDiffCallbacks. - # If a Class argument is provided for +callbacks+, #diff will attempt - # to initialise it. If the +callbacks+ object (possibly initialised) - # responds to #finish, it will be called. - def diff(seq1, seq2, callbacks = nil, &block) # :yields diff changes: - callbacks ||= Diff::LCS::DiffCallbacks - if callbacks.kind_of?(Class) - cb = callbacks.new rescue callbacks - callbacks = cb - end - traverse_sequences(seq1, seq2, callbacks) - callbacks.finish if callbacks.respond_to?(:finish) - - if block_given? - res = callbacks.diffs.map do |hunk| - if hunk.kind_of?(Array) - hunk = hunk.map { |block| yield block } - else - yield hunk - end - end - res - else - callbacks.diffs - end - end - - # Diff::LCS.sdiff computes all necessary components to show two sequences - # and their minimized differences side by side, just like the Unix - # utility sdiff does: - # - # old < - - # same same - # before | after - # - > new - # - # See Diff::LCS::SDiffCallbacks for the default behaviour. An alternate - # behaviour may be implemented with Diff::LCS::ContextDiffCallbacks. If - # a Class argument is provided for +callbacks+, #diff will attempt to - # initialise it. If the +callbacks+ object (possibly initialised) - # responds to #finish, it will be called. - def sdiff(seq1, seq2, callbacks = nil, &block) #:yields diff changes: - callbacks ||= Diff::LCS::SDiffCallbacks - if callbacks.kind_of?(Class) - cb = callbacks.new rescue callbacks - callbacks = cb - end - traverse_balanced(seq1, seq2, callbacks) - callbacks.finish if callbacks.respond_to?(:finish) - - if block_given? - res = callbacks.diffs.map do |hunk| - if hunk.kind_of?(Array) - hunk = hunk.map { |block| yield block } - else - yield hunk - end - end - res - else - callbacks.diffs - end - end - - # Diff::LCS.traverse_sequences is the most general facility provided by this - # module; +diff+ and +LCS+ are implemented as calls to it. - # - # The arguments to #traverse_sequences are the two sequences to - # traverse, and a callback object, like this: - # - # traverse_sequences(seq1, seq2, Diff::LCS::ContextDiffCallbacks.new) - # - # #diff is implemented with #traverse_sequences. - # - # == Callback Methods - # Optional callback methods are emphasized. - # - # callbacks#match:: Called when +a+ and +b+ are pointing - # to common elements in +A+ and +B+. - # callbacks#discard_a:: Called when +a+ is pointing to an - # element not in +B+. - # callbacks#discard_b:: Called when +b+ is pointing to an - # element not in +A+. - # callbacks#finished_a:: Called when +a+ has reached the end of - # sequence +A+. - # callbacks#finished_b:: Called when +b+ has reached the end of - # sequence +B+. - # - # == Algorithm - # a---+ - # v - # A = a b c e h j l m n p - # B = b c d e f j k l m r s t - # ^ - # b---+ - # - # If there are two arrows (+a+ and +b+) pointing to elements of - # sequences +A+ and +B+, the arrows will initially point to the first - # elements of their respective sequences. #traverse_sequences will - # advance the arrows through the sequences one element at a time, - # calling a method on the user-specified callback object before each - # advance. It will advance the arrows in such a way that if there are - # elements A[ii] and B[jj] which are both equal and - # part of the longest common subsequence, there will be some moment - # during the execution of #traverse_sequences when arrow +a+ is pointing - # to A[ii] and arrow +b+ is pointing to B[jj]. When - # this happens, #traverse_sequences will call callbacks#match - # and then it will advance both arrows. - # - # Otherwise, one of the arrows is pointing to an element of its sequence - # that is not part of the longest common subsequence. - # #traverse_sequences will advance that arrow and will call - # callbacks#discard_a or callbacks#discard_b, depending - # on which arrow it advanced. If both arrows point to elements that are - # not part of the longest common subsequence, then #traverse_sequences - # will advance one of them and call the appropriate callback, but it is - # not specified which it will call. - # - # The methods for callbacks#match, callbacks#discard_a, - # and callbacks#discard_b are invoked with an event comprising - # the action ("=", "+", or "-", respectively), the indicies +ii+ and - # +jj+, and the elements A[ii] and B[jj]. Return - # values are discarded by #traverse_sequences. - # - # === End of Sequences - # If arrow +a+ reaches the end of its sequence before arrow +b+ does, - # #traverse_sequence try to call callbacks#finished_a with the - # last index and element of +A+ (A[-1]) and the current index - # and element of +B+ (B[jj]). If callbacks#finished_a - # does not exist, then callbacks#discard_b will be called on - # each element of +B+ until the end of the sequence is reached (the call - # will be done with A[-1] and B[jj] for each element). - # - # If +b+ reaches the end of +B+ before +a+ reaches the end of +A+, - # callbacks#finished_b will be called with the current index - # and element of +A+ (A[ii]) and the last index and element of - # +B+ (A[-1]). Again, if callbacks#finished_b does not - # exist on the callback object, then callbacks#discard_a will - # be called on each element of +A+ until the end of the sequence is - # reached (A[ii] and B[-1]). - # - # There is a chance that one additional callbacks#discard_a or - # callbacks#discard_b will be called after the end of the - # sequence is reached, if +a+ has not yet reached the end of +A+ or +b+ - # has not yet reached the end of +B+. - def traverse_sequences(seq1, seq2, callbacks = Diff::LCS::SequenceCallbacks, &block) #:yields change events: - matches = Diff::LCS.__lcs(seq1, seq2) - - run_finished_a = run_finished_b = false - string = seq1.kind_of?(String) - - a_size = seq1.size - b_size = seq2.size - ai = bj = 0 - - (0 .. matches.size).each do |ii| - b_line = matches[ii] - - ax = string ? seq1[ii, 1] : seq1[ii] - bx = string ? seq2[bj, 1] : seq2[bj] - - if b_line.nil? - unless ax.nil? - event = Diff::LCS::ContextChange.new('-', ii, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - end - else - loop do - break unless bj < b_line - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('+', ii, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('=', ii, ax, bj, bx) - event = yield event if block_given? - callbacks.match(event) - bj += 1 - end - ai = ii - end - ai += 1 - - # The last entry (if any) processed was a match. +ai+ and +bj+ point - # just past the last matching lines in their sequences. - while (ai < a_size) or (bj < b_size) - # last A? - if ai == a_size and bj < b_size - if callbacks.respond_to?(:finished_a) and not run_finished_a - ax = string ? seq1[-1, 1] : seq1[-1] - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('>', (a_size - 1), ax, bj, bx) - event = yield event if block_given? - callbacks.finished_a(event) - run_finished_a = true - else - ax = string ? seq1[ai, 1] : seq1[ai] - loop do - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - break unless bj < b_size - end - end - end - - # last B? - if bj == b_size and ai < a_size - if callbacks.respond_to?(:finished_b) and not run_finished_b - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[-1, 1] : seq2[-1] - event = Diff::LCS::ContextChange.new('<', ai, ax, (b_size - 1), bx) - event = yield event if block_given? - callbacks.finished_b(event) - run_finished_b = true - else - bx = string ? seq2[bj, 1] : seq2[bj] - loop do - ax = string ? seq1[ai, 1] : seq1[ai] - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - break unless bj < b_size - end - end - end - - if ai < a_size - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - end - - if bj < b_size - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - end - end - - # #traverse_balanced is an alternative to #traverse_sequences. It - # uses a different algorithm to iterate through the entries in the - # computed longest common subsequence. Instead of viewing the changes as - # insertions or deletions from one of the sequences, #traverse_balanced - # will report changes between the sequences. To represent a - # - # The arguments to #traverse_balanced are the two sequences to traverse - # and a callback object, like this: - # - # traverse_balanced(seq1, seq2, Diff::LCS::ContextDiffCallbacks.new) - # - # #sdiff is implemented with #traverse_balanced. - # - # == Callback Methods - # Optional callback methods are emphasized. - # - # callbacks#match:: Called when +a+ and +b+ are pointing - # to common elements in +A+ and +B+. - # callbacks#discard_a:: Called when +a+ is pointing to an - # element not in +B+. - # callbacks#discard_b:: Called when +b+ is pointing to an - # element not in +A+. - # callbacks#change:: Called when +a+ and +b+ are pointing - # to the same relative position, but - # A[a] and B[b] are - # not the same; a change has - # occurred. - # - # #traverse_balanced might be a bit slower than #traverse_sequences, - # noticable only while processing huge amounts of data. - # - # The +sdiff+ function of this module is implemented as call to - # #traverse_balanced. - # - # == Algorithm - # a---+ - # v - # A = a b c e h j l m n p - # B = b c d e f j k l m r s t - # ^ - # b---+ - # - # === Matches - # If there are two arrows (+a+ and +b+) pointing to elements of - # sequences +A+ and +B+, the arrows will initially point to the first - # elements of their respective sequences. #traverse_sequences will - # advance the arrows through the sequences one element at a time, - # calling a method on the user-specified callback object before each - # advance. It will advance the arrows in such a way that if there are - # elements A[ii] and B[jj] which are both equal and - # part of the longest common subsequence, there will be some moment - # during the execution of #traverse_sequences when arrow +a+ is pointing - # to A[ii] and arrow +b+ is pointing to B[jj]. When - # this happens, #traverse_sequences will call callbacks#match - # and then it will advance both arrows. - # - # === Discards - # Otherwise, one of the arrows is pointing to an element of its sequence - # that is not part of the longest common subsequence. - # #traverse_sequences will advance that arrow and will call - # callbacks#discard_a or callbacks#discard_b, - # depending on which arrow it advanced. - # - # === Changes - # If both +a+ and +b+ point to elements that are not part of the longest - # common subsequence, then #traverse_sequences will try to call - # callbacks#change and advance both arrows. If - # callbacks#change is not implemented, then - # callbacks#discard_a and callbacks#discard_b will be - # called in turn. - # - # The methods for callbacks#match, callbacks#discard_a, - # callbacks#discard_b, and callbacks#change are - # invoked with an event comprising the action ("=", "+", "-", or "!", - # respectively), the indicies +ii+ and +jj+, and the elements - # A[ii] and B[jj]. Return values are discarded by - # #traverse_balanced. - # - # === Context - # Note that +ii+ and +jj+ may not be the same index position, even if - # +a+ and +b+ are considered to be pointing to matching or changed - # elements. - def traverse_balanced(seq1, seq2, callbacks = Diff::LCS::BalancedCallbacks) - matches = Diff::LCS.__lcs(seq1, seq2) - a_size = seq1.size - b_size = seq2.size - ai = bj = mb = 0 - ma = -1 - string = seq1.kind_of?(String) - - # Process all the lines in the match vector. - loop do - # Find next match indices +ma+ and +mb+ - loop do - ma += 1 - break unless ma < matches.size and matches[ma].nil? - end - - break if ma >= matches.size # end of matches? - mb = matches[ma] - - # Change(seq2) - while (ai < ma) or (bj < mb) - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[bj, 1] : seq2[bj] - - case [(ai < ma), (bj < mb)] - when [true, true] - if callbacks.respond_to?(:change) - event = Diff::LCS::ContextChange.new('!', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.change(event) - ai += 1 - bj += 1 - else - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - ax = string ? seq1[ai, 1] : seq1[ai] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - when [true, false] - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - when [false, true] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - end - - # Match - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[bj, 1] : seq2[bj] - event = Diff::LCS::ContextChange.new('=', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.match(event) - ai += 1 - bj += 1 - end - - while (ai < a_size) or (bj < b_size) - ax = string ? seq1[ai, 1] : seq1[ai] - bx = string ? seq2[bj, 1] : seq2[bj] - - case [(ai < a_size), (bj < b_size)] - when [true, true] - if callbacks.respond_to?(:change) - event = Diff::LCS::ContextChange.new('!', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.change(event) - ai += 1 - bj += 1 - else - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - ax = string ? seq1[ai, 1] : seq1[ai] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - when [true, false] - event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_a(event) - ai += 1 - when [false, true] - event = Diff::LCS::ContextChange.new('+', ai, ax, bj, bx) - event = yield event if block_given? - callbacks.discard_b(event) - bj += 1 - end - end - end - - PATCH_MAP = { #:nodoc: - :patch => { '+' => '+', '-' => '-', '!' => '!', '=' => '=' }, - :unpatch => { '+' => '-', '-' => '+', '!' => '!', '=' => '=' } - } - - # Given a patchset, convert the current version to the new - # version. If +direction+ is not specified (must be - # :patch or :unpatch), then discovery of the - # direction of the patch will be attempted. - def patch(src, patchset, direction = nil) - string = src.kind_of?(String) - # Start with a new empty type of the source's class - res = src.class.new - - # Normalize the patchset. - patchset = __normalize_patchset(patchset) - - direction ||= Diff::LCS.__diff_direction(src, patchset) - direction ||= :patch - - ai = bj = 0 - - patchset.each do |change| - # Both Change and ContextChange support #action - action = PATCH_MAP[direction][change.action] - - case change - when Diff::LCS::ContextChange - case direction - when :patch - el = change.new_element - op = change.old_position - np = change.new_position - when :unpatch - el = change.old_element - op = change.new_position - np = change.old_position - end - - case action - when '-' # Remove details from the old string - while ai < op - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - ai += 1 - when '+' - while bj < np - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - - res << el - bj += 1 - when '=' - # This only appears in sdiff output with the SDiff callback. - # Therefore, we only need to worry about dealing with a single - # element. - res << el - - ai += 1 - bj += 1 - when '!' - while ai < op - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - - bj += 1 - ai += 1 - - res << el - end - when Diff::LCS::Change - case action - when '-' - while ai < change.position - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - ai += 1 - when '+' - while bj < change.position - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - - bj += 1 - - res << change.element - end - end - end - - while ai < src.size - res << (string ? src[ai, 1] : src[ai]) - ai += 1 - bj += 1 - end - - res - end - - # Given a set of patchset, convert the current version to the prior - # version. Does no auto-discovery. - def unpatch!(src, patchset) - Diff::LCS.patch(src, patchset, :unpatch) - end - - # Given a set of patchset, convert the current version to the next - # version. Does no auto-discovery. - def patch!(src, patchset) - Diff::LCS.patch(src, patchset, :patch) - end - - # private - # Compute the longest common subsequence between the sequenced Enumerables - # +a+ and +b+. The result is an array whose contents is such that - # - # result = Diff::LCS.__lcs(a, b) - # result.each_with_index do |e, ii| - # assert_equal(a[ii], b[e]) unless e.nil? - # end - def __lcs(a, b) - a_start = b_start = 0 - a_finish = a.size - 1 - b_finish = b.size - 1 - vector = [] - - # Prune off any common elements at the beginning... - while (a_start <= a_finish) and - (b_start <= b_finish) and - (a[a_start] == b[b_start]) - vector[a_start] = b_start - a_start += 1 - b_start += 1 - end - - # Now the end... - while (a_start <= a_finish) and - (b_start <= b_finish) and - (a[a_finish] == b[b_finish]) - vector[a_finish] = b_finish - a_finish -= 1 - b_finish -= 1 - end - - # Now, compute the equivalence classes of positions of elements. - b_matches = Diff::LCS.__position_hash(b, b_start .. b_finish) - - thresh = [] - links = [] - - (a_start .. a_finish).each do |ii| - ai = a.kind_of?(String) ? a[ii, 1] : a[ii] - bm = b_matches[ai] - kk = nil - bm.reverse_each do |jj| - if kk and (thresh[kk] > jj) and (thresh[kk - 1] < jj) - thresh[kk] = jj - else - kk = Diff::LCS.__replace_next_larger(thresh, jj, kk) - end - links[kk] = [ (kk > 0) ? links[kk - 1] : nil, ii, jj ] unless kk.nil? - end - end - - unless thresh.empty? - link = links[thresh.size - 1] - while not link.nil? - vector[link[1]] = link[2] - link = link[0] - end - end - - vector - end - - # Find the place at which +value+ would normally be inserted into the - # Enumerable. If that place is already occupied by +value+, do nothing - # and return +nil+. If the place does not exist (i.e., it is off the end - # of the Enumerable), add it to the end. Otherwise, replace the element - # at that point with +value+. It is assumed that the Enumerable's values - # are numeric. - # - # This operation preserves the sort order. - def __replace_next_larger(enum, value, last_index = nil) - # Off the end? - if enum.empty? or (value > enum[-1]) - enum << value - return enum.size - 1 - end - - # Binary search for the insertion point - last_index ||= enum.size - first_index = 0 - while (first_index <= last_index) - ii = (first_index + last_index) >> 1 - - found = enum[ii] - - if value == found - return nil - elsif value > found - first_index = ii + 1 - else - last_index = ii - 1 - end - end - - # The insertion point is in first_index; overwrite the next larger - # value. - enum[first_index] = value - return first_index - end - - # If +vector+ maps the matching elements of another collection onto this - # Enumerable, compute the inverse +vector+ that maps this Enumerable - # onto the collection. (Currently unused.) - def __inverse_vector(a, vector) - inverse = a.dup - (0 ... vector.size).each do |ii| - inverse[vector[ii]] = ii unless vector[ii].nil? - end - inverse - end - - # Returns a hash mapping each element of an Enumerable to the set of - # positions it occupies in the Enumerable, optionally restricted to the - # elements specified in the range of indexes specified by +interval+. - def __position_hash(enum, interval = 0 .. -1) - hash = Hash.new { |hh, kk| hh[kk] = [] } - interval.each do |ii| - kk = enum.kind_of?(String) ? enum[ii, 1] : enum[ii] - hash[kk] << ii - end - hash - end - - # Examine the patchset and the source to see in which direction the - # patch should be applied. - # - # WARNING: By default, this examines the whole patch, so this could take - # some time. This also works better with Diff::LCS::ContextChange or - # Diff::LCS::Change as its source, as an array will cause the creation - # of one of the above. - def __diff_direction(src, patchset, limit = nil) - count = left = left_miss = right = right_miss = 0 - string = src.kind_of?(String) - - patchset.each do |change| - count += 1 - - case change - when Diff::LCS::Change - # With a simplistic change, we can't tell the difference between - # the left and right on '!' actions, so we ignore those. On '=' - # actions, if there's a miss, we miss both left and right. - element = string ? src[change.position, 1] : src[change.position] - - case change.action - when '-' - if element == change.element - left += 1 - else - left_miss += 1 - end - when '+' - if element == change.element - right += 1 - else - right_miss += 1 - end - when '=' - if element != change.element - left_miss += 1 - right_miss += 1 - end - end - when Diff::LCS::ContextChange - case change.action - when '-' # Remove details from the old string - element = string ? src[change.old_position, 1] : src[change.old_position] - if element == change.old_element - left += 1 - else - left_miss += 1 - end - when '+' - element = string ? src[change.new_position, 1] : src[change.new_position] - if element == change.new_element - right += 1 - else - right_miss += 1 - end - when '=' - le = string ? src[change.old_position, 1] : src[change.old_position] - re = string ? src[change.new_position, 1] : src[change.new_position] - - left_miss += 1 if le != change.old_element - right_miss += 1 if re != change.new_element - when '!' - element = string ? src[change.old_position, 1] : src[change.old_position] - if element == change.old_element - left += 1 - else - element = string ? src[change.new_position, 1] : src[change.new_position] - if element == change.new_element - right += 1 - else - left_miss += 1 - right_miss += 1 - end - end - end - end - - break if not limit.nil? and count > limit - end - - no_left = (left == 0) and (left_miss >= 0) - no_right = (right == 0) and (right_miss >= 0) - - case [no_left, no_right] - when [false, true] - return :patch - when [true, false] - return :unpatch - else - raise "The provided patchset does not appear to apply to the provided value as either source or destination value." - end - end - - # Normalize the patchset. A patchset is always a sequence of changes, but - # how those changes are represented may vary, depending on how they were - # generated. In all cases we support, we also support the array - # representation of the changes. The formats are: - # - # [ # patchset <- Diff::LCS.diff(a, b) - # [ # one or more hunks - # Diff::LCS::Change # one or more changes - # ] ] - # - # [ # patchset, equivalent to the above - # [ # one or more hunks - # [ action, line, value ] # one or more changes - # ] ] - # - # [ # patchset <- Diff::LCS.diff(a, b, Diff::LCS::ContextDiffCallbacks) - # # OR <- Diff::LCS.sdiff(a, b, Diff::LCS::ContextDiffCallbacks) - # [ # one or more hunks - # Diff::LCS::ContextChange # one or more changes - # ] ] - # - # [ # patchset, equivalent to the above - # [ # one or more hunks - # [ action, [ old line, old value ], [ new line, new value ] ] - # # one or more changes - # ] ] - # - # [ # patchset <- Diff::LCS.sdiff(a, b) - # # OR <- Diff::LCS.diff(a, b, Diff::LCS::SDiffCallbacks) - # Diff::LCS::ContextChange # one or more changes - # ] - # - # [ # patchset, equivalent to the above - # [ action, [ old line, old value ], [ new line, new value ] ] - # # one or more changes - # ] - # - # The result of this will be either of the following. - # - # [ # patchset - # Diff::LCS::ContextChange # one or more changes - # ] - # - # [ # patchset - # Diff::LCS::Change # one or more changes - # ] - # - # If either of the above is provided, it will be returned as such. - # - def __normalize_patchset(patchset) - patchset.map do |hunk| - case hunk - when Diff::LCS::ContextChange, Diff::LCS::Change - hunk - when Array - if (not hunk[0].kind_of?(Array)) and hunk[1].kind_of?(Array) and hunk[2].kind_of?(Array) - Diff::LCS::ContextChange.from_a(hunk) - else - hunk.map do |change| - case change - when Diff::LCS::ContextChange, Diff::LCS::Change - change - when Array - # change[1] will ONLY be an array in a ContextChange#to_a call. - # In Change#to_a, it represents the line (singular). - if change[1].kind_of?(Array) - Diff::LCS::ContextChange.from_a(change) - else - Diff::LCS::Change.from_a(change) - end - end - end - end - else - raise ArgumentError, "Cannot normalise a hunk of class #{hunk.class}." - end - end.flatten - end - end - end -end diff --git a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/array.rb b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/array.rb deleted file mode 100644 index dcbeebc..0000000 --- a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/array.rb +++ /dev/null @@ -1,21 +0,0 @@ -#! /usr/env/bin ruby -#-- -# Copyright 2004 Austin Ziegler -# adapted from: -# Algorithm::Diff (Perl) by Ned Konz -# Smalltalk by Mario I. Wolczko -# implements McIlroy-Hunt diff algorithm -# -# This program is free software. It may be redistributed and/or modified under -# the terms of the GPL version 2 (or later), the Perl Artistic licence, or the -# Ruby licence. -# -# $Id: array.rb,v 1.3 2004/08/08 20:33:09 austin Exp $ -#++ -# Includes Diff::LCS into the Array built-in class. - -require 'diff/lcs' - -class Array - include LCSDiff::Diff::LCS -end diff --git a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/block.rb b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/block.rb deleted file mode 100644 index ca791f3..0000000 --- a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/block.rb +++ /dev/null @@ -1,51 +0,0 @@ -#! /usr/env/bin ruby -#-- -# Copyright 2004 Austin Ziegler -# adapted from: -# Algorithm::Diff (Perl) by Ned Konz -# Smalltalk by Mario I. Wolczko -# implements McIlroy-Hunt diff algorithm -# -# This program is free software. It may be redistributed and/or modified under -# the terms of the GPL version 2 (or later), the Perl Artistic licence, or the -# Ruby licence. -# -# $Id: block.rb,v 1.3 2004/08/08 20:33:09 austin Exp $ -#++ -# Contains Diff::LCS::Block for bin/ldiff. - - # A block is an operation removing, adding, or changing a group of items. - # Basically, this is just a list of changes, where each change adds or - # deletes a single item. Used by bin/ldiff. -class LCSDiff::Diff::LCS::Block - attr_reader :changes, :insert, :remove - - def initialize(chunk) - @changes = [] - @insert = [] - @remove = [] - - chunk.each do |item| - @changes << item - @remove << item if item.deleting? - @insert << item if item.adding? - end - end - - def diff_size - @insert.size - @remove.size - end - - def op - case [@remove.empty?, @insert.empty?] - when [false, false] - '!' - when [false, true] - '-' - when [true, false] - '+' - else # [true, true] - '^' - end - end -end diff --git a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/callbacks.rb b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/callbacks.rb deleted file mode 100644 index 1c170d8..0000000 --- a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/callbacks.rb +++ /dev/null @@ -1,322 +0,0 @@ -#! /usr/env/bin ruby -#-- -# Copyright 2004 Austin Ziegler -# adapted from: -# Algorithm::Diff (Perl) by Ned Konz -# Smalltalk by Mario I. Wolczko -# implements McIlroy-Hunt diff algorithm -# -# This program is free software. It may be redistributed and/or modified under -# the terms of the GPL version 2 (or later), the Perl Artistic licence, or the -# Ruby licence. -# -# $Id: callbacks.rb,v 1.4 2004/09/14 18:51:26 austin Exp $ -#++ -# Contains definitions for all default callback objects. - -require 'diff/lcs/change' - -module LCSDiff::Diff::LCS - # This callback object implements the default set of callback events, which - # only returns the event itself. Note that #finished_a and #finished_b are - # not implemented -- I haven't yet figured out where they would be useful. - # - # Note that this is intended to be called as is, e.g., - # - # Diff::LCS.LCS(seq1, seq2, Diff::LCS::DefaultCallbacks) - class DefaultCallbacks - class << self - # Called when two items match. - def match(event) - event - end - # Called when the old value is discarded in favour of the new value. - def discard_a(event) - event - end - # Called when the new value is discarded in favour of the old value. - def discard_b(event) - event - end - # Called when both the old and new values have changed. - def change(event) - event - end - - private :new - end - end - - # An alias for DefaultCallbacks that is used in Diff::LCS#traverse_sequences. - # - # Diff::LCS.LCS(seq1, seq2, Diff::LCS::SequenceCallbacks) - SequenceCallbacks = DefaultCallbacks - # An alias for DefaultCallbacks that is used in Diff::LCS#traverse_balanced. - # - # Diff::LCS.LCS(seq1, seq2, Diff::LCS::BalancedCallbacks) - BalancedCallbacks = DefaultCallbacks -end - - # This will produce a compound array of simple diff change objects. Each - # element in the #diffs array is a +hunk+ or +hunk+ array, where each - # element in each +hunk+ array is a single Change object representing the - # addition or removal of a single element from one of the two tested - # sequences. The +hunk+ provides the full context for the changes. - # - # diffs = Diff::LCS.diff(seq1, seq2) - # # This example shows a simplified array format. - # # [ [ [ '-', 0, 'a' ] ], # 1 - # # [ [ '+', 2, 'd' ] ], # 2 - # # [ [ '-', 4, 'h' ], # 3 - # # [ '+', 4, 'f' ] ], - # # [ [ '+', 6, 'k' ] ], # 4 - # # [ [ '-', 8, 'n' ], # 5 - # # [ '-', 9, 'p' ], - # # [ '+', 9, 'r' ], - # # [ '+', 10, 's' ], - # # [ '+', 11, 't' ] ] ] - # - # There are five hunks here. The first hunk says that the +a+ at position 0 - # of the first sequence should be deleted ('-'). The second hunk - # says that the +d+ at position 2 of the second sequence should be inserted - # ('+'). The third hunk says that the +h+ at position 4 of the - # first sequence should be removed and replaced with the +f+ from position 4 - # of the second sequence. The other two hunks are described similarly. - # - # === Use - # This callback object must be initialised and is used by the Diff::LCS#diff - # method. - # - # cbo = Diff::LCS::DiffCallbacks.new - # Diff::LCS.LCS(seq1, seq2, cbo) - # cbo.finish - # - # Note that the call to #finish is absolutely necessary, or the last set of - # changes will not be visible. Alternatively, can be used as: - # - # cbo = Diff::LCS::DiffCallbacks.new { |tcbo| Diff::LCS.LCS(seq1, seq2, tcbo) } - # - # The necessary #finish call will be made. - # - # === Simplified Array Format - # The simplified array format used in the example above can be obtained - # with: - # - # require 'pp' - # pp diffs.map { |e| e.map { |f| f.to_a } } -class LCSDiff::Diff::LCS::DiffCallbacks - # Returns the difference set collected during the diff process. - attr_reader :diffs - - def initialize # :yields self: - @hunk = [] - @diffs = [] - - if block_given? - begin - yield self - ensure - self.finish - end - end - end - - # Finalizes the diff process. If an unprocessed hunk still exists, then it - # is appended to the diff list. - def finish - add_nonempty_hunk - end - - def match(event) - add_nonempty_hunk - end - - def discard_a(event) - @hunk << LCSDiff::Diff::LCS::Change.new('-', event.old_position, event.old_element) - end - - def discard_b(event) - @hunk << LCSDiff::Diff::LCS::Change.new('+', event.new_position, event.new_element) - end - -private - def add_nonempty_hunk - @diffs << @hunk unless @hunk.empty? - @hunk = [] - end -end - - # This will produce a compound array of contextual diff change objects. Each - # element in the #diffs array is a "hunk" array, where each element in each - # "hunk" array is a single change. Each change is a Diff::LCS::ContextChange - # that contains both the old index and new index values for the change. The - # "hunk" provides the full context for the changes. Both old and new objects - # will be presented for changed objects. +nil+ will be substituted for a - # discarded object. - # - # seq1 = %w(a b c e h j l m n p) - # seq2 = %w(b c d e f j k l m r s t) - # - # diffs = Diff::LCS.diff(seq1, seq2, Diff::LCS::ContextDiffCallbacks) - # # This example shows a simplified array format. - # # [ [ [ '-', [ 0, 'a' ], [ 0, nil ] ] ], # 1 - # # [ [ '+', [ 3, nil ], [ 2, 'd' ] ] ], # 2 - # # [ [ '-', [ 4, 'h' ], [ 4, nil ] ], # 3 - # # [ '+', [ 5, nil ], [ 4, 'f' ] ] ], - # # [ [ '+', [ 6, nil ], [ 6, 'k' ] ] ], # 4 - # # [ [ '-', [ 8, 'n' ], [ 9, nil ] ], # 5 - # # [ '+', [ 9, nil ], [ 9, 'r' ] ], - # # [ '-', [ 9, 'p' ], [ 10, nil ] ], - # # [ '+', [ 10, nil ], [ 10, 's' ] ], - # # [ '+', [ 10, nil ], [ 11, 't' ] ] ] ] - # - # The five hunks shown are comprised of individual changes; if there is a - # related set of changes, they are still shown individually. - # - # This callback can also be used with Diff::LCS#sdiff, which will produce - # results like: - # - # diffs = Diff::LCS.sdiff(seq1, seq2, Diff::LCS::ContextCallbacks) - # # This example shows a simplified array format. - # # [ [ [ "-", [ 0, "a" ], [ 0, nil ] ] ], # 1 - # # [ [ "+", [ 3, nil ], [ 2, "d" ] ] ], # 2 - # # [ [ "!", [ 4, "h" ], [ 4, "f" ] ] ], # 3 - # # [ [ "+", [ 6, nil ], [ 6, "k" ] ] ], # 4 - # # [ [ "!", [ 8, "n" ], [ 9, "r" ] ], # 5 - # # [ "!", [ 9, "p" ], [ 10, "s" ] ], - # # [ "+", [ 10, nil ], [ 11, "t" ] ] ] ] - # - # The five hunks are still present, but are significantly shorter in total - # presentation, because changed items are shown as changes ("!") instead of - # potentially "mismatched" pairs of additions and deletions. - # - # The result of this operation is similar to that of - # Diff::LCS::SDiffCallbacks. They may be compared as: - # - # s = Diff::LCS.sdiff(seq1, seq2).reject { |e| e.action == "=" } - # c = Diff::LCS.sdiff(seq1, seq2, Diff::LCS::ContextDiffCallbacks).flatten - # - # s == c # -> true - # - # === Use - # This callback object must be initialised and can be used by the - # Diff::LCS#diff or Diff::LCS#sdiff methods. - # - # cbo = Diff::LCS::ContextDiffCallbacks.new - # Diff::LCS.LCS(seq1, seq2, cbo) - # cbo.finish - # - # Note that the call to #finish is absolutely necessary, or the last set of - # changes will not be visible. Alternatively, can be used as: - # - # cbo = Diff::LCS::ContextDiffCallbacks.new { |tcbo| Diff::LCS.LCS(seq1, seq2, tcbo) } - # - # The necessary #finish call will be made. - # - # === Simplified Array Format - # The simplified array format used in the example above can be obtained - # with: - # - # require 'pp' - # pp diffs.map { |e| e.map { |f| f.to_a } } -class LCSDiff::Diff::LCS::ContextDiffCallbacks < LCSDiff::Diff::LCS::DiffCallbacks - def discard_a(event) - @hunk << Diff::LCS::ContextChange.simplify(event) - end - - def discard_b(event) - @hunk << Diff::LCS::ContextChange.simplify(event) - end - - def change(event) - @hunk << Diff::LCS::ContextChange.simplify(event) - end -end - - # This will produce a simple array of diff change objects. Each element in - # the #diffs array is a single ContextChange. In the set of #diffs provided - # by SDiffCallbacks, both old and new objects will be presented for both - # changed and unchanged objects. +nil+ will be substituted - # for a discarded object. - # - # The diffset produced by this callback, when provided to Diff::LCS#sdiff, - # will compute and display the necessary components to show two sequences - # and their minimized differences side by side, just like the Unix utility - # +sdiff+. - # - # same same - # before | after - # old < - - # - > new - # - # seq1 = %w(a b c e h j l m n p) - # seq2 = %w(b c d e f j k l m r s t) - # - # diffs = Diff::LCS.sdiff(seq1, seq2) - # # This example shows a simplified array format. - # # [ [ "-", [ 0, "a"], [ 0, nil ] ], - # # [ "=", [ 1, "b"], [ 0, "b" ] ], - # # [ "=", [ 2, "c"], [ 1, "c" ] ], - # # [ "+", [ 3, nil], [ 2, "d" ] ], - # # [ "=", [ 3, "e"], [ 3, "e" ] ], - # # [ "!", [ 4, "h"], [ 4, "f" ] ], - # # [ "=", [ 5, "j"], [ 5, "j" ] ], - # # [ "+", [ 6, nil], [ 6, "k" ] ], - # # [ "=", [ 6, "l"], [ 7, "l" ] ], - # # [ "=", [ 7, "m"], [ 8, "m" ] ], - # # [ "!", [ 8, "n"], [ 9, "r" ] ], - # # [ "!", [ 9, "p"], [ 10, "s" ] ], - # # [ "+", [ 10, nil], [ 11, "t" ] ] ] - # - # The result of this operation is similar to that of - # Diff::LCS::ContextDiffCallbacks. They may be compared as: - # - # s = Diff::LCS.sdiff(seq1, seq2).reject { |e| e.action == "=" } - # c = Diff::LCS.sdiff(seq1, seq2, Diff::LCS::ContextDiffCallbacks).flatten - # - # s == c # -> true - # - # === Use - # This callback object must be initialised and is used by the Diff::LCS#sdiff - # method. - # - # cbo = Diff::LCS::SDiffCallbacks.new - # Diff::LCS.LCS(seq1, seq2, cbo) - # - # As with the other initialisable callback objects, Diff::LCS::SDiffCallbacks - # can be initialised with a block. As there is no "fininishing" to be done, - # this has no effect on the state of the object. - # - # cbo = Diff::LCS::SDiffCallbacks.new { |tcbo| Diff::LCS.LCS(seq1, seq2, tcbo) } - # - # === Simplified Array Format - # The simplified array format used in the example above can be obtained - # with: - # - # require 'pp' - # pp diffs.map { |e| e.to_a } -class LCSDiff::Diff::LCS::SDiffCallbacks - # Returns the difference set collected during the diff process. - attr_reader :diffs - - def initialize #:yields self: - @diffs = [] - yield self if block_given? - end - - def match(event) - @diffs << Diff::LCS::ContextChange.simplify(event) - end - - def discard_a(event) - @diffs << Diff::LCS::ContextChange.simplify(event) - end - - def discard_b(event) - @diffs << Diff::LCS::ContextChange.simplify(event) - end - - def change(event) - @diffs << Diff::LCS::ContextChange.simplify(event) - end -end diff --git a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/change.rb b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/change.rb deleted file mode 100644 index 65d0eb6..0000000 --- a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/change.rb +++ /dev/null @@ -1,172 +0,0 @@ -#! /usr/env/bin ruby -#-- -# Copyright 2004 Austin Ziegler -# adapted from: -# Algorithm::Diff (Perl) by Ned Konz -# Smalltalk by Mario I. Wolczko -# implements McIlroy-Hunt diff algorithm -# -# This program is free software. It may be redistributed and/or modified under -# the terms of the GPL version 2 (or later), the Perl Artistic licence, or the -# Ruby licence. -# -# $Id: change.rb,v 1.4 2004/08/08 20:33:09 austin Exp $ -#++ -# Provides Diff::LCS::Change and Diff::LCS::ContextChange. - -module LCSDiff - - # Centralises the change test code in Diff::LCS::Change and - # Diff::LCS::ContextChange, since it's the same for both classes. - module Diff::LCS::ChangeTypeTests - def deleting? - @action == '-' - end - - def adding? - @action == '+' - end - - def unchanged? - @action == '=' - end - - def changed? - @changed == '!' - end - - def finished_a? - @changed == '>' - end - - def finished_b? - @changed == '<' - end - end - - # Represents a simplistic (non-contextual) change. Represents the removal or - # addition of an element from either the old or the new sequenced enumerable. - class Diff::LCS::Change - # Returns the action this Change represents. Can be '+' (#adding?), '-' - # (#deleting?), '=' (#unchanged?), # or '!' (#changed?). When created by - # Diff::LCS#diff or Diff::LCS#sdiff, it may also be '>' (#finished_a?) or - # '<' (#finished_b?). - attr_reader :action - attr_reader :position - attr_reader :element - - include Comparable - def ==(other) - (self.action == other.action) and - (self.position == other.position) and - (self.element == other.element) - end - - def <=>(other) - r = self.action <=> other.action - r = self.position <=> other.position if r.zero? - r = self.element <=> other.element if r.zero? - r - end - - def initialize(action, position, element) - @action = action - @position = position - @element = element - end - - # Creates a Change from an array produced by Change#to_a. - def to_a - [@action, @position, @element] - end - - def self.from_a(arr) - Diff::LCS::Change.new(arr[0], arr[1], arr[2]) - end - - include Diff::LCS::ChangeTypeTests - end - - # Represents a contextual change. Contains the position and values of the - # elements in the old and the new sequenced enumerables as well as the action - # taken. - class Diff::LCS::ContextChange - # Returns the action this Change represents. Can be '+' (#adding?), '-' - # (#deleting?), '=' (#unchanged?), # or '!' (#changed?). When - # created by Diff::LCS#diff or Diff::LCS#sdiff, it may also be '>' - # (#finished_a?) or '<' (#finished_b?). - attr_reader :action - attr_reader :old_position - attr_reader :old_element - attr_reader :new_position - attr_reader :new_element - - include Comparable - - def ==(other) - (@action == other.action) and - (@old_position == other.old_position) and - (@new_position == other.new_position) and - (@old_element == other.old_element) and - (@new_element == other.new_element) - end - - def inspect(*args) - %Q(#<#{self.class.name}:#{__id__} @action=#{action} positions=#{old_position},#{new_position} elements=#{old_element.inspect},#{new_element.inspect}>) - end - - def <=>(other) - r = @action <=> other.action - r = @old_position <=> other.old_position if r.zero? - r = @new_position <=> other.new_position if r.zero? - r = @old_element <=> other.old_element if r.zero? - r = @new_element <=> other.new_element if r.zero? - r - end - - def initialize(action, old_position, old_element, new_position, new_element) - @action = action - @old_position = old_position - @old_element = old_element - @new_position = new_position - @new_element = new_element - end - - def to_a - [@action, [@old_position, @old_element], [@new_position, @new_element]] - end - - # Creates a ContextChange from an array produced by ContextChange#to_a. - def self.from_a(arr) - if arr.size == 5 - Diff::LCS::ContextChange.new(arr[0], arr[1], arr[2], arr[3], arr[4]) - else - Diff::LCS::ContextChange.new(arr[0], arr[1][0], arr[1][1], arr[2][0], - arr[2][1]) - end - end - - # Simplifies a context change for use in some diff callbacks. '<' actions - # are converted to '-' and '>' actions are converted to '+'. - def self.simplify(event) - ea = event.to_a - - case ea[0] - when '-' - ea[2][1] = nil - when '<' - ea[0] = '-' - ea[2][1] = nil - when '+' - ea[1][1] = nil - when '>' - ea[0] = '+' - ea[1][1] = nil - end - - Diff::LCS::ContextChange.from_a(ea) - end - - include Diff::LCS::ChangeTypeTests - end -end diff --git a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/hunk.rb b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/hunk.rb deleted file mode 100644 index f175a39..0000000 --- a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/hunk.rb +++ /dev/null @@ -1,257 +0,0 @@ -#! /usr/env/bin ruby -#-- -# Copyright 2004 Austin Ziegler -# adapted from: -# Algorithm::Diff (Perl) by Ned Konz -# Smalltalk by Mario I. Wolczko -# implements McIlroy-Hunt diff algorithm -# -# This program is free software. It may be redistributed and/or modified under -# the terms of the GPL version 2 (or later), the Perl Artistic licence, or the -# Ruby licence. -# -# $Id: hunk.rb,v 1.2 2004/08/08 20:33:09 austin Exp $ -#++ -# Contains Diff::LCS::Hunk for bin/ldiff. - -require 'diff/lcs/block' - - # A Hunk is a group of Blocks which overlap because of the context - # surrounding each block. (So if we're not using context, every hunk will - # contain one block.) Used in the diff program (bin/diff). -class LCSDiff::Diff::LCS::Hunk - # Create a hunk using references to both the old and new data, as well as - # the piece of data - def initialize(data_old, data_new, piece, context, file_length_difference) - # At first, a hunk will have just one Block in it - @blocks = [ Diff::LCS::Block.new(piece) ] - @data_old = data_old - @data_new = data_new - - before = after = file_length_difference - after += @blocks[0].diff_size - @file_length_difference = after # The caller must get this manually - - # Save the start & end of each array. If the array doesn't exist - # (e.g., we're only adding items in this block), then figure out the - # line number based on the line number of the other file and the - # current difference in file lengths. - if @blocks[0].remove.empty? - a1 = a2 = nil - else - a1 = @blocks[0].remove[0].position - a2 = @blocks[0].remove[-1].position - end - - if @blocks[0].insert.empty? - b1 = b2 = nil - else - b1 = @blocks[0].insert[0].position - b2 = @blocks[0].insert[-1].position - end - - @start_old = a1 || (b1 - before) - @start_new = b1 || (a1 + before) - @end_old = a2 || (b2 - after) - @end_new = b2 || (a2 + after) - - self.flag_context = context - end - - attr_reader :blocks - attr_reader :start_old, :start_new - attr_reader :end_old, :end_new - attr_reader :file_length_difference - - # Change the "start" and "end" fields to note that context should be added - # to this hunk - attr_accessor :flag_context - def flag_context=(context) #:nodoc: - return if context.nil? or context.zero? - - add_start = (context > @start_old) ? @start_old : context - @start_old -= add_start - @start_new -= add_start - - if (@end_old + context) > @data_old.size - add_end = @data_old.size - @end_old - else - add_end = context - end - @end_old += add_end - @end_new += add_end - end - - def unshift(hunk) - @start_old = hunk.start_old - @start_new = hunk.start_new - blocks.unshift(*hunk.blocks) - end - - # Is there an overlap between hunk arg0 and old hunk arg1? Note: if end - # of old hunk is one less than beginning of second, they overlap - def overlaps?(hunk = nil) - return nil if hunk.nil? - - a = (@start_old - hunk.end_old) <= 1 - b = (@start_new - hunk.end_new) <= 1 - return (a or b) - end - - def diff(format) - case format - when :old - old_diff - when :unified - unified_diff - when :context - context_diff - when :ed - self - when :reverse_ed, :ed_finish - ed_diff(format) - else - raise "Unknown diff format #{format}." - end - end - - def each_old(block) - @data_old[@start_old .. @end_old].each { |e| yield e } - end - - private - # Note that an old diff can't have any context. Therefore, we know that - # there's only one block in the hunk. - def old_diff - warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 - op_act = { "+" => 'a', "-" => 'd', "!" => "c" } - - block = @blocks[0] - - # Calculate item number range. Old diff range is just like a context - # diff range, except the ranges are on one line with the action between - # them. - s = "#{context_range(:old)}#{op_act[block.op]}#{context_range(:new)}\n" - # If removing anything, just print out all the remove lines in the hunk - # which is just all the remove lines in the block. - @data_old[@start_old .. @end_old].each { |e| s << "< #{e}\n" } unless block.remove.empty? - s << "---\n" if block.op == "!" - @data_new[@start_new .. @end_new].each { |e| s << "> #{e}\n" } unless block.insert.empty? - s - end - - def unified_diff - # Calculate item number range. - s = "@@ -#{unified_range(:old)} +#{unified_range(:new)} @@\n" - - # Outlist starts containing the hunk of the old file. Removing an item - # just means putting a '-' in front of it. Inserting an item requires - # getting it from the new file and splicing it in. We splice in - # +num_added+ items. Remove blocks use +num_added+ because splicing - # changed the length of outlist. - # - # We remove +num_removed+ items. Insert blocks use +num_removed+ - # because their item numbers -- corresponding to positions in the NEW - # file -- don't take removed items into account. - lo, hi, num_added, num_removed = @start_old, @end_old, 0, 0 - - outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - - @blocks.each do |block| - block.remove.each do |item| - op = item.action.to_s # - - offset = item.position - lo + num_added - outlist[offset].gsub!(/^ /, op.to_s) - num_removed += 1 - end - block.insert.each do |item| - op = item.action.to_s # + - offset = item.position - @start_new + num_removed - outlist[offset, 0] = "#{op}#{@data_new[item.position]}" - num_added += 1 - end - end - - s << outlist.join("\n") - end - - def context_diff - s = "***************\n" - s << "*** #{context_range(:old)} ****\n" - r = context_range(:new) - - # Print out file 1 part for each block in context diff format if there - # are any blocks that remove items - lo, hi = @start_old, @end_old - removes = @blocks.select { |e| not e.remove.empty? } - if removes - outlist = @data_old[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - removes.each do |block| - block.remove.each do |item| - outlist[item.position - lo].gsub!(/^ /) { block.op } # - or ! - end - end - s << outlist.join("\n") - end - - s << "\n--- #{r} ----\n" - lo, hi = @start_new, @end_new - inserts = @blocks.select { |e| not e.insert.empty? } - if inserts - outlist = @data_new[lo .. hi].collect { |e| e.gsub(/^/, ' ') } - inserts.each do |block| - block.insert.each do |item| - outlist[item.position - lo].gsub!(/^ /) { block.op } # + or ! - end - end - s << outlist.join("\n") - end - s - end - - def ed_diff(format) - op_act = { "+" => 'a', "-" => 'd', "!" => "c" } - warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1 - - if format == :reverse_ed - s = "#{op_act[@blocks[0].op]}#{context_range(:old)}\n" - else - s = "#{context_range(:old).gsub(/,/, ' ')}#{op_act[@blocks[0].op]}\n" - end - - unless @blocks[0].insert.empty? - @data_new[@start_new .. @end_new].each { |e| s << "#{e}\n" } - s << ".\n" - end - s - end - - # Generate a range of item numbers to print. Only print 1 number if the - # range has only one item in it. Otherwise, it's 'start,end' - def context_range(mode) - case mode - when :old - s, e = (@start_old + 1), (@end_old + 1) - when :new - s, e = (@start_new + 1), (@end_new + 1) - end - - (s < e) ? "#{s},#{e}" : "#{e}" - end - - # Generate a range of item numbers to print for unified diff. Print - # number where block starts, followed by number of lines in the block - # (don't print number of lines if it's 1) - def unified_range(mode) - case mode - when :old - s, e = (@start_old + 1), (@end_old + 1) - when :new - s, e = (@start_new + 1), (@end_new + 1) - end - - length = e - s + 1 - first = (length < 2) ? e : s # "strange, but correct" - (length == 1) ? "#{first}" : "#{first},#{length}" - end -end diff --git a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/ldiff.rb b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/ldiff.rb deleted file mode 100644 index 32d4704..0000000 --- a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/ldiff.rb +++ /dev/null @@ -1,226 +0,0 @@ -#!/usr/bin/env ruby - -require 'optparse' -require 'ostruct' -require 'diff/lcs/hunk' - - # == ldiff Usage - # ldiff [options] oldfile newfile - # - # -c:: Displays a context diff with 3 lines of context. - # -C [LINES], --context [LINES]:: Displays a context diff with LINES lines of context. Default 3 lines. - # -u:: Displays a unified diff with 3 lines of context. - # -U [LINES], --unified [LINES]:: Displays a unified diff with LINES lines of context. Default 3 lines. - # -e:: Creates an 'ed' script to change oldfile to newfile. - # -f:: Creates an 'ed' script to change oldfile to newfile in reverse order. - # -a, --text:: Treats the files as text and compares them line-by-line, even if they do not seem to be text. - # --binary:: Treats the files as binary. - # -q, --brief:: Reports only whether or not the files differ, not the details. - # --help:: Shows the command-line help. - # --version:: Shows the version of Diff::LCS. - # - # By default, runs produces an "old-style" diff, with output like UNIX diff. - # - # == Copyright - # Copyright © 2004 Austin Ziegler - # - # Part of Diff::LCS - # Austin Ziegler - # - # This program is free software. It may be redistributed and/or modified under - # the terms of the GPL version 2 (or later), the Perl Artistic licence, or the - # Ruby licence. -module LCSDiff::Diff::LCS::Ldiff - BANNER = <<-COPYRIGHT -ldiff #{Diff::LCS::VERSION} - Copyright © 2004 Austin Ziegler - - Part of Diff::LCS. - http://rubyforge.org/projects/ruwiki/ - - Austin Ziegler - - This program is free software. It may be redistributed and/or modified under - the terms of the GPL version 2 (or later), the Perl Artistic licence, or the - Ruby licence. - -$Id: ldiff.rb,v 1.1 2004/09/26 01:37:49 austin Exp $ - COPYRIGHT - - class << self - attr_reader :format, :lines #:nodoc: - attr_reader :file_old, :file_new #:nodoc: - attr_reader :data_old, :data_new #:nodoc: - - def run(args, input = $stdin, output = $stdout, error = $stderr) #:nodoc: - args.options do |o| - o.banner = "Usage: #{File.basename($0)} [options] oldfile newfile" - o.separator "" - o.on('-c', - 'Displays a context diff with 3 lines of', - 'context.') do |ctx| - @format = :context - @lines = 3 - end - o.on('-C', '--context [LINES]', Numeric, - 'Displays a context diff with LINES lines', - 'of context. Default 3 lines.') do |ctx| - @format = :context - @lines = ctx || 3 - end - o.on('-u', - 'Displays a unified diff with 3 lines of', - 'context.') do |ctx| - @format = :unified - @lines = 3 - end - o.on('-U', '--unified [LINES]', Numeric, - 'Displays a unified diff with LINES lines', - 'of context. Default 3 lines.') do |ctx| - @format = :unified - @lines = ctx || 3 - end - o.on('-e', - 'Creates an \'ed\' script to change', - 'oldfile to newfile.') do |ctx| - @format = :ed - end - o.on('-f', - 'Creates an \'ed\' script to change', - 'oldfile to newfile in reverse order.') do |ctx| - @format = :reverse_ed - end - o.on('-a', '--text', - 'Treat the files as text and compare them', - 'line-by-line, even if they do not seem', - 'to be text.') do |txt| - @binary = false - end - o.on('--binary', - 'Treats the files as binary.') do |bin| - @binary = true - end - o.on('-q', '--brief', - 'Report only whether or not the files', - 'differ, not the details.') do |ctx| - @format = :report - end - o.on_tail('--help', 'Shows this text.') do - error << o - return 0 - end - o.on_tail('--version', 'Shows the version of Diff::LCS.') do - error << BANNER - return 0 - end - o.on_tail "" - o.on_tail 'By default, runs produces an "old-style" diff, with output like UNIX diff.' - o.parse! - end - - unless args.size == 2 - error << args.options - return 127 - end - - # Defaults are for old-style diff - @format ||= :old - @lines ||= 0 - - file_old, file_new = *ARGV - - case @format - when :context - char_old = '*' * 3 - char_new = '-' * 3 - when :unified - char_old = '-' * 3 - char_new = '+' * 3 - end - - # After we've read up to a certain point in each file, the number of - # items we've read from each file will differ by FLD (could be 0). - file_length_difference = 0 - - if @binary.nil? or @binary - data_old = IO::read(file_old) - data_new = IO::read(file_new) - - # Test binary status - if @binary.nil? - old_txt = data_old[0...4096].grep(/\0/).empty? - new_txt = data_new[0...4096].grep(/\0/).empty? - @binary = (not old_txt) or (not new_txt) - old_txt = new_txt = nil - end - - unless @binary - data_old = data_old.split(/\n/).map! { |e| e.chomp } - data_new = data_new.split(/\n/).map! { |e| e.chomp } - end - else - data_old = IO::readlines(file_old).map! { |e| e.chomp } - data_new = IO::readlines(file_new).map! { |e| e.chomp } - end - - # diff yields lots of pieces, each of which is basically a Block object - if @binary - diffs = (data_old == data_new) - else - diffs = Diff::LCS.diff(data_old, data_new) - diffs = nil if diffs.empty? - end - - return 0 unless diffs - - if (@format == :report) and diffs - output << "Files #{file_old} and #{file_new} differ\n" - return 1 - end - - if (@format == :unified) or (@format == :context) - ft = File.stat(file_old).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S %z') - puts "#{char_old} #{file_old}\t#{ft}" - ft = File.stat(file_new).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S %z') - puts "#{char_new} #{file_new}\t#{ft}" - end - - # Loop over hunks. If a hunk overlaps with the last hunk, join them. - # Otherwise, print out the old one. - oldhunk = hunk = nil - - if @format == :ed - real_output = output - output = [] - end - - diffs.each do |piece| - begin - hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, @lines, - file_length_difference) - file_length_difference = hunk.file_length_difference - - next unless oldhunk - - if (@lines > 0) and hunk.overlaps?(oldhunk) - hunk.unshift(oldhunk) - else - output << oldhunk.diff(@format) - end - ensure - oldhunk = hunk - output << "\n" - end - end - - output << oldhunk.diff(@format) - output << "\n" - - if @format == :ed - output.reverse_each { |e| real_output << e.diff(:ed_finish) } - end - - return 1 - end - end -end diff --git a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/string.rb b/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/string.rb deleted file mode 100644 index 514fa5e..0000000 --- a/vendor/gems/diff-lcs-1.1.2/lib/diff/lcs/string.rb +++ /dev/null @@ -1,19 +0,0 @@ -#! /usr/env/bin ruby -#-- -# Copyright 2004 Austin Ziegler -# adapted from: -# Algorithm::Diff (Perl) by Ned Konz -# Smalltalk by Mario I. Wolczko -# implements McIlroy-Hunt diff algorithm -# -# This program is free software. It may be redistributed and/or modified under -# the terms of the GPL version 2 (or later), the Perl Artistic licence, or the -# Ruby licence. -# -# $Id: string.rb,v 1.3 2004/08/08 20:33:09 austin Exp $ -#++ -# Includes Diff::LCS into String. - -class String - include LCSDiff::Diff::LCS -end diff --git a/vendor/gems/diff-lcs-1.1.2/tests/00test.rb b/vendor/gems/diff-lcs-1.1.2/tests/00test.rb deleted file mode 100644 index 8872dfd..0000000 --- a/vendor/gems/diff-lcs-1.1.2/tests/00test.rb +++ /dev/null @@ -1,626 +0,0 @@ -#! /usr/bin/env ruby -# -$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../lib") if __FILE__ == $0 - -require 'diff/lcs' -require 'test/unit' -require 'pp' -require 'diff/lcs/array' - -module Diff::LCS::Tests - def __format_diffs(diffs) - diffs.map do |e| - if e.kind_of?(Array) - e.map { |f| f.to_a.join }.join(", ") - else - e.to_a.join - end - end.join("; ") - end - - def __map_diffs(diffs, klass = Diff::LCS::ContextChange) - diffs.map do |chunks| - if klass == Diff::LCS::ContextChange - klass.from_a(chunks) - else - chunks.map { |changes| klass.from_a(changes) } - end - end - end - - def __simple_callbacks - callbacks = Object.new - class << callbacks - attr_reader :matched_a - attr_reader :matched_b - attr_reader :discards_a - attr_reader :discards_b - attr_reader :done_a - attr_reader :done_b - - def reset - @matched_a = [] - @matched_b = [] - @discards_a = [] - @discards_b = [] - @done_a = [] - @done_b = [] - end - - def match(event) - @matched_a << event.old_element - @matched_b << event.new_element - end - - def discard_b(event) - @discards_b << event.new_element - end - - def discard_a(event) - @discards_a << event.old_element - end - - def finished_a(event) - @done_a << [event.old_element, event.old_position] - end - - def finished_b(event) - @done_b << [event.new_element, event.new_position] - end - end - callbacks.reset - callbacks - end - - def __balanced_callback - cb = Object.new - class << cb - attr_reader :result - - def reset - @result = "" - end - - def match(event) - @result << "M#{event.old_position}#{event.new_position} " - end - - def discard_a(event) - @result << "DA#{event.old_position}#{event.new_position} " - end - - def discard_b(event) - @result << "DB#{event.old_position}#{event.new_position} " - end - - def change(event) - @result << "C#{event.old_position}#{event.new_position} " - end - end - cb.reset - cb - end - - def setup - @seq1 = %w(a b c e h j l m n p) - @seq2 = %w(b c d e f j k l m r s t) - - @correct_lcs = %w(b c e j l m) - - @skipped_seq1 = 'a h n p' - @skipped_seq2 = 'd f k r s t' - - correct_diff = [ - [ [ '-', 0, 'a' ] ], - [ [ '+', 2, 'd' ] ], - [ [ '-', 4, 'h' ], - [ '+', 4, 'f' ] ], - [ [ '+', 6, 'k' ] ], - [ [ '-', 8, 'n' ], - [ '-', 9, 'p' ], - [ '+', 9, 'r' ], - [ '+', 10, 's' ], - [ '+', 11, 't' ] ] ] - @correct_diff = __map_diffs(correct_diff, Diff::LCS::Change) - end -end - -class TestLCS < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_lcs - res = ares = bres = nil - assert_nothing_raised { res = Diff::LCS.__lcs(@seq1, @seq2) } - # The result of the LCS (less the +nil+ values) must be as long as the - # correct result. - assert_equal(res.compact.size, @correct_lcs.size) - res.each_with_index { |ee, ii| assert(ee.nil? || (@seq1[ii] == @seq2[ee])) } - assert_nothing_raised { ares = (0...res.size).map { |ii| res[ii] ? @seq1[ii] : nil } } - assert_nothing_raised { bres = (0...res.size).map { |ii| res[ii] ? @seq2[res[ii]] : nil } } - assert_equal(@correct_lcs, ares.compact) - assert_equal(@correct_lcs, bres.compact) - assert_nothing_raised { res = Diff::LCS.LCS(@seq1, @seq2) } - assert_equal(res.compact, @correct_lcs) - end -end - -class TestSequences < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_sequences - callbacks = nil - assert_nothing_raised do - callbacks = __simple_callbacks - class << callbacks - undef :finished_a - undef :finished_b - end - Diff::LCS.traverse_sequences(@seq1, @seq2, callbacks) - end - assert_equal(@correct_lcs.size, callbacks.matched_a.size) - assert_equal(@correct_lcs.size, callbacks.matched_b.size) - assert_equal(@skipped_seq1, callbacks.discards_a.join(" ")) - assert_equal(@skipped_seq2, callbacks.discards_b.join(" ")) - assert_nothing_raised do - callbacks = __simple_callbacks - Diff::LCS.traverse_sequences(@seq1, @seq2, callbacks) - end - assert_equal(@correct_lcs.size, callbacks.matched_a.size) - assert_equal(@correct_lcs.size, callbacks.matched_b.size) - assert_equal(@skipped_seq1, callbacks.discards_a.join(" ")) - assert_equal(@skipped_seq2, callbacks.discards_b.join(" ")) - assert_equal(9, callbacks.done_a[0][1]) - assert_nil(callbacks.done_b[0]) - -# seqw = %w(abcd efgh ijkl mnopqrstuvwxyz) -# assert_nothing_raised do -# callbacks = __simple_callbacks -# class << callbacks -# undef :finished_a -# undef :finished_b -# end -# Diff::LCS.traverse_sequences(seqw, [], callbacks) -# end - end - - def test_diff - diff = nil - assert_nothing_raised { diff = Diff::LCS.diff(@seq1, @seq2) } - assert_equal(__format_diffs(@correct_diff), __format_diffs(diff)) - assert_equal(@correct_diff, diff) - end - - def test_diff_empty - seqw = %w(abcd efgh ijkl mnopqrstuvwxyz) - correct_diff = [ - [ [ '-', 0, 'abcd' ], - [ '-', 1, 'efgh' ], - [ '-', 2, 'ijkl' ], - [ '-', 3, 'mnopqrstuvwxyz' ] ] ] - diff = nil - - assert_nothing_raised { diff = Diff::LCS.diff(seqw, []) } - assert_equal(__format_diffs(correct_diff), __format_diffs(diff)) - - correct_diff = [ - [ [ '+', 0, 'abcd' ], - [ '+', 1, 'efgh' ], - [ '+', 2, 'ijkl' ], - [ '+', 3, 'mnopqrstuvwxyz' ] ] ] - assert_nothing_raised { diff = Diff::LCS.diff([], seqw) } - assert_equal(__format_diffs(correct_diff), __format_diffs(diff)) - end -end - -class TestBalanced < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_sdiff_a - sdiff = nil - seq1 = %w(abc def yyy xxx ghi jkl) - seq2 = %w(abc dxf xxx ghi jkl) - correct_sdiff = [ - [ '=', [ 0, 'abc' ], [ 0, 'abc' ] ], - [ '!', [ 1, 'def' ], [ 1, 'dxf' ] ], - [ '-', [ 2, 'yyy' ], [ 2, nil ] ], - [ '=', [ 3, 'xxx' ], [ 2, 'xxx' ] ], - [ '=', [ 4, 'ghi' ], [ 3, 'ghi' ] ], - [ '=', [ 5, 'jkl' ], [ 4, 'jkl' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_b - sdiff = nil - correct_sdiff = [ - [ '-', [ 0, 'a' ], [ 0, nil ] ], - [ '=', [ 1, 'b' ], [ 0, 'b' ] ], - [ '=', [ 2, 'c' ], [ 1, 'c' ] ], - [ '+', [ 3, nil ], [ 2, 'd' ] ], - [ '=', [ 3, 'e' ], [ 3, 'e' ] ], - [ '!', [ 4, 'h' ], [ 4, 'f' ] ], - [ '=', [ 5, 'j' ], [ 5, 'j' ] ], - [ '+', [ 6, nil ], [ 6, 'k' ] ], - [ '=', [ 6, 'l' ], [ 7, 'l' ] ], - [ '=', [ 7, 'm' ], [ 8, 'm' ] ], - [ '!', [ 8, 'n' ], [ 9, 'r' ] ], - [ '!', [ 9, 'p' ], [ 10, 's' ] ], - [ '+', [ 10, nil ], [ 11, 't' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(@seq1, @seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_c - sdiff = nil - seq1 = %w(a b c d e) - seq2 = %w(a e) - correct_sdiff = [ - [ '=', [ 0, 'a' ], [ 0, 'a' ] ], - [ '-', [ 1, 'b' ], [ 1, nil ] ], - [ '-', [ 2, 'c' ], [ 1, nil ] ], - [ '-', [ 3, 'd' ], [ 1, nil ] ], - [ '=', [ 4, 'e' ], [ 1, 'e' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_d - sdiff = nil - seq1 = %w(a e) - seq2 = %w(a b c d e) - correct_sdiff = [ - [ '=', [ 0, 'a' ], [ 0, 'a' ] ], - [ '+', [ 1, nil ], [ 1, 'b' ] ], - [ '+', [ 1, nil ], [ 2, 'c' ] ], - [ '+', [ 1, nil ], [ 3, 'd' ] ], - [ '=', [ 1, 'e' ], [ 4, 'e' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_e - sdiff = nil - seq1 = %w(v x a e) - seq2 = %w(w y a b c d e) - correct_sdiff = [ - [ '!', [ 0, 'v' ], [ 0, 'w' ] ], - [ '!', [ 1, 'x' ], [ 1, 'y' ] ], - [ '=', [ 2, 'a' ], [ 2, 'a' ] ], - [ '+', [ 3, nil ], [ 3, 'b' ] ], - [ '+', [ 3, nil ], [ 4, 'c' ] ], - [ '+', [ 3, nil ], [ 5, 'd' ] ], - [ '=', [ 3, 'e' ], [ 6, 'e' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_f - sdiff = nil - seq1 = %w(x a e) - seq2 = %w(a b c d e) - correct_sdiff = [ - [ '-', [ 0, 'x' ], [ 0, nil ] ], - [ '=', [ 1, 'a' ], [ 0, 'a' ] ], - [ '+', [ 2, nil ], [ 1, 'b' ] ], - [ '+', [ 2, nil ], [ 2, 'c' ] ], - [ '+', [ 2, nil ], [ 3, 'd' ] ], - [ '=', [ 2, 'e' ], [ 4, 'e' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_g - sdiff = nil - seq1 = %w(a e) - seq2 = %w(x a b c d e) - correct_sdiff = [ - [ '+', [ 0, nil ], [ 0, 'x' ] ], - [ '=', [ 0, 'a' ], [ 1, 'a' ] ], - [ '+', [ 1, nil ], [ 2, 'b' ] ], - [ '+', [ 1, nil ], [ 3, 'c' ] ], - [ '+', [ 1, nil ], [ 4, 'd' ] ], - [ '=', [ 1, 'e' ], [ 5, 'e' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_h - sdiff = nil - seq1 = %w(a e v) - seq2 = %w(x a b c d e w x) - correct_sdiff = [ - [ '+', [ 0, nil ], [ 0, 'x' ] ], - [ '=', [ 0, 'a' ], [ 1, 'a' ] ], - [ '+', [ 1, nil ], [ 2, 'b' ] ], - [ '+', [ 1, nil ], [ 3, 'c' ] ], - [ '+', [ 1, nil ], [ 4, 'd' ] ], - [ '=', [ 1, 'e' ], [ 5, 'e' ] ], - [ '!', [ 2, 'v' ], [ 6, 'w' ] ], - [ '+', [ 3, nil ], [ 7, 'x' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_i - sdiff = nil - seq1 = %w() - seq2 = %w(a b c) - correct_sdiff = [ - [ '+', [ 0, nil ], [ 0, 'a' ] ], - [ '+', [ 0, nil ], [ 1, 'b' ] ], - [ '+', [ 0, nil ], [ 2, 'c' ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_j - sdiff = nil - seq1 = %w(a b c) - seq2 = %w() - correct_sdiff = [ - [ '-', [ 0, 'a' ], [ 0, nil ] ], - [ '-', [ 1, 'b' ], [ 0, nil ] ], - [ '-', [ 2, 'c' ], [ 0, nil ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_k - sdiff = nil - seq1 = %w(a b c) - seq2 = %w(1) - correct_sdiff = [ - [ '!', [ 0, 'a' ], [ 0, '1' ] ], - [ '-', [ 1, 'b' ], [ 1, nil ] ], - [ '-', [ 2, 'c' ], [ 1, nil ] ] ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_l - sdiff = nil - seq1 = %w(a b c) - seq2 = %w(c) - correct_sdiff = [ - [ '-', [ 0, 'a' ], [ 0, nil ] ], - [ '-', [ 1, 'b' ], [ 0, nil ] ], - [ '=', [ 2, 'c' ], [ 0, 'c' ] ] - ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_m - sdiff = nil - seq1 = %w(abcd efgh ijkl mnop) - seq2 = [] - correct_sdiff = [ - [ '-', [ 0, 'abcd' ], [ 0, nil ] ], - [ '-', [ 1, 'efgh' ], [ 0, nil ] ], - [ '-', [ 2, 'ijkl' ], [ 0, nil ] ], - [ '-', [ 3, 'mnop' ], [ 0, nil ] ] - ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_sdiff_n - sdiff = nil - seq1 = [] - seq2 = %w(abcd efgh ijkl mnop) - correct_sdiff = [ - [ '+', [ 0, nil ], [ 0, 'abcd' ] ], - [ '+', [ 0, nil ], [ 1, 'efgh' ] ], - [ '+', [ 0, nil ], [ 2, 'ijkl' ] ], - [ '+', [ 0, nil ], [ 3, 'mnop' ] ] - ] - correct_sdiff = __map_diffs(correct_sdiff) - assert_nothing_raised { sdiff = Diff::LCS.sdiff(seq1, seq2) } - assert_equal(correct_sdiff, sdiff) - end - - def test_balanced_a - seq1 = %w(a b c) - seq2 = %w(a x c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 C11 M22 ", callback.result) - end - - def test_balanced_b - seq1 = %w(a b c) - seq2 = %w(a x c) - callback = nil - assert_nothing_raised do - callback = __balanced_callback - class << callback - undef change - end - end - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 DA11 DB21 M22 ", callback.result) - end - - def test_balanced_c - seq1 = %w(a x y c) - seq2 = %w(a v w c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 C11 C22 M33 ", callback.result) - end - - def test_balanced_d - seq1 = %w(x y c) - seq2 = %w(v w c) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 M22 ", callback.result) - end - - def test_balanced_e - seq1 = %w(a x y z) - seq2 = %w(b v w) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 C22 DA33 ", callback.result) - end - - def test_balanced_f - seq1 = %w(a z) - seq2 = %w(a) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("M00 DA11 ", callback.result) - end - - def test_balanced_g - seq1 = %w(z a) - seq2 = %w(a) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DA00 M10 ", callback.result) - end - - def test_balanced_h - seq1 = %w(a b c) - seq2 = %w(x y z) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("C00 C11 C22 ", callback.result) - end - - def test_balanced_i - seq1 = %w(abcd efgh ijkl mnopqrstuvwxyz) - seq2 = [] - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DA00 DA10 DA20 DA30 ", callback.result) - end - - def test_balanced_j - seq1 = [] - seq2 = %w(abcd efgh ijkl mnopqrstuvwxyz) - callback = nil - assert_nothing_raised { callback = __balanced_callback } - assert_nothing_raised { Diff::LCS.traverse_balanced(seq1, seq2, callback) } - assert_equal("DB00 DB01 DB02 DB03 ", callback.result) - end -end - -class TestPatching < Test::Unit::TestCase - include Diff::LCS::Tests - - def test_patch_diff - ps = ms1 = ms2 = ms3 = nil - assert_nothing_raised do - ps = Diff::LCS.diff(@seq1, @seq2) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms3 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - assert_nothing_raised do - ps = Diff::LCS.diff(@seq1, @seq2, Diff::LCS::ContextDiffCallbacks) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms2 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - assert_nothing_raised do - ps = Diff::LCS.diff(@seq1, @seq2, Diff::LCS::SDiffCallbacks) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms3 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - end - - # Tests patch bug #891: - # http://rubyforge.org/tracker/?func=detail&atid=407&aid=891&group_id=84 - def test_patch_bug891 - s1 = s2 = s3 = s4 = s5 = ps = nil - assert_nothing_raised do - s1 = %w{a b c d e f g h i j k } - s2 = %w{a b c d D e f g h i j k } - ps = Diff::LCS::diff(s1, s2) - s3 = Diff::LCS.patch(s1, ps, :patch) - ps = Diff::LCS::diff(s1, s2, Diff::LCS::ContextDiffCallbacks) - s4 = Diff::LCS.patch(s1, ps, :patch) - ps = Diff::LCS::diff(s1, s2, Diff::LCS::SDiffCallbacks) - s5 = Diff::LCS.patch(s1, ps, :patch) - end - assert_equal(s2, s3) - assert_equal(s2, s4) - assert_equal(s2, s5) - - assert_nothing_raised do - ps = Diff::LCS::sdiff(s1, s2) - s3 = Diff::LCS.patch(s1, ps, :patch) - ps = Diff::LCS::diff(s1, s2, Diff::LCS::ContextDiffCallbacks) - s4 = Diff::LCS.patch(s1, ps, :patch) - ps = Diff::LCS::diff(s1, s2, Diff::LCS::DiffCallbacks) - s5 = Diff::LCS.patch(s1, ps, :patch) - end - assert_equal(s2, s3) - assert_equal(s2, s4) - assert_equal(s2, s5) - end - - def test_patch_sdiff - ps = ms1 = ms2 = ms3 = nil - assert_nothing_raised do - ps = Diff::LCS.sdiff(@seq1, @seq2) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms3 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - assert_nothing_raised do - ps = Diff::LCS.sdiff(@seq1, @seq2, Diff::LCS::ContextDiffCallbacks) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms3 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - assert_nothing_raised do - ps = Diff::LCS.sdiff(@seq1, @seq2, Diff::LCS::DiffCallbacks) - ms1 = Diff::LCS.patch(@seq1, ps) - ms2 = Diff::LCS.patch(@seq2, ps, :unpatch) - ms3 = Diff::LCS.patch(@seq2, ps) - end - assert_equal(@seq2, ms1) - assert_equal(@seq1, ms2) - assert_equal(@seq1, ms3) - end -end From 6aaaa6fcf333617bf5044053c930fe6aa4805121 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 17 May 2009 14:39:38 -0400 Subject: [PATCH 141/387] Fixed build script to generate headers when none are present. --- build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build b/build index d837da2..f1520d9 100755 --- a/build +++ b/build @@ -20,7 +20,7 @@ success="Build successful; ohcount is in bin/" # presumably generated together), regenerate the headers. build_hash_headers() { - if [[ -z `ls src/hash/` || + if [[ -z `ls src/hash/*.h` || ! -z `find src/hash/*.gperf -newer src/hash/parser_hash.h` ]] then echo "Generating hash headers" From 216662746e1129591757e10345759df5a1d11a60 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 17 May 2009 14:40:13 -0400 Subject: [PATCH 142/387] Added Ohcount's output build files to .gitignore. --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 6995014..391e13d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,7 @@ lib/x86* *.swp tags .DS_Store +src/hash/*_hash.h +src/parsers/*.h +src/parser.o +test/unit/run_tests From ee3dc15e593a6629b8a989b6c9dd0f0b4d7eea91 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 17 May 2009 14:42:21 -0400 Subject: [PATCH 143/387] Modified build file to create 'bin/' directory if it does not exist. --- build | 1 + 1 file changed, 1 insertion(+) diff --git a/build b/build index f1520d9..4e0b52e 100755 --- a/build +++ b/build @@ -46,6 +46,7 @@ build_ohcount() build_hash_headers build_parser_o echo "Building Ohcount" + mkdir -p bin/ sh -c "$cc src/ohcount.c $files -o bin/ohcount -lpcre" || exit 1 } From 987ae767b4b6deacedc62dec14d14bd506b98322 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 17 May 2009 17:50:04 -0400 Subject: [PATCH 144/387] Reduced calling of 'strlen' in loops for speed in src/detector.c. --- src/detector.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/detector.c b/src/detector.c index f65867c..33f725f 100644 --- a/src/detector.c +++ b/src/detector.c @@ -72,7 +72,8 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { p = pe; } else break; } - for (p = line; p < line + strlen(line); p++) *p = tolower(*p); + char *eol = line + strlen(line); + for (p = line; p < eol; p++) *p = tolower(*p); p = strstr(line, "-*-"); if (p) { p += 3; @@ -99,7 +100,8 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { FILE *f = popen(command, "r"); if (f) { fgets(line, sizeof(line), f); - for (p = line; p < line + strlen(line); p++) *p = tolower(*p); + char *eol = line + strlen(line); + for (p = line; p < eol; p++) *p = tolower(*p); p = strstr(line, "script text"); if (p && p == line) { // /^script text(?: executable)? for \w/ p = strstr(line, "for "); @@ -150,8 +152,8 @@ const char *disambiguate_aspx(SourceFile *sourcefile) { char buf[length]; strncpy(buf, p, length); buf[length] = '\0'; - for (p = buf; p < buf + strlen(buf); p++) - *p = tolower(*p); + char *eol = buf + strlen(buf); + for (p = buf; p < eol; p++) *p = tolower(*p); p = buf; while (*p == ' ' || *p == '\t') p++; if (strncmp(p, "page", 4) == 0) { @@ -336,6 +338,7 @@ const char *disambiguate_h(SourceFile *sourcefile) { length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); strncpy(line, p, length); line[length] = '\0'; + char *eol = line + strlen(line); char *line_end = pe; // Look for C++ headers. @@ -351,7 +354,7 @@ const char *disambiguate_h(SourceFile *sourcefile) { // Is the header file a C++ header file? p++; pe = p; - while (pe < p + strlen(line) && *pe != '>' && *pe != '"') pe++; + while (pe < eol && *pe != '>' && *pe != '"') pe++; length = pe - p; strncpy(buf, p, length); buf[length] = '\0'; @@ -372,7 +375,7 @@ const char *disambiguate_h(SourceFile *sourcefile) { // Look for C++ keywords. p = line; - while (p < line + strlen(line) && *p != '\r' && *p != '\n') { + while (p < eol) { if (islower(*p) && !isalnum(*(p - 1)) && *(p - 1) != '_') { pe = p; while (islower(*pe)) pe++; @@ -495,6 +498,7 @@ const char *disambiguate_m(SourceFile *sourcefile) { length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); strncpy(line, p, length); line[length] = '\0'; + char *eol = line + strlen(line); char *line_end = pe; // Look for tell-tale lines. @@ -528,7 +532,7 @@ const char *disambiguate_m(SourceFile *sourcefile) { if (*p == ' ' || *p == '\t') { while (*p == ' ' || *p == '\t') p++; if (*p == '"') { - while (*p != '"' && p < line + strlen(line)) p++; + while (*p != '"' && p < eol) p++; if (*p == '"' && *(p - 2) == '.' && *(p - 1) == 'm') limbo_score++; } @@ -537,7 +541,7 @@ const char *disambiguate_m(SourceFile *sourcefile) { // Look for Octave keywords. p = line; - while (p < line + strlen(line)) { + while (p < eol) { if (islower(*p) && !isalnum(*(p - 1))) { pe = p; while (islower(*pe) || *pe == '_') pe++; @@ -557,7 +561,7 @@ const char *disambiguate_m(SourceFile *sourcefile) { // Look for Limbo declarations p = line; - while (p < line + strlen(line)) { + while (p < eol) { if (*p == ':' && (*(p + 1) == ' ' || *(p + 1) == '\t')) { // /:[ \t]+(module|adt|fn ?\(|con[ \t])/ p += 2; @@ -602,12 +606,13 @@ const char *disambiguate_st(SourceFile *sourcefile) { length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); strncpy(line, p, length); line[length] = '\0'; + char *eol = line + strlen(line); char *line_end = pe; - for (p = line; p < line + strlen(line); p++) { + for (p = line; p < eol; p++) { if (*p == ':') { p++; - while (p < line + strlen(line) && (*p == ' ' || *p == '\t')) p++; + while (p < eol && (*p == ' ' || *p == '\t')) p++; if (*p == '=') found_assignment = 1; else if (*p == '[') From 03876095e01e4b5ab029f02da30316b7463ee70c Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 17 May 2009 18:54:13 -0400 Subject: [PATCH 145/387] Added doc/html and bin/ to .gitignore. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 391e13d..71062be 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ src/hash/*_hash.h src/parsers/*.h src/parser.o test/unit/run_tests +doc/html +bin/ From 2c64f6527d796f2895d4299cfc51ea370ce3f449 Mon Sep 17 00:00:00 2001 From: mitchell Date: Mon, 18 May 2009 16:43:03 -0400 Subject: [PATCH 146/387] Parsing SourceFileLists in src/sourcefile.c is much more memory efficient. --- src/sourcefile.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sourcefile.c b/src/sourcefile.c index aac2a24..03458e3 100644 --- a/src/sourcefile.c +++ b/src/sourcefile.c @@ -175,6 +175,14 @@ void ohcount_sourcefile_parse(SourceFile *sourcefile) { if (sourcefile->parsed_language_list == NULL) { sourcefile->parsed_language_list = ohcount_parsed_language_list_new(); ohcount_parse(sourcefile, 1, parser_callback, sourcefile); + + // Since the SourceFile contents are not 'free'd until the SourceFile itself + // is, continually parsing SourceFiles in a SourceFileList will cause an + // undesirable build-up of memory until the SourceFileList is 'free'd. + // While it is expensive to re-read the contents from the disk, it is + // unlikely they will need to be accessed again after parsing. + free(sourcefile->contents); // field is guaranteed to exist + sourcefile->contents = NULL; } } From a2f01ebca744323b9b986959e863d7d8ba9af83b Mon Sep 17 00:00:00 2001 From: mitchell Date: Mon, 18 May 2009 17:09:49 -0400 Subject: [PATCH 147/387] Use diskpath field if necessary for getting file contents; src/sourcefile.c --- src/sourcefile.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sourcefile.c b/src/sourcefile.c index 03458e3..6834d24 100644 --- a/src/sourcefile.c +++ b/src/sourcefile.c @@ -75,7 +75,10 @@ void ohcount_sourcefile_set_contents(SourceFile *sourcefile, char *ohcount_sourcefile_get_contents(SourceFile *sourcefile) { if (sourcefile->contents == NULL) { - FILE *f = fopen(sourcefile->filepath, "r"); + char *path = sourcefile->filepath; + if (sourcefile->diskpath) + path = sourcefile->diskpath; + FILE *f = fopen(path, "r"); if (f) { fseek(f, 0, SEEK_END); int size = ftell(f); From a7b1053db19c4024eeb7cc05b5c792710c88ee8b Mon Sep 17 00:00:00 2001 From: mitchell Date: Wed, 20 May 2009 15:51:13 -0400 Subject: [PATCH 148/387] Add option to build file to build Ohcount as shared library. --- build | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/build b/build index 4e0b52e..a70b595 100755 --- a/build +++ b/build @@ -3,7 +3,7 @@ # Written by Mitchell Foral. mitchellcaladbolg.net. # C compiler and flags -cc="gcc -g -Wall -Wno-pointer-to-int-cast -Wno-parentheses" +cc="gcc -fPIC -g -Wall -Wno-pointer-to-int-cast -Wno-parentheses" # Ohcount source files files="src/sourcefile.c \ @@ -14,13 +14,11 @@ files="src/sourcefile.c \ src/diff.c \ src/parsed_language.c" -success="Build successful; ohcount is in bin/" - # If any src/hash/*.gperf file is newer than the header files (which were # presumably generated together), regenerate the headers. build_hash_headers() { - if [[ -z `ls src/hash/*.h` || + if [[ -z `ls src/hash/ | grep "_hash.h$"` || ! -z `find src/hash/*.gperf -newer src/hash/parser_hash.h` ]] then echo "Generating hash headers" @@ -37,7 +35,19 @@ build_parser_o() then sh -c "cd src/parsers/ && ./compile" || exit 1 echo "Building src/parser.c (will take a while)" - gcc -c src/parser.c -o src/parser.o || exit 1 + sh -c "$cc -c src/parser.c -o src/parser.o" || exit 1 + fi +} + +build_shared() +{ + build_hash_headers + build_parser_o + if [[ ! -f src/libohcount.so || + ! -z `find src/*.{h,c} -newer src/libohcount.so` ]] + then + echo "Building shared library" + sh -c "$cc -shared $files -o src/libohcount.so" || exit 1 fi } @@ -47,7 +57,7 @@ build_ohcount() build_parser_o echo "Building Ohcount" mkdir -p bin/ - sh -c "$cc src/ohcount.c $files -o bin/ohcount -lpcre" || exit 1 + sh -c "$cc src/ohcount.c $files -o bin/ohcount -lpcre" || exit 1 } build_test_suite() @@ -71,21 +81,26 @@ then build_test_suite run_test_suite echo $success +elif [ $1 == "shared" ] +then + build_shared + echo "Build successful; libohcount.so is in src/" elif [ $1 == "ohcount" ] then build_ohcount - echo $success + echo "Build successful; ohcount is in bin/" elif [ $1 == "tests" ] then build_test_suite run_test_suite elif [ $1 == "clean" ] then + rm src/libohcount.so rm bin/ohcount rm test/unit/run_tests rm src/parser.o rm src/parsers/*.h rm src/hash/*.h else - echo "Usage: build [all|ohcount|tests|clean]" + echo "Usage: build [all|ohcount|shared|tests|clean]" fi From 8c4a1ec1e598334fbbbce0db017b7f3b303c0e3f Mon Sep 17 00:00:00 2001 From: mitchell Date: Fri, 22 May 2009 18:30:04 -0400 Subject: [PATCH 149/387] Added #include guards for src/hash/ headers. --- src/hash/cppheaders.gperf | 6 ++++++ src/hash/disambiguatefuncs.gperf | 5 +++++ src/hash/extensions.gperf | 6 ++++++ src/hash/filenames.gperf | 5 +++++ src/hash/languages.gperf | 5 +++++ src/hash/options.gperf | 5 +++++ src/hash/parsers.gperf | 5 +++++ 7 files changed, 37 insertions(+) diff --git a/src/hash/cppheaders.gperf b/src/hash/cppheaders.gperf index 3a70930..4d94ccf 100644 --- a/src/hash/cppheaders.gperf +++ b/src/hash/cppheaders.gperf @@ -1,3 +1,7 @@ +%{ +#ifndef OHCOUNT_HASH_CPPHEADERS_HASH_H +#define OHCOUNT_HASH_CPPHEADERS_HASH_H +%} struct CppHeaderMap { const char *key; int value; }; %% algorithm, 1 @@ -89,3 +93,5 @@ tr1/type_traits, 1 tr1/unordered_map, 1 tr1/unordered_set, 1 tr1/utility, 1 +%% +#endif diff --git a/src/hash/disambiguatefuncs.gperf b/src/hash/disambiguatefuncs.gperf index 1bd1a6b..3f6ac3d 100644 --- a/src/hash/disambiguatefuncs.gperf +++ b/src/hash/disambiguatefuncs.gperf @@ -1,4 +1,7 @@ %{ +#ifndef OHCOUNT_HASH_DISAMBIGUATEFUNCS_HASH_H +#define OHCOUNT_HASH_DISAMBIGUATEFUNCS_HASH_H + #include "../detector.h" #include "../sourcefile.h" @@ -25,3 +28,5 @@ in, disambiguate_in inc, disambiguate_inc m, disambiguate_m st, disambiguate_st +%% +#endif diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index 46c0ac7..73fbfb4 100644 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -1,5 +1,9 @@ %{ +#ifndef OHCOUNT_HASH_EXTENSIONS_HASH_H +#define OHCOUNT_HASH_EXTENSIONS_HASH_H + #include "../languages.h" + #define BINARY NULL #define DISAMBIGUATE(x) ("\1" x) %} @@ -174,3 +178,5 @@ xsd, LANG_XMLSCHEMA xsl, LANG_XSLT z80, LANG_ASSEMBLER zip, BINARY +%% +#endif diff --git a/src/hash/filenames.gperf b/src/hash/filenames.gperf index 54b1685..279e934 100644 --- a/src/hash/filenames.gperf +++ b/src/hash/filenames.gperf @@ -1,4 +1,7 @@ %{ +#ifndef OHCOUNT_HASH_FILENAMES_HASH_H +#define OHCOUNT_HASH_FILENAMES_HASH_H + #include "../languages.h" %} struct FilenameMap { const char *key; const char *value; }; @@ -11,3 +14,5 @@ configure, LANG_AUTOCONF configure.ac, LANG_AUTOCONF configure.in, LANG_AUTOCONF makefile, LANG_MAKE +%% +#endif diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index ed746e6..ca52eae 100644 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -1,4 +1,7 @@ %{ +#ifndef OHCOUNT_HASH_LANGUAGE_HASH_H +#define OHCOUNT_HASH_LANGUAGE_HASH_H + #include "../languages.h" %} struct LanguageMap { const char *key; const char *value; }; @@ -82,3 +85,5 @@ xaml, LANG_XAML xml, LANG_XML xslt, LANG_XSLT xmlschema, LANG_XMLSCHEMA +%% +#endif diff --git a/src/hash/options.gperf b/src/hash/options.gperf index 4df3769..04d176f 100644 --- a/src/hash/options.gperf +++ b/src/hash/options.gperf @@ -1,4 +1,7 @@ %{ +#ifndef OHCOUNT_HASH_OPTIONS_HASH_H +#define OHCOUNT_HASH_OPTIONS_HASH_H + #include "../ohcount.h" %} struct OhcountOption { const char *key; int value; }; @@ -18,3 +21,5 @@ struct OhcountOption { const char *key; int value; }; -re, COMMAND_RAWENTITIES -s, COMMAND_SUMMARY --summary, COMMAND_SUMMARY +%% +#endif diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index a16792c..6579c7d 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -1,4 +1,7 @@ %{ +#ifndef OHCOUNT_HASH_PARSERS_HASH_H +#define OHCOUNT_HASH_PARSERS_HASH_H + #include "../parsers/actionscript.h" #include "../parsers/ada.h" #include "../parsers/assembler.h" @@ -157,3 +160,5 @@ xaml, parse_xaml xml, parse_xml xslt, parse_xslt xmlschema, parse_xmlschema +%% +#endif From 56e7572f66c796d73b0adbad4d276c6e1885ed51 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sat, 23 May 2009 15:08:58 -0400 Subject: [PATCH 150/387] Changed BINARY from NULL to "\1" for faster binary file detection. --- src/detector.c | 5 +++-- src/hash/extensions.gperf | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/detector.c b/src/detector.c index 33f725f..4e9b227 100644 --- a/src/detector.c +++ b/src/detector.c @@ -15,7 +15,8 @@ #include "hash/filename_hash.h" #include "hash/language_hash.h" -#define ISAMBIGUOUS(x) (x[0] == '\1') +#define ISBINARY(x) (x[0] == '\1') +#define ISAMBIGUOUS(x) (x[0] == '\2') #define DISAMBIGUATEWHAT(x) &x[1] const char *ohcount_detect_language(SourceFile *sourcefile) { @@ -45,7 +46,7 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { ohcount_hash_disambiguate_func_from_id(DISAMBIGUATEWHAT(language), length); if (rd) return rd->value(sourcefile); - } else return language; + } else return ISBINARY(language) ? NULL : language; } // Attempt to detect based on filename. diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index 73fbfb4..0d30807 100644 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -4,8 +4,8 @@ #include "../languages.h" -#define BINARY NULL -#define DISAMBIGUATE(x) ("\1" x) +#define BINARY "\1" +#define DISAMBIGUATE(x) ("\2" x) %} struct ExtensionMap { const char *key; const char *value; }; %% From 86d0faba6ab22283315e7fa92c6dc5f8d1b3adc9 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sat, 23 May 2009 15:09:39 -0400 Subject: [PATCH 151/387] Added extra Doxygen doc; src/sourcefile.c --- src/sourcefile.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sourcefile.h b/src/sourcefile.h index a347b9a..fef6a6b 100644 --- a/src/sourcefile.h +++ b/src/sourcefile.h @@ -157,6 +157,7 @@ LocDelta *ohcount_sourcefile_calc_loc_delta(SourceFile *from, /** * Sets the given SourceFile's directory contents to the string array given. + * The given array is copied and may be 'free'd immediately. * @param sourcefile A SourceFile created by ohcount_sourcefile_new(). * @param filenames String array of filenames. If NULL, the next call to * ohcount_sourcefile_get_filenames will access the SourceFile's directory. From 9db411dabf3f1c0525cec8ea655d8435af4d9760 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sat, 23 May 2009 18:41:08 -0400 Subject: [PATCH 152/387] Renamed ParsedLanguage->language to ParsedLanguage->name. --- src/parsed_language.c | 4 ++-- src/sourcefile.c | 14 +++++++------- src/structs.h | 2 +- test/unit/parser_test.h | 6 +++--- test/unit/sourcefile_test.h | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/parsed_language.c b/src/parsed_language.c index 70092cf..5cf6fdb 100644 --- a/src/parsed_language.c +++ b/src/parsed_language.c @@ -6,10 +6,10 @@ #include "parsed_language.h" -ParsedLanguage *ohcount_parsed_language_new(const char *language, +ParsedLanguage *ohcount_parsed_language_new(const char *name, int buffer_size) { ParsedLanguage *pl = malloc(sizeof(ParsedLanguage)); - pl->language = language; + pl->name = name; pl->buffer_size = buffer_size; pl->code = malloc(buffer_size + 5); pl->code_p = pl->code; diff --git a/src/sourcefile.c b/src/sourcefile.c index 6834d24..18f40eb 100644 --- a/src/sourcefile.c +++ b/src/sourcefile.c @@ -148,7 +148,7 @@ void parser_callback(const char *language, const char *entity, int start, // Has this language been detected before? ParsedLanguageList *iter = list->head; while (iter) { - if (strcmp(iter->pl->language, language) == 0) + if (strcmp(iter->pl->name, language) == 0) break; // yes it has iter = iter->next; } @@ -225,7 +225,7 @@ LocList *ohcount_sourcefile_get_loc_list(SourceFile *sourcefile) { ParsedLanguageList *iter; iter = ohcount_sourcefile_get_parsed_language_list(sourcefile)->head; while (iter) { - Loc *loc = ohcount_loc_new(iter->pl->language, iter->pl->code_count, + Loc *loc = ohcount_loc_new(iter->pl->name, iter->pl->code_count, iter->pl->comments_count, iter->pl->blanks_count, 1); ohcount_loc_list_add_loc(list, loc); @@ -244,7 +244,7 @@ LocDeltaList *ohcount_sourcefile_diff(SourceFile *from, SourceFile *to) { iter = ohcount_sourcefile_get_parsed_language_list(from)->head; while (iter) { LocDelta *delta = ohcount_sourcefile_calc_loc_delta(from, - iter->pl->language, + iter->pl->name, to); ohcount_loc_delta_list_add_loc_delta(list, delta); ohcount_loc_delta_free(delta); @@ -252,9 +252,9 @@ LocDeltaList *ohcount_sourcefile_diff(SourceFile *from, SourceFile *to) { } iter = ohcount_sourcefile_get_parsed_language_list(to)->head; while (iter) { - if (!ohcount_loc_delta_list_get_loc_delta(list, iter->pl->language)) { + if (!ohcount_loc_delta_list_get_loc_delta(list, iter->pl->name)) { LocDelta *delta = ohcount_sourcefile_calc_loc_delta(from, - iter->pl->language, + iter->pl->name, to); ohcount_loc_delta_list_add_loc_delta(list, delta); ohcount_loc_delta_free(delta); @@ -277,7 +277,7 @@ LocDelta *ohcount_sourcefile_calc_loc_delta(SourceFile *from, ParsedLanguageList *iter; iter = ohcount_sourcefile_get_parsed_language_list(from)->head; while (iter) { - if (strcmp(language, iter->pl->language) == 0) { + if (strcmp(language, iter->pl->name) == 0) { from_code = iter->pl->code; from_comments = iter->pl->comments; from_blanks_count = iter->pl->blanks_count; @@ -287,7 +287,7 @@ LocDelta *ohcount_sourcefile_calc_loc_delta(SourceFile *from, } iter = ohcount_sourcefile_get_parsed_language_list(to)->head; while (iter) { - if (strcmp(language, iter->pl->language) == 0) { + if (strcmp(language, iter->pl->name) == 0) { to_code = iter->pl->code; to_comments = iter->pl->comments; to_blanks_count = iter->pl->blanks_count; diff --git a/src/structs.h b/src/structs.h index 98e14fb..3bd9b67 100644 --- a/src/structs.h +++ b/src/structs.h @@ -178,7 +178,7 @@ typedef struct LocDeltaListItem { */ typedef struct { /** The parsed language. */ - const char *language; + const char *name; /** The size of the code and comments buffers. */ int buffer_size; diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index bf69ba6..d4a11f7 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -21,7 +21,7 @@ void test_parser_verify_parse(SourceFile *sf, const char *language, int blanks) { ohcount_sourcefile_parse(sf); ParsedLanguageList *list = ohcount_sourcefile_get_parsed_language_list(sf); - assert(strcmp(list->head->pl->language, language) == 0); + assert(strcmp(list->head->pl->name, language) == 0); assert(strcmp(list->head->pl->code, code) == 0); assert(strcmp(list->head->pl->comments, comments) == 0); assert(list->head->pl->blanks_count == blanks); @@ -35,11 +35,11 @@ void test_parser_verify_parse2(SourceFile *sf, const char *language, int blanks2) { ohcount_sourcefile_parse(sf); ParsedLanguageList *list = ohcount_sourcefile_get_parsed_language_list(sf); - assert(strcmp(list->head->pl->language, language) == 0); + assert(strcmp(list->head->pl->name, language) == 0); assert(strcmp(list->head->pl->code, code) == 0); assert(strcmp(list->head->pl->comments, comments) == 0); assert(list->head->pl->blanks_count == blanks); - assert(strcmp(list->head->next->pl->language, language2) == 0); + assert(strcmp(list->head->next->pl->name, language2) == 0); assert(strcmp(list->head->next->pl->code, code2) == 0); assert(strcmp(list->head->next->pl->comments, comments2) == 0); assert(list->head->next->pl->blanks_count == blanks2); diff --git a/test/unit/sourcefile_test.h b/test/unit/sourcefile_test.h index fee7b4a..e93eeb6 100644 --- a/test/unit/sourcefile_test.h +++ b/test/unit/sourcefile_test.h @@ -30,7 +30,7 @@ void test_sourcefile_language_breakdowns() { SourceFile *sf = ohcount_sourcefile_new("foo.rb"); ohcount_sourcefile_set_contents(sf, "x = 5"); ParsedLanguageList *list = ohcount_sourcefile_get_parsed_language_list(sf); - assert(strcmp("ruby", list->head->pl->language) == 0); + assert(strcmp("ruby", list->head->pl->name) == 0); assert(strcmp("x = 5", list->head->pl->code) == 0); ohcount_sourcefile_free(sf); } From 6f64a9156e37c264a71089310d8b48c54a0d15cf Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 24 May 2009 00:56:18 -0400 Subject: [PATCH 153/387] Added Ruby interface. --- build | 19 +++++- ruby/ohcount.i | 101 ++++++++++++++++++++++++++++ ruby/ohcount.rb | 77 ++++++++++++++++++++++ src/detector.c | 26 ++++++-- src/detector.h | 2 + src/hash/generate_headers | 2 +- src/hash/languages.gperf | 165 ++++++++++++++++++++++------------------------ src/languages.h | 6 ++ src/sourcefile.c | 10 ++- src/sourcefile.h | 3 +- 10 files changed, 314 insertions(+), 97 deletions(-) create mode 100644 ruby/ohcount.i create mode 100644 ruby/ohcount.rb diff --git a/build b/build index a70b595..89f1c84 100755 --- a/build +++ b/build @@ -12,7 +12,8 @@ files="src/sourcefile.c \ src/parser.o \ src/loc.c \ src/diff.c \ - src/parsed_language.c" + src/parsed_language.c \ + src/hash/language_hash.c" # If any src/hash/*.gperf file is newer than the header files (which were # presumably generated together), regenerate the headers. @@ -75,6 +76,14 @@ run_test_suite() sh -c "cd test/unit/ && ./run_tests" } +build_ruby_bindings() +{ + echo "Generating Ruby bindings" + sh -c "swig -ruby -o ruby/ohcount_wrap.c ruby/ohcount.i" || exit 1 + sh -c "$cc -shared ruby/ohcount_wrap.c $files -o ruby/ohcount.so \ + -I/usr/lib/ruby/1.8/x86_64-linux/ -lpcre" || exit 1 +} + if [ $# -eq 0 ] || [ $1 == "all" ] then build_ohcount @@ -93,6 +102,10 @@ elif [ $1 == "tests" ] then build_test_suite run_test_suite +elif [ $1 == "ruby" ] +then + build_ruby_bindings + echo "Build successful; ohcount.so is in ruby/" elif [ $1 == "clean" ] then rm src/libohcount.so @@ -100,7 +113,7 @@ then rm test/unit/run_tests rm src/parser.o rm src/parsers/*.h - rm src/hash/*.h + rm src/hash/*.c else - echo "Usage: build [all|ohcount|shared|tests|clean]" + echo "Usage: build [all|ohcount|shared|tests|ruby|clean]" fi diff --git a/ruby/ohcount.i b/ruby/ohcount.i new file mode 100644 index 0000000..a42f326 --- /dev/null +++ b/ruby/ohcount.i @@ -0,0 +1,101 @@ + +%module ohcount +%{ +#include "../src/detector.h" +#include "../src/languages.h" +#include "../src/sourcefile.h" +%} + +%include typemaps.i + +%typemap(in) (register const char *str, register unsigned int len) { + Check_Type($input, T_STRING); + $1 = STR2CSTR($input); + $2 = RSTRING($input)->len; +}; + +%nodefaultctor SourceFile; +%immutable; +%include "../src/languages.h" +%include "../src/structs.h" +%mutable; + +%extend SourceFile { + void set_diskpath(const char *diskpath) { + ohcount_sourcefile_set_diskpath($self, diskpath); + } + void set_contents(const char *contents) { + ohcount_sourcefile_set_contents($self, contents); + } + char *get_contents() { + return ohcount_sourcefile_get_contents($self); + } + int contents_size() { + return ohcount_sourcefile_get_contents_size($self); + } + const char *get_language() { + return ohcount_sourcefile_get_language($self); + } + void parse() { + ohcount_sourcefile_parse($self); + } + ParsedLanguageList *get_parsed_language_list() { + return ohcount_sourcefile_get_parsed_language_list($self); + } + LicenseList *get_license_list() { + return ohcount_sourcefile_get_license_list($self); + } + LocList *get_loc_list() { + return ohcount_sourcefile_get_loc_list($self); + } + LocDeltaList *_diff(SourceFile *to) { + return ohcount_sourcefile_diff($self, to); + } + void set_filenames(VALUE filenames) { + int i, length = RARRAY(filenames)->len; + char **fnames = calloc(length + 1, sizeof(char *)); + VALUE *iter = RARRAY(filenames)->ptr; + for (i = 0; i < length; i++, iter++) + fnames[i] = STR2CSTR(*iter); + ohcount_sourcefile_set_filenames($self, fnames); + free(fnames); + } + SourceFile(const char *filepath, VALUE opt_hash=NULL) { + SourceFile *sourcefile = ohcount_sourcefile_new(filepath); + if (opt_hash) { + VALUE val; + val = rb_hash_aref(opt_hash, ID2SYM(rb_intern("contents"))); + if (val && rb_type(val) == T_STRING) + ohcount_sourcefile_set_contents(sourcefile, STR2CSTR(val)); + val = rb_hash_aref(opt_hash, ID2SYM(rb_intern("file_location"))); + if (val && rb_type(val) == T_STRING) + ohcount_sourcefile_set_diskpath(sourcefile, STR2CSTR(val)); + val = rb_hash_aref(opt_hash, ID2SYM(rb_intern("filenames"))); + if (val && rb_type(val) == T_ARRAY) + SourceFile_set_filenames(sourcefile, val); + } + return sourcefile; + } + ~SourceFile() { + ohcount_sourcefile_free($self); + } +}; + +%extend SourceFileList { + SourceFileList() { + return ohcount_sourcefile_list_new(); + } + ~SourceFileList() { + ohcount_sourcefile_list_free($self); + } + void add_file(const char *filepath) { + ohcount_sourcefile_list_add_file($self, filepath); + } + void add_directory(const char *directory) { + ohcount_sourcefile_list_add_directory($self, directory); + } +} + +int ohcount_is_binary_filename(const char *filename); + +struct LanguageMap *ohcount_hash_language_from_name(register const char *str, register unsigned int len); diff --git a/ruby/ohcount.rb b/ruby/ohcount.rb new file mode 100644 index 0000000..2d2ae6b --- /dev/null +++ b/ruby/ohcount.rb @@ -0,0 +1,77 @@ +# ohcount.rb written by Mitchell Foral. mitchellcaladbolg.net. +# See COPYING for license information. +# Ohcount module tweaked for use by Ohloh. + +$: << File.expand_path(File.dirname(__FILE__)) +require 'ohcount.so' + +module Ohcount + class SourceFile + def file_location=(value) set_diskpath(value) end + def file_location() diskpath() end + def filenames=(value) set_filenames(value) end + def contents() get_contents() end + def polyglot() get_language() end + + def language_breakdowns + list = get_parsed_language_list() + return array_from_list(list, :pl) + end + + def language_breakdown(language) + return language_breakdowns().find { |lb| lb.name == language.to_s } + end + + def licenses + list = get_license_list() + array = array_from_list(list, :lic) + return array.map! { |l| l.name } + end + + def languages + return language_breakdowns().collect { |lb| lb.name } + end + + def loc_list + list = get_loc_list() + return array_from_list(list, :loc) + end + + def diff(to) + list = _diff(to) + ret = array_from_list(list, :delta) + class << ret + def loc_deltas() self end + end + return ret + end + + private + + def array_from_list(list, method) + array = Array.new + iter = list.head + while (iter) + array << iter.send(method) + iter = iter.next + end + return array + end + end + + class SourceFileList + def each_source_file + iter = self.head + while (iter) + yield iter.sf if iter.sf.polyglot + iter = iter.next + end + end + end + + class Detector + def self.binary_filename?(filename) + return Ohcount.ohcount_is_binary_filename(filename) == 1 + end + end +end diff --git a/src/detector.c b/src/detector.c index 4e9b227..c8ff3b9 100644 --- a/src/detector.c +++ b/src/detector.c @@ -13,7 +13,6 @@ #include "hash/disambiguatefunc_hash.h" #include "hash/extension_hash.h" #include "hash/filename_hash.h" -#include "hash/language_hash.h" #define ISBINARY(x) (x[0] == '\1') #define ISAMBIGUOUS(x) (x[0] == '\2') @@ -89,7 +88,7 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { strncpy(buf, p, length); buf[length] = '\0'; struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); - if (rl) return rl->value; + if (rl) return rl->name; } // Attempt to detect based on Unix 'file' command. @@ -114,7 +113,7 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { strncpy(buf, p, length); buf[length] = '\0'; struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); - if (rl) language = rl->value; + if (rl) language = rl->name; } } else if (p) { // /(\w+)(?: -\w+)* script text/ do { @@ -128,7 +127,7 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { strncpy(buf, p, length); buf[length] = '\0'; struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); - if (rl) language = rl->value; + if (rl) language = rl->name; } else if (strstr(line, "xml")) language = LANG_XML; fclose(f); if (language) return language; @@ -631,3 +630,22 @@ const char *disambiguate_st(SourceFile *sourcefile) { return NULL; } + +int ohcount_is_binary_filename(const char *filename) { + char *p = (char *)filename + strlen(filename); + while (p > filename && *(p - 1) != '.') p--; + if (p > filename) { + struct ExtensionMap *re; + int length = strlen(p); + re = ohcount_hash_language_from_ext(p, length); + if (re) return ISBINARY(re->value); + // Try the lower-case version of this extension. + char lowerext[length]; + strncpy(lowerext, p, length); + lowerext[length] = '\0'; + for (p = lowerext; p < lowerext + length; p++) *p = tolower(*p); + re = ohcount_hash_language_from_ext(lowerext, length); + if (re) return ISBINARY(re->value); + } + return 0; +} diff --git a/src/detector.h b/src/detector.h index e63646c..53277b8 100644 --- a/src/detector.h +++ b/src/detector.h @@ -29,4 +29,6 @@ */ const char *ohcount_detect_language(SourceFile *sourcefile); +int ohcount_is_binary_filename(const char *filename); + #endif diff --git a/src/hash/generate_headers b/src/hash/generate_headers index 06fe011..679a8b3 100755 --- a/src/hash/generate_headers +++ b/src/hash/generate_headers @@ -1,6 +1,6 @@ #!/bin/sh -gperf -L ANSI-C -E -D -K key -H ohcount_hash_language -N ohcount_hash_language_from_name -t languages.gperf > language_hash.h +gperf -L ANSI-C -E -D -K key -H ohcount_hash_language -N ohcount_hash_language_from_name -t languages.gperf > language_hash.c gperf -L ANSI-C -E -D -K key -H ohcount_hash_extension -N ohcount_hash_language_from_ext -t extensions.gperf > extension_hash.h gperf -L ANSI-C -E -D -K key -H ohcount_hash_filename -N ohcount_hash_language_from_filename -t filenames.gperf > filename_hash.h gperf -L ANSI-C -E -D -K key -H ohcount_hash_disambiguatefunc -N ohcount_hash_disambiguate_func_from_id -t disambiguatefuncs.gperf > disambiguatefunc_hash.h diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index ca52eae..21dca50 100644 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -1,89 +1,84 @@ %{ -#ifndef OHCOUNT_HASH_LANGUAGE_HASH_H -#define OHCOUNT_HASH_LANGUAGE_HASH_H - #include "../languages.h" %} -struct LanguageMap { const char *key; const char *value; }; +struct LanguageMap; %% -actionscript, LANG_ACTIONSCRIPT -ada, LANG_ADA -assembler, LANG_ASSEMBLER -autoconf, LANG_AUTOCONF -automake, LANG_AUTOMAKE -awk, LANG_AWK -bat, LANG_BAT -blitzmax, LANG_BLITZMAX -boo, LANG_BOO -c, LANG_C -classic_basic, LANG_CLASSIC_BASIC -clearsilver, LANG_CLEARSILVER -clearsilver_template, LANG_CLEARSILVER_TEMPLATE -cpp, LANG_CPP -cs_aspx, LANG_CS_ASPX -csharp, LANG_CSHARP -css, LANG_CSS -dcl, LANG_DCL -dmd, LANG_DMD -dylan, LANG_DYLAN -ebuild, LANG_EBUILD -eiffel, LANG_EIFFEL -erlang, LANG_ERLANG -exheres, LANG_EXHERES -emacslisp, LANG_EMACSLISP -factor, LANG_FACTOR -fortranfixed, LANG_FORTRANFIXED -fortranfree, LANG_FORTRANFREE -glsl, LANG_GLSL -groovy, LANG_GROOVY -haskell, LANG_HASKELL -haml, LANG_HAML -haxe, LANG_HAXE -html, LANG_HTML -java, LANG_JAVA -javascript, LANG_JAVASCRIPT -jsp, LANG_JSP -limbo, LANG_LIMBO -lisp, LANG_LISP -lua, LANG_LUA -make, LANG_MAKE -matlab, LANG_MATLAB -metafont, LANG_METAFONT -metapost, LANG_METAPOST -metapost_with_tex, LANG_METAPOST_WITH_TEX -mxml, LANG_MXML -nix, LANG_NIX -objective_c, LANG_OBJECTIVE_C -objective_j, LANG_OBJECTIVE_J -ocaml, LANG_OCAML -octave, LANG_OCTAVE -pascal, LANG_PASCAL -perl, LANG_PERL -php, LANG_PHP -pike, LANG_PIKE -python, LANG_PYTHON -r, LANG_R -rexx, LANG_REXX -rhtml, LANG_RHTML -ruby, LANG_RUBY -scala, LANG_SCALA -scheme, LANG_SCHEME -scilab, LANG_SCILAB -shell, LANG_SHELL -smalltalk, LANG_SMALLTALK -stratego, LANG_STRATEGO -structured_basic, LANG_STRUCTURED_BASIC -sql, LANG_SQL -tcl, LANG_TCL -tex, LANG_TEX -vala, LANG_VALA -vb_aspx, LANG_VB_ASPX -vhdl, LANG_VHDL -vim, LANG_VIM -visualbasic, LANG_VISUALBASIC -xaml, LANG_XAML -xml, LANG_XML -xslt, LANG_XSLT -xmlschema, LANG_XMLSCHEMA -%% -#endif +actionscript, LANG_ACTIONSCRIPT, "ActionScript", 0 +ada, LANG_ADA, "Ada", 0 +assembler, LANG_ASSEMBLER, "Assembler", 0 +autoconf, LANG_AUTOCONF, "Autoconf", 2 +automake, LANG_AUTOMAKE, "Automake", 2 +awk, LANG_AWK, "AWK", 0 +bat, LANG_BAT, "DOS batch script", 0 +blitzmax, LANG_BLITZMAX, "BlitzMax", 0 +boo, LANG_BOO, "Boo", 0 +c, LANG_C, "C", 0 +classic_basic, LANG_CLASSIC_BASIC, "Classic Basic", 0 +clearsilver, LANG_CLEARSILVER, "Cmake script", 2 +clearsilver_template, LANG_CLEARSILVER_TEMPLATE, "ClearSilver", 0 +cpp, LANG_CPP, "C++", 0 +cs_aspx, LANG_CS_ASPX, "", 0 +csharp, LANG_CSHARP, "C#", 0 +css, LANG_CSS, "CSS", 1 +dcl, LANG_DCL, "DCL", 0 +dmd, LANG_DMD, "D", 0 +dylan, LANG_DYLAN, "Dylan", 0 +ebuild, LANG_EBUILD, "Ebuild", 0 +eiffel, LANG_EIFFEL, "Eiffel", 0 +emacslisp, LANG_EMACSLISP, "Emacs lisp", 0 +erlang, LANG_ERLANG, "Erlang", 0 +exheres, LANG_EXHERES, "Exheres", 0 +factor, LANG_FACTOR, "Factor", 0 +fortranfixed, LANG_FORTRANFIXED, "Fortan (Fixed-format)", 0 +fortranfree, LANG_FORTRANFREE, "Fortan (Free-format)", 0 +glsl, LANG_GLSL, "OpenGL Shading Language", 0 +groovy, LANG_GROOVY, "Groovy", 0 +haml, LANG_HAML, "Haml", 1 +haskell, LANG_HASKELL, "Haskell", 0 +haxe, LANG_HAXE, "HaXe", 0 +html, LANG_HTML, "HTML", 1 +java, LANG_JAVA, "Java", 0 +javascript, LANG_JAVASCRIPT, "JavaScript", 0 +jsp, LANG_JSP, "", 0 +limbo, LANG_LIMBO, "Limbo", 0 +lisp, LANG_LISP, "Lisp", 0 +lua, LANG_LUA, "Lua", 0 +make, LANG_MAKE, "Make", 2 +matlab, LANG_MATLAB, "Matlab", 0 +metafont, LANG_METAFONT, "MetaFont", 1 +metapost, LANG_METAPOST, "MetaPost", 1 +metapost_with_tex, LANG_METAPOST_WITH_TEX, "", 0 +mxml, LANG_MXML, "Flex", 1 +nix, LANG_NIX, "Nix", 0 +objective_c, LANG_OBJECTIVE_C, "Objective C", 0 +objective_j, LANG_OBJECTIVE_J, "Objective-J", 0 +ocaml, LANG_OCAML, "Objective Caml", 0 +octave, LANG_OCTAVE, "", 0 +pascal, LANG_PASCAL, "Pascal", 0 +perl, LANG_PERL, "Perl", 0 +php, LANG_PHP, "PHP", 0 +pike, LANG_PIKE, "Pike", 0 +python, LANG_PYTHON, "Python", 0 +r, LANG_R, "R", 0 +rexx, LANG_REXX, "rexx", 0 +rhtml, LANG_RHTML, "", 0 +ruby, LANG_RUBY, "Ruby", 0 +scala, LANG_SCALA, "Scala", 0 +scheme, LANG_SCHEME, "Scheme", 0 +scilab, LANG_SCILAB, "Scilab", 0 +shell, LANG_SHELL, "shell script", 0 +smalltalk, LANG_SMALLTALK, "Smalltalk", 0 +stratego, LANG_STRATEGO, "Stratego", 0 +structured_basic, LANG_STRUCTURED_BASIC, "Structured Basic", 0 +sql, LANG_SQL, "SQL", 0 +tcl, LANG_TCL, "TCL", 0 +tex, LANG_TEX, "TeX/LaTeX", 1 +vala, LANG_VALA, "Vala", 0 +vb_aspx, LANG_VB_ASPX, "", 0 +vhdl, LANG_VHDL, "VHDL", 0 +vim, LANG_VIM, "Vim script", 0 +visualbasic, LANG_VISUALBASIC, "Visual Basic", 0 +xaml, LANG_XAML, "XAML", 1 +xml, LANG_XML, "XML", 1 +xslt, LANG_XSLT, "XSL Transformation", 0 +xmlschema, LANG_XMLSCHEMA, "XML Schema", 1 diff --git a/src/languages.h b/src/languages.h index 0a3a569..4088c80 100644 --- a/src/languages.h +++ b/src/languages.h @@ -4,6 +4,8 @@ #ifndef OHCOUNT_LANGUAGES_H #define OHCOUNT_LANGUAGES_H +#include + #define LANG_ACTIONSCRIPT "actionscript" #define LANG_ADA "ada" #define LANG_ASSEMBLER "assembler" @@ -85,4 +87,8 @@ #define LANG_XSLT "xslt" #define LANG_XMLSCHEMA "xmlschema" +// For gperf. +struct LanguageMap { const char *key; const char *name; const char *nice_name; int category; }; +struct LanguageMap *ohcount_hash_language_from_name(register const char *str, register unsigned int len); + #endif diff --git a/src/sourcefile.c b/src/sourcefile.c index 18f40eb..8b2d114 100644 --- a/src/sourcefile.c +++ b/src/sourcefile.c @@ -8,6 +8,7 @@ #include "detector.h" #include "diff.h" +#include "languages.h" #include "licenses.h" #include "parser.h" @@ -104,8 +105,12 @@ int ohcount_sourcefile_get_contents_size(SourceFile *sourcefile) { void ohcount_sourcefile_set_language(SourceFile *sourcefile, const char *language) { - sourcefile->language = language; - sourcefile->language_detected = 1; + struct LanguageMap *rl = + ohcount_hash_language_from_name(language, strlen(language)); + if (rl) { + sourcefile->language = rl->name; + sourcefile->language_detected = 1; + } } const char *ohcount_sourcefile_get_language(SourceFile *sourcefile) { @@ -431,6 +436,7 @@ void ohcount_sourcefile_list_add_directory(SourceFileList *list, ohcount_sourcefile_list_add_file(list, filepath); } closedir(d); + ohcount_sourcefile_list_add_file(list, directory); } } diff --git a/src/sourcefile.h b/src/sourcefile.h index fef6a6b..0d63ab1 100644 --- a/src/sourcefile.h +++ b/src/sourcefile.h @@ -51,8 +51,7 @@ int ohcount_sourcefile_get_contents_size(SourceFile *sourcefile); /** * Sets the language of a given SourceFile. - * The given language is not copied and may not be 'free'd. Use a language - * defined in src/languages.h. + * The given language copied and may be 'free'd immediately. * @param sourcefile A SourceFile created by ohcount_sourcefile_new(). * @param language The language to set the SourceFile to. */ From 24f478c5d3e6d61275e7ab7104ea1a7ed36d2000 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 24 May 2009 00:56:53 -0400 Subject: [PATCH 154/387] Removed hash header include guards; they're unnecessary. --- src/hash/cppheaders.gperf | 6 ------ src/hash/disambiguatefuncs.gperf | 5 ----- src/hash/extensions.gperf | 5 ----- src/hash/filenames.gperf | 5 ----- src/hash/options.gperf | 5 ----- src/hash/parsers.gperf | 5 ----- 6 files changed, 31 deletions(-) diff --git a/src/hash/cppheaders.gperf b/src/hash/cppheaders.gperf index 4d94ccf..3a70930 100644 --- a/src/hash/cppheaders.gperf +++ b/src/hash/cppheaders.gperf @@ -1,7 +1,3 @@ -%{ -#ifndef OHCOUNT_HASH_CPPHEADERS_HASH_H -#define OHCOUNT_HASH_CPPHEADERS_HASH_H -%} struct CppHeaderMap { const char *key; int value; }; %% algorithm, 1 @@ -93,5 +89,3 @@ tr1/type_traits, 1 tr1/unordered_map, 1 tr1/unordered_set, 1 tr1/utility, 1 -%% -#endif diff --git a/src/hash/disambiguatefuncs.gperf b/src/hash/disambiguatefuncs.gperf index 3f6ac3d..1bd1a6b 100644 --- a/src/hash/disambiguatefuncs.gperf +++ b/src/hash/disambiguatefuncs.gperf @@ -1,7 +1,4 @@ %{ -#ifndef OHCOUNT_HASH_DISAMBIGUATEFUNCS_HASH_H -#define OHCOUNT_HASH_DISAMBIGUATEFUNCS_HASH_H - #include "../detector.h" #include "../sourcefile.h" @@ -28,5 +25,3 @@ in, disambiguate_in inc, disambiguate_inc m, disambiguate_m st, disambiguate_st -%% -#endif diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index 0d30807..45d7e25 100644 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -1,7 +1,4 @@ %{ -#ifndef OHCOUNT_HASH_EXTENSIONS_HASH_H -#define OHCOUNT_HASH_EXTENSIONS_HASH_H - #include "../languages.h" #define BINARY "\1" @@ -178,5 +175,3 @@ xsd, LANG_XMLSCHEMA xsl, LANG_XSLT z80, LANG_ASSEMBLER zip, BINARY -%% -#endif diff --git a/src/hash/filenames.gperf b/src/hash/filenames.gperf index 279e934..54b1685 100644 --- a/src/hash/filenames.gperf +++ b/src/hash/filenames.gperf @@ -1,7 +1,4 @@ %{ -#ifndef OHCOUNT_HASH_FILENAMES_HASH_H -#define OHCOUNT_HASH_FILENAMES_HASH_H - #include "../languages.h" %} struct FilenameMap { const char *key; const char *value; }; @@ -14,5 +11,3 @@ configure, LANG_AUTOCONF configure.ac, LANG_AUTOCONF configure.in, LANG_AUTOCONF makefile, LANG_MAKE -%% -#endif diff --git a/src/hash/options.gperf b/src/hash/options.gperf index 04d176f..4df3769 100644 --- a/src/hash/options.gperf +++ b/src/hash/options.gperf @@ -1,7 +1,4 @@ %{ -#ifndef OHCOUNT_HASH_OPTIONS_HASH_H -#define OHCOUNT_HASH_OPTIONS_HASH_H - #include "../ohcount.h" %} struct OhcountOption { const char *key; int value; }; @@ -21,5 +18,3 @@ struct OhcountOption { const char *key; int value; }; -re, COMMAND_RAWENTITIES -s, COMMAND_SUMMARY --summary, COMMAND_SUMMARY -%% -#endif diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index 6579c7d..a16792c 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -1,7 +1,4 @@ %{ -#ifndef OHCOUNT_HASH_PARSERS_HASH_H -#define OHCOUNT_HASH_PARSERS_HASH_H - #include "../parsers/actionscript.h" #include "../parsers/ada.h" #include "../parsers/assembler.h" @@ -160,5 +157,3 @@ xaml, parse_xaml xml, parse_xml xslt, parse_xslt xmlschema, parse_xmlschema -%% -#endif From ef27f84fe0797db42902d1f65995fd73a58ae8d1 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 24 May 2009 00:59:03 -0400 Subject: [PATCH 155/387] Added gestalts. --- .gitignore | 3 + ruby/gestalt.rb | 40 +++++ ruby/gestalt/base.rb | 37 +++++ ruby/gestalt/definition.rb | 72 ++++++++ ruby/gestalt/definitions.rb | 235 ++++++++++++++++++++++++++ ruby/gestalt/gestalt_engine.rb | 129 +++++++++++++++ ruby/gestalt/gestalt_facts.rb | 68 ++++++++ ruby/gestalt/rules/and_rule.rb | 16 ++ ruby/gestalt/rules/c_header_rule.rb | 31 ++++ ruby/gestalt/rules/c_keyword_rule.rb | 18 ++ ruby/gestalt/rules/file_rule.rb | 53 ++++++ ruby/gestalt/rules/filename_rule.rb | 25 +++ ruby/gestalt/rules/find_filenames_rule.rb | 33 ++++ ruby/gestalt/rules/find_java_imports_rule.rb | 47 ++++++ ruby/gestalt/rules/gestalt_rule.rb | 22 +++ ruby/gestalt/rules/java_import_rule.rb | 28 ++++ ruby/gestalt/rules/keyword_rule.rb | 36 ++++ ruby/gestalt/rules/language_rule.rb | 26 +++ ruby/gestalt/rules/logical_rule.rb | 80 +++++++++ ruby/gestalt/rules/or_rule.rb | 14 ++ ruby/gestalt/rules/rule.rb | 47 ++++++ ruby/gestalt/rules/xml_keyword_rule.rb | 15 ++ ruby/gestalt/trigger.rb | 13 ++ test/unit/gestalt/definitions_test.rb | 238 +++++++++++++++++++++++++++ test/unit/gestalt/file_rule_test.rb | 54 ++++++ test/unit/gestalt/filename_rule_test.rb | 19 +++ test/unit/gestalt/keyword_rule_test.rb | 20 +++ test/unit/gestalt/rule_test.rb | 11 ++ 28 files changed, 1430 insertions(+) create mode 100644 ruby/gestalt.rb create mode 100644 ruby/gestalt/base.rb create mode 100644 ruby/gestalt/definition.rb create mode 100644 ruby/gestalt/definitions.rb create mode 100644 ruby/gestalt/gestalt_engine.rb create mode 100644 ruby/gestalt/gestalt_facts.rb create mode 100644 ruby/gestalt/rules/and_rule.rb create mode 100644 ruby/gestalt/rules/c_header_rule.rb create mode 100644 ruby/gestalt/rules/c_keyword_rule.rb create mode 100644 ruby/gestalt/rules/file_rule.rb create mode 100644 ruby/gestalt/rules/filename_rule.rb create mode 100644 ruby/gestalt/rules/find_filenames_rule.rb create mode 100644 ruby/gestalt/rules/find_java_imports_rule.rb create mode 100644 ruby/gestalt/rules/gestalt_rule.rb create mode 100644 ruby/gestalt/rules/java_import_rule.rb create mode 100644 ruby/gestalt/rules/keyword_rule.rb create mode 100644 ruby/gestalt/rules/language_rule.rb create mode 100644 ruby/gestalt/rules/logical_rule.rb create mode 100644 ruby/gestalt/rules/or_rule.rb create mode 100644 ruby/gestalt/rules/rule.rb create mode 100644 ruby/gestalt/rules/xml_keyword_rule.rb create mode 100644 ruby/gestalt/trigger.rb create mode 100644 test/unit/gestalt/definitions_test.rb create mode 100644 test/unit/gestalt/file_rule_test.rb create mode 100644 test/unit/gestalt/filename_rule_test.rb create mode 100644 test/unit/gestalt/keyword_rule_test.rb create mode 100644 test/unit/gestalt/rule_test.rb diff --git a/.gitignore b/.gitignore index 71062be..bd77c61 100644 --- a/.gitignore +++ b/.gitignore @@ -5,8 +5,11 @@ lib/x86* tags .DS_Store src/hash/*_hash.h +src/hash/language_hash.c src/parsers/*.h src/parser.o test/unit/run_tests doc/html bin/ +ruby/ohcount.so +ruby/ohcount_wrap.c diff --git a/ruby/gestalt.rb b/ruby/gestalt.rb new file mode 100644 index 0000000..3aad661 --- /dev/null +++ b/ruby/gestalt.rb @@ -0,0 +1,40 @@ +# gestalt.rb written by Mitchell Foral. mitchellcaladbolg.net. +# See COPYING for license information. +# Ohcount module tweaked for use by Gestalts. + +$: << File.expand_path(File.dirname(__FILE__)) +require "ohcount" + +# gestalt +require "gestalt/trigger" +require "gestalt/definition" +require "gestalt/base" +require "gestalt/definitions" +require "gestalt/gestalt_engine" + +module Ohcount + class SourceFile + def gestalts + gestalt_engine = Gestalt::GestaltEngine.new + gestalt_engine.process(self) + gestalt_engine.calc_gestalts + gestalt_engine.gestalts + end + end + + class SourceFileList + def analyze_gestalt + @gestalt_engine = Gestalt::GestaltEngine.new + iter = self.head + while (iter) + @gestalt_engine.process(iter.sf) + iter = iter.next + end + @gestalt_engine.calc_gestalts + end + + def gestalts + @gestalt_engine.gestalts if @gestalt_engine + end + end +end diff --git a/ruby/gestalt/base.rb b/ruby/gestalt/base.rb new file mode 100644 index 0000000..7584c17 --- /dev/null +++ b/ruby/gestalt/base.rb @@ -0,0 +1,37 @@ +module Ohcount + module Gestalt + + class Base + attr_reader :type, :name, :count + + def initialize(type, name, count = 1) + @type = type + @name = name + @count = count + end + + def ==(other) + other.type.to_s == self.type.to_s && + other.name == self.name && + other.count == self.count + end + + def <=>(other) + # Sort by type, then descending count, then name + if self.type != other.type + self.type.to_s <=> other.type.to_s + elsif self.count != other.count + -(self.count <=> other.count) + else + self.name.to_s <=> other.name.to_s + end + end + + # will return an array of detected gestalts from a source_file_list + def self.find_gestalts(source_file_list) + GestaltEngine.new.process(source_file_list).gestalts + end + + end + end +end diff --git a/ruby/gestalt/definition.rb b/ruby/gestalt/definition.rb new file mode 100644 index 0000000..b6d0bcc --- /dev/null +++ b/ruby/gestalt/definition.rb @@ -0,0 +1,72 @@ +require 'gestalt/rules/rule' +require 'gestalt/rules/logical_rule' +require 'gestalt/rules/or_rule' +require 'gestalt/rules/and_rule' +require 'gestalt/rules/language_rule' +require 'gestalt/rules/file_rule' +require 'gestalt/rules/filename_rule' +require 'gestalt/rules/find_filenames_rule' +require 'gestalt/rules/c_header_rule' +require 'gestalt/rules/keyword_rule' +require 'gestalt/rules/c_keyword_rule' +require 'gestalt/rules/gestalt_rule' +require 'gestalt/rules/java_import_rule' +require 'gestalt/rules/find_java_imports_rule' + +module Ohcount + module Gestalt + + class Definition + attr_reader :type, :fixed_name + + def initialize(type, fixed_name = nil, options = {}, &block) + @type = type + @fixed_name = fixed_name + if options[:rule] + @top_level_or = options[:rule] + else + @top_level_or = OrRule.new(&block) + end + end + + def gestalts(gestalt_engine) + @top_level_or.triggers(gestalt_engine).map do |trigger| + Gestalt::Base.new(type, trigger.name || self.fixed_name, trigger.count) + end + end + + def top_level_or + @top_level_or ||= OrRule.new + end + + def self.add_definition(definition) + @definitions ||= [] + @definitions << definition + end + + def self.all_definitions + @definitions || [] + end + + def clone + rule = top_level_or.clone + Definition.new(type,fixed_name,:rule => rule) + end + end + + + # DSL language to allow people to define gestalt definitions like this:\ + # + # define_xxx 'Foobar' do + # filenames 'foobar' + # end + # + def self.method_missing(method, *args, &block) + if method.to_s =~ /define_(.*)$/ + Definition.add_definition(Definition.new($1.intern,*args,&block)) + else + super + end + end + end +end diff --git a/ruby/gestalt/definitions.rb b/ruby/gestalt/definitions.rb new file mode 100644 index 0000000..37fe678 --- /dev/null +++ b/ruby/gestalt/definitions.rb @@ -0,0 +1,235 @@ +module Ohcount + module Gestalt + + + ############################# Platforms ############################# + # # + # Platforms is used in the most general sense of the word. We don't # + # discriminate between OS-platforms and a lightweight framework - # + # any type of dependency is fair game. # + # # + # What guides what we add here is mostly for internal Ohloh # + # purposes. # + # # + ##################################################################### + + define_platform 'POSIX' do + # gnu_lib && generic + c_headers 'pthread.h', 'xstrtol.h', 'xreadlink.h', 'fatal-signal.h', 'diacrit.h', 'syslog.h', 'sys/stat.h' + + # autoconf means m4 (unix macro processor) + language :autoconf + end + + define_platform 'Win32' do + c_headers 'windows.h' + c_keywords 'WM_PAINT', 'ReleaseDC', 'WndProc', :min => 2 + end + + define_platform 'WPF' do + filenames '\.xaml$' + end + + define_platform 'Dot_NET' do + language :csharp, :min_percent => 10 + end + + define_platform 'VisualBasic' do + language :visualbasic, :min_percent => 5 + end + + define_platform 'ASP_NET' do + filenames('\.(aspx|ascx|ashx|asax|axd)$') + end + + define_platform 'Ruby' do + language :ruby, :min_percent => 15 + end + + define_platform 'Rails' do + _and do + gestalt(:platform, 'Ruby') + ruby_keywords("RAILS_ROOT") + end + end + + define_platform 'Java' do + language :java, :min_percent => 15 + end + + define_platform 'Javascript' do + language :javascript, :min_percent => 20 + end + + define_platform 'JQuery' do + filenames 'jquery-\d.\d.\d.min.js' + end + + define_platform 'SpringFramework' do + _and do + gestalt(:platform,'Java') + filenames('spring\.jar$') + end + end + + define_platform 'XWindows' do + c_headers 'Xlib.h', 'X11\/xpm.h', 'X11/Xlib.h' + end + + define_platform 'Mac' do + # apple events + c_keywords 'AppleEvent', 'AEBuildAppleEvent' + + # plist is a mac thing, right? + filenames '\.plist' + end + + define_platform 'PHP' do + language :php, :min_percent => 15 + end + + define_platform 'WxWidgets' do + c_headers 'wx/window.h' + end + + define_platform 'ZendFramework' do + _and do + gestalt(:platform, 'PHP') + php_keywords('Zend_Controller_Action') + end + end + + define_platform 'Symfony' do + _and do + gestalt(:platform, 'PHP') + php_keywords('sfCore', 'sfConfig') + end + end + + define_platform 'Pear' do + _and do + gestalt(:platform, 'PHP') + _or do + filenames('\bpackage\.xml(\.tpl)?$') + xml_keywords('pear.php.net/dtd/package-2.0') + end + end + end + + define_platform 'Moodle' do + _and do + gestalt(:platform, 'PHP') + php_keywords("moodle") + end + end + + define_platform 'SQL' do + language :sql + end + + define_platform 'MySQL' do + php_keywords('mysql_connect') + end + + define_platform 'PostgreSQL' do + php_keywords('pg_connect') + end + + define_platform 'Python' do + language :python, :min_percent => 15 + end + + define_platform 'Perl' do + language :perl, :min_percent => 20 + end + + define_platform 'Scripting' do + gestalt(:platform, 'Javascript') + gestalt(:platform, 'Perl') + gestalt(:platform, 'PHP') + gestalt(:platform, 'Python') + gestalt(:platform, 'Ruby') + end + + define_platform 'CakePHP' do + _and do + gestalt(:platform, 'PHP') + php_keywords('CAKE_CORE_INCLUDE_PATH') + end + end + + define_platform 'KDE' do + c_headers 'KDEInit.h', 'kdeversion.h' + end + + define_platform 'GTK' do + c_keywords 'gtk_init', 'gtk_main', 'gtk_window_new', 'GtkWidget' + end + + define_platform 'Drupal' do + _and do + gestalt(:platform, 'PHP') + _or do + php_keywords('drupal_set_message') + php_keywords('drupal_render') + php_keywords('Drupal', :min => 3) + end + end + end + + define_platform 'MSDos' do + c_keywords '__MSDOS__', 'MSDOS', :min => 2 + end + + define_platform 'EclipsePlatform' do + java_import /org\.eclipse\./ + end + + + ############################### Tools ############################### + + define_tool 'VisualStudio' do + filenames '\.(sln|vcproj|vsproj|csproj|vbproj|vbp)$' + end + + define_tool 'Eclipse' do + filenames '\.(project|classpath)$' + end + + define_tool 'NetBeans' do + filenames '\bnbplatform\b' + filenames '\.nbm$' + end + + + ########################## Java Jars ############################### + + define_java_jar do + find_filenames /([^\\^\/]*\.(jar|JAR))/, :name_from_match => 1 + end + + + ######################## Java Imports ############################## + + define_java_import do + find_java_imports + end + + + ############################ ARM ################################### + + define_platform 'arm' do + makefile_keywords '\b-mabi\b','\barmcc\b' + assembler_keywords '\bsmlal\b', '\bsmulw\b', '\borrs\b' + gestalt(:platform, 'arm_neon') + end + + ########################## ARM NEON ################################ + + define_platform 'arm_neon' do + assembler_keywords '\bvld1.\d\d\b', '\bvld1.\d\d\b','\bvmov\b','\bvmov.u8\b' + makefile_keywords '\bneon\b','\bNEON\b' + end + + end +end diff --git a/ruby/gestalt/gestalt_engine.rb b/ruby/gestalt/gestalt_engine.rb new file mode 100644 index 0000000..2ccd6b4 --- /dev/null +++ b/ruby/gestalt/gestalt_engine.rb @@ -0,0 +1,129 @@ +module Ohcount + module Gestalt + + # smells is a general class that aggregates facts required to deduce + # gestalts + class GestaltEngine + attr_reader :gestalts + + def initialize + @language_facts = LanguageFacts.new + @gestalts = [] + @source_file_rules = [] + @definitions = Definition.all_definitions.map do |d| + new_definition = d.clone + new_definition.top_level_or.each_rule do |r| + @source_file_rules << r if r.is_a?(FileRule) + end + new_definition + end + end + + def process_source_file(source_file) + @source_file_rules.each do |r| + r.process_source_file(source_file) + end + @language_facts.process_source_file(source_file) + end + + def process_source_files(source_file_list) + source_file_list.each_source_file do |source_file| + process_source_file source_file + end + self + end + + def process(what) + if what.is_a?(SourceFile) + process_source_file(what) + elsif what.is_a?(SourceFileList) + process_source_file_list(what) + else + raise ArgumentError.new + end + end + + def calc_gestalts(definitions = nil) + # since gestalts can depend on other gestalts, we perform an + # iterative process and break when no new gestalts have been + # detected. + gestalt_count = 0 + + while true do + + # collect what we can + yank_definitions = [] + @definitions.each do |d| + + new_gestalts = d.gestalts(self) + if new_gestalts.any? + yank_definitions << d + @gestalts += new_gestalts + end + end + @definitions -= yank_definitions + + # did we make any progress? + break if gestalt_count == @gestalts.size + + # nope, keep going + gestalt_count = @gestalts.size + end + + gestalts + end + + def has_gestalt?(type,name) + @gestalts.find do |g| + g.type.to_s == type.to_s && + g.name == name + end + end + + def includes_language?(language, min_percent) + @language_facts.includes_language?(language,min_percent) + end + end + + + # keeps track of languages seen + class LanguageFacts + + def initialize + @language_counts ||= {} + end + + def process_source_file(source_file) + source_file.language_breakdowns.each do |lb| + @language_counts[lb.name.intern] ||= 0 + @language_counts[lb.name.intern] += lb.code_count + end + end + + def includes_language?(language, min_percent = 0) + return false unless @language_counts[language] + language_percents[language] >= min_percent + end + + # ignores markup languages (xml/html) + def language_percents + @language_percents ||= begin + total = 0 + @language_counts.each do |name,code_count| + next if Ohcount.ohcount_hash_language_from_name(name.to_s).category == 1 + total += code_count + end + + l = {} + @language_counts.each do |k,v| + l[k] = 100.0 * v.to_i / total + end + l + + end + end + end + + end +end + diff --git a/ruby/gestalt/gestalt_facts.rb b/ruby/gestalt/gestalt_facts.rb new file mode 100644 index 0000000..154860b --- /dev/null +++ b/ruby/gestalt/gestalt_facts.rb @@ -0,0 +1,68 @@ +module Ohcount + + # Represents language statistics for a collection of files + class GestaltFacts + attr_accessor :platforms, :tools, :file_rules, :language_counts + + def initialize + @platforms = [] + @tools = [] + @file_rules = {} + @language_counts = {} + end + + def process(source_file) + Gestalt::FileRule.rules_triggered_by(source_file).each do |r| + @file_rules[r] ||= 0 + @file_rules[r] += 1 + end + source_file.language_breakdowns.each do |lb| + @language_counts[lb.name.intern] ||= 0 + @language_counts[lb.name.intern] += lb.code_count + end + end + + def post_process + # since platforms can depend on other platforms, + # we perform an iterative process and break when + # no new platforms have been detected. + while true do + prev_platforms = self.platforms.clone + uninfered_platforms.each do |p| + platforms << p if p.triggered?(self) + end + prev_tools = self.tools.clone + uninfered_tools.each do |t| + tools << t if t.triggered?(self) + end + break if prev_platforms == self.platforms && prev_tools == self.tools + end + end + + def uninfered_platforms #:nodoc: + Gestalt::Platform.descendants - @platforms + end + + def uninfered_tools #:nodoc: + Gestalt::Tool.descendants - @tools + end + + def includes_language?(language, min_percent = 0) + return false unless language_counts[language] + language_percents[language] >= min_percent + end + + def language_percents + @language_percents ||= begin + total = language_counts.values.inject(0) { |s,c| s+c } + l = {} + language_counts.each do |k,v| + l[k] = 100.0 * v.to_i / total + end + l + end + end + + end +end + diff --git a/ruby/gestalt/rules/and_rule.rb b/ruby/gestalt/rules/and_rule.rb new file mode 100644 index 0000000..c631519 --- /dev/null +++ b/ruby/gestalt/rules/and_rule.rb @@ -0,0 +1,16 @@ +module Ohcount + module Gestalt + # Will trigger if all sub-rules do + class AndRule < LogicalRule + + def triggers(gestalt_engine) + rules.each do |r| + return [] if r.triggers(gestalt_engine).empty? + end + [Trigger.new] + end + end + end +end + + diff --git a/ruby/gestalt/rules/c_header_rule.rb b/ruby/gestalt/rules/c_header_rule.rb new file mode 100644 index 0000000..fbbb630 --- /dev/null +++ b/ruby/gestalt/rules/c_header_rule.rb @@ -0,0 +1,31 @@ +module Ohcount + module Gestalt + # Triggers if a c or cpp header is present + class CHeaderRule < FileRule + attr_reader :headers + + def initialize(*args) + options = args.pop if args.last.is_a?(Hash) + @headers = args + super(options) + end + + def process_source_file(source_file) + return unless ['c','cpp'].include?(source_file.polyglot) + + ['c','cpp'].each do |lang| + next unless source_file.language_breakdown(lang) + md = regexp.match(source_file.language_breakdown(lang).code) + @count += (md && md.size).to_i + end + end + + def regexp + @regexp ||= begin + header_term = "(" + headers.join("|") + ")" + Regexp.new("include\s+['<\"]#{ header_term }[\">']", Regexp::IGNORECASE) + end + end + end + end +end diff --git a/ruby/gestalt/rules/c_keyword_rule.rb b/ruby/gestalt/rules/c_keyword_rule.rb new file mode 100644 index 0000000..bbad838 --- /dev/null +++ b/ruby/gestalt/rules/c_keyword_rule.rb @@ -0,0 +1,18 @@ +module Ohcount + module Gestalt + class CKeywordRule < KeywordRule + + def initialize(*keywords) + super('c',*keywords) + end + + def process_source_file(source_file) + if source_file.language_breakdown('c') + @count += source_file.language_breakdown('c').code.scan(regexp).size + elsif source_file.language_breakdown('cpp') + @count += source_file.language_breakdown('cpp').code.scan(regexp).size + end + end + end + end +end diff --git a/ruby/gestalt/rules/file_rule.rb b/ruby/gestalt/rules/file_rule.rb new file mode 100644 index 0000000..821679e --- /dev/null +++ b/ruby/gestalt/rules/file_rule.rb @@ -0,0 +1,53 @@ +module Ohcount + module Gestalt + # an abstract base class representing a rule based + # on an individual file's attribute (like + # code content, or filename, etc..) + class FileRule < Rule + attr_reader :min_count, :count + + def initialize(args = {}) + args ||= {} + @min_count = 1 + @count = 0 + @triggers = [] + args.each do |k,v| + case k + when :min then @min_count = v + else raise ArgumentError.new("Unrecognized option: #{ k.inspect }") + end + end + FileRule.add_instance(self) + end + + # default implementation - will yield a single trigger if appropriate + def triggers(gestalt_engine) + if triggered? + [Trigger.new] + else + [] + end + end + + def self.process_source_file(source_file) + instances.each do |rule| + next if rule.triggered? + rule.process_source_file(source_file) + end + end + + def self.instances + @instances ||= [] + end + + def self.add_instance(r) + instances << r + end + + def triggered? + @count >= @min_count + end + + end + end +end diff --git a/ruby/gestalt/rules/filename_rule.rb b/ruby/gestalt/rules/filename_rule.rb new file mode 100644 index 0000000..8f14e13 --- /dev/null +++ b/ruby/gestalt/rules/filename_rule.rb @@ -0,0 +1,25 @@ +module Ohcount + module Gestalt + # rule based a the name of the file + class FilenameRule < FileRule + attr_reader :filenames + + def initialize(*args) + options = args.pop if args.last.is_a?(Hash) + @filenames = args + super(options) + end + + def process_source_file(source_file) + @count += 1 if regex.match(source_file.filename) + end + + def regex + @regex ||= begin + r = filenames.collect { |f| "(" + f + ")"}.join("|") + Regexp.new(r) + end + end + end + end +end diff --git a/ruby/gestalt/rules/find_filenames_rule.rb b/ruby/gestalt/rules/find_filenames_rule.rb new file mode 100644 index 0000000..d05c488 --- /dev/null +++ b/ruby/gestalt/rules/find_filenames_rule.rb @@ -0,0 +1,33 @@ +module Ohcount + module Gestalt + + # will yield as many triggers as files that match the regexp + class FindFilenamesRule < FileRule + attr_reader :regex + + def initialize(regex, options = {}) + @regex = regex + @triggers = [] + @name_from_match = options.delete(:name_from_match).to_i + super(options) + end + + # deep clone + def clone + self.class.new(@regex,:name_from_match => @name_from_match) + end + + def triggers(gestalt_engine) + @triggers + end + + def process_source_file(source_file) + m = @regex.match(source_file.filename) + if m + @triggers << Trigger.new(:name => m[@name_from_match]) + end + end + + end + end +end diff --git a/ruby/gestalt/rules/find_java_imports_rule.rb b/ruby/gestalt/rules/find_java_imports_rule.rb new file mode 100644 index 0000000..818b379 --- /dev/null +++ b/ruby/gestalt/rules/find_java_imports_rule.rb @@ -0,0 +1,47 @@ +module Ohcount + module Gestalt + + # Will yield one trigger per java import - each with the name of the imported + # namespace. Example java source file: + # + # import com.foo.bar; + # + # will yield a trigger with name='com.foo.bar' + class FindJavaImportsRule < FileRule + attr_reader :keywords, :language + + def initialize(*args) + @trigger_hash = {} + super(*args) + end + + def process_source_file(source_file) + return unless source_file.language_breakdown('java') + + java_code = source_file.language_breakdown('java').code + java_code.scan(import_regexp).each do |matches| + name = matches[0] + @trigger_hash[name] = @trigger_hash[name].to_i + 1 + end + end + + # implement deep clone + def clone + self.class.new(:min => @min_count) + end + + def triggers(gestalt_engine) + triggers = [] + @trigger_hash.each do |k,v| + triggers << Trigger.new(:name => k, :count => v) + end + triggers + end + + def import_regexp + /\bimport\s+([a-zA-Z][\w\.\*\-]*)/ + end + + end + end +end diff --git a/ruby/gestalt/rules/gestalt_rule.rb b/ruby/gestalt/rules/gestalt_rule.rb new file mode 100644 index 0000000..1ffd1a0 --- /dev/null +++ b/ruby/gestalt/rules/gestalt_rule.rb @@ -0,0 +1,22 @@ +module Ohcount + module Gestalt + + # states that a certain gestalt is required. + class GestaltRule < Rule + attr_reader :type, :name + + def initialize(type, name) + @type = type + @name = name + end + + def triggers(gestalt_engine) + if gestalt_engine.has_gestalt?(type,name) + [Trigger.new] + else + [] + end + end + end + end +end diff --git a/ruby/gestalt/rules/java_import_rule.rb b/ruby/gestalt/rules/java_import_rule.rb new file mode 100644 index 0000000..863f7e5 --- /dev/null +++ b/ruby/gestalt/rules/java_import_rule.rb @@ -0,0 +1,28 @@ +module Ohcount + module Gestalt + + # Triggers if a matching java 'import' statement is present + class JavaImportRule < FileRule + + def initialize(*args) + options = args.pop if args.last.is_a?(Hash) + @regex = args[0] + super(options) + end + + def process_source_file(source_file) + return false unless source_file.language_breakdown('java') + + java_code = source_file.language_breakdown('java').code + java_code.scan(import_regexp).each do |match| + import = match[0] + @count += 1 if import =~ @regex + end + end + + def import_regexp + /\bimport\s+([a-zA-Z][\w\.\*\-]*)/ + end + end + end +end diff --git a/ruby/gestalt/rules/keyword_rule.rb b/ruby/gestalt/rules/keyword_rule.rb new file mode 100644 index 0000000..eab56cd --- /dev/null +++ b/ruby/gestalt/rules/keyword_rule.rb @@ -0,0 +1,36 @@ +module Ohcount + module Gestalt + # Will trigger if the given keywords are found in the specified language. + # Example; + # + # + # c_keywords '__MSDOS__', 'MSDOS', :min => 2 + # # this will trigger if the words "__MSDOS__" or "MSDOS" is found at + # # least twice in 'C' source code + # + class KeywordRule < FileRule + attr_reader :keywords, :language + + def initialize(language, *args) + options = args.pop if args.last.is_a?(Hash) + keywords = args + @language = language + @keywords = keywords + super(options) + end + + def process_source_file(source_file) + return unless source_file.language_breakdown(language) + + code = source_file.language_breakdown(language).code + @count += code.scan(regexp).size + end + + def regexp + @regexp ||= begin + Regexp.new("(" + keywords.join("|") + ")") + end + end + end + end +end diff --git a/ruby/gestalt/rules/language_rule.rb b/ruby/gestalt/rules/language_rule.rb new file mode 100644 index 0000000..b66fcf5 --- /dev/null +++ b/ruby/gestalt/rules/language_rule.rb @@ -0,0 +1,26 @@ +module Ohcount + module Gestalt + + # states that a platform depends on a programming + # language being at least :min_percent + class LanguageRule < Rule + attr_reader :language + attr_reader :min_percent + + def initialize(language, options= {}) + @min_percent = options.delete(:min_percent) || 0 + raise "Unrecognized LanguageRule options '#{ options.keys.inspect }'" if options.any? + @language = language + end + + def triggers(gestalt_engine) + if gestalt_engine.includes_language?(language, min_percent) + [Trigger.new] + else + [] + end + end + + end + end +end diff --git a/ruby/gestalt/rules/logical_rule.rb b/ruby/gestalt/rules/logical_rule.rb new file mode 100644 index 0000000..6fccce7 --- /dev/null +++ b/ruby/gestalt/rules/logical_rule.rb @@ -0,0 +1,80 @@ +module Ohcount + module Gestalt + class LogicalRule < Rule + attr_reader :rules + + def initialize(*rules, &block) + @rules = rules + self.instance_eval(&block) if block + end + + def each_rule(&block) + @rules.each { |r| r.each_rule(&block) } + yield self + end + + def clone + cloned_rules = @rules.map { |r| + r.clone + } + self.class.new(*cloned_rules) + end + + def new_rule(r_class, *args, &block) + @rules << r_class.new(*args,&block) + end + + def _or(*args, &block) + new_rule OrRule, *args, &block + end + + def _and(*args, &block) + new_rule AndRule, *args, &block + end + + def gestalt(*args) + new_rule GestaltRule, *args + end + + def language(*args) + new_rule LanguageRule, *args + end + + # file rules + def c_headers(*args) + new_rule CHeaderRule, *args + end + + def filenames(*args) + new_rule FilenameRule, *args + end + + def c_keywords(*args) + new_rule CKeywordRule, *args + end + + def java_import(*args) + new_rule JavaImportRule, *args + end + + def find_filenames(*args) + new_rule FindFilenamesRule, *args + end + + def find_java_imports(*args) + new_rule FindJavaImportsRule, *args + end + + def method_missing(m,*args, &block) + if m.to_s =~ /^(.*)_keywords$/ + language = $1 + new_args = [language] + args + new_rule(KeywordRule, *new_args, &block) + return + end + super + end + + end + end +end diff --git a/ruby/gestalt/rules/or_rule.rb b/ruby/gestalt/rules/or_rule.rb new file mode 100644 index 0000000..d180b03 --- /dev/null +++ b/ruby/gestalt/rules/or_rule.rb @@ -0,0 +1,14 @@ +module Ohcount + module Gestalt + # Will trigger if any sub-rule does + class OrRule < LogicalRule + def triggers(gestalt_engine) + rules.each do |r| + triggers = r.triggers(gestalt_engine) + return triggers if triggers.any? + end + [] + end + end + end +end diff --git a/ruby/gestalt/rules/rule.rb b/ruby/gestalt/rules/rule.rb new file mode 100644 index 0000000..710bcb1 --- /dev/null +++ b/ruby/gestalt/rules/rule.rb @@ -0,0 +1,47 @@ +module Ohcount + module Gestalt + class Rule + def ==(other) + return false unless self.class == other.class + return false unless self.instance_variables == other.instance_variables + self.instance_variables.each do |v| + return false unless self.instance_eval(v) == other.instance_eval(v) + end + true + end + + def each_rule + yield self + end + + def to_sym + self.class.to_sym + end + + # when tallying up libraries, its easier to + # use symbol names instead of class names + # to_sym maps FooLib to :foo_lib + def self.to_sym + @symbol ||= begin + to_s =~ /([^:]*)$/ + naked_classname = $1 + chars = naked_classname.scan(/./) + chars[0] = chars[0].downcase + ruby_s = chars.collect do |char| + char.downcase == char ? char : "_" + char.downcase + end.to_s + ruby_s.intern + end + end + + def self.method_missing(m,*args) + if /(.*)_keywords$/ =~ m.to_s + language = $1 + return rules << KeywordRule.new(language,*args) + end + super + end + + end + end +end diff --git a/ruby/gestalt/rules/xml_keyword_rule.rb b/ruby/gestalt/rules/xml_keyword_rule.rb new file mode 100644 index 0000000..c9607ba --- /dev/null +++ b/ruby/gestalt/rules/xml_keyword_rule.rb @@ -0,0 +1,15 @@ +module Ohcount + module Gestalt + class XmlKeywordRule < KeywordRule + + def initialize(*keywords) + super('xml',*keywords) + end + + def trigger_file?(source_file) + return false unless source_file.polyglot = 'xml' + regexp.match(source_file.language_breakdowns('xml').code) + end + end + end +end diff --git a/ruby/gestalt/trigger.rb b/ruby/gestalt/trigger.rb new file mode 100644 index 0000000..1e66097 --- /dev/null +++ b/ruby/gestalt/trigger.rb @@ -0,0 +1,13 @@ +module Ohcount + module Gestalt + class Trigger + attr_reader :name, :count + + def initialize(args = {}) + @name = args[:name] + @count = args[:count] || 1 + end + + end + end +end diff --git a/test/unit/gestalt/definitions_test.rb b/test/unit/gestalt/definitions_test.rb new file mode 100644 index 0000000..78dd565 --- /dev/null +++ b/test/unit/gestalt/definitions_test.rb @@ -0,0 +1,238 @@ +require 'test/unit' +require '../../../ruby/gestalt' + +include Ohcount +include Ohcount::Gestalt + +class PlatformTest < Test::Unit::TestCase + + def test_zend_framework + assert_gestalts 'zend_framework', [ + Base.new(:platform,'PHP'), + Base.new(:platform,'ZendFramework'), + Base.new(:platform,'Scripting') + ] + end + + def test_php + assert_gestalts 'php', [ + Base.new(:platform,'PHP'), + Base.new(:platform,'Scripting') + ] + end + + def test_wx_widgets + assert_gestalts 'wx_widgets', [ + Base.new(:platform,'WxWidgets') + ] + end + + def test_eclipse_platform + assert_gestalts 'eclipse_platform', [ + Base.new(:platform,'Java'), + Base.new(:platform,'EclipsePlatform'), + Base.new(:java_import,"java.text.SimpleDateFormat"), + Base.new(:java_import,"java.util.Map"), + Base.new(:java_import,"org.eclipse.core.lotsa_stuff") + ] + end + + def test_win32_not_enough + assert_gestalts 'win32_not_enough', [] + end + + def test_win32_enough + assert_gestalts 'win32_enough', [ + Base.new(:platform, 'Win32') + ] + end + + def test_wpf + assert_gestalts 'wpf', [ + Base.new(:platform, 'WPF') + ] + end + + def test_asp_net + assert_gestalts 'asp_net', [ + Base.new(:platform, 'ASP_NET') + ] + end + + def test_ruby_just_enough + assert_gestalts 'ruby_just_enough', [ + Base.new(:platform, 'Ruby'), + Base.new(:platform, 'Scripting') + ] + end + + def test_ruby_not_enough + assert_gestalts 'ruby_not_enough', [] + end + + def test_cakephp + assert_gestalts 'cakephp', [ + Base.new(:platform, 'PHP'), + Base.new(:platform, 'CakePHP'), + Base.new(:platform, 'Scripting'), + ] + end + + def test_symfony + assert_platform('symfony', :PHP, :Symfony, :Scripting) + end + + def test_pear + assert_platform('pear', :PHP, :Pear, :Scripting) + end + + def test_moodle + assert_platform('moodle', :PHP, :Moodle, :Scripting) + end + + def test_spring_framework + assert_gestalts 'spring_framework', [ + Base.new(:platform, 'Java'), + Base.new(:platform, 'SpringFramework'), + Base.new(:java_jar, 'spring.jar'), + ] + end + + def test_rails + assert_platform('rails', :Ruby, :Rails, :Scripting) + end + + def test_jquery + assert_platform('jquery', :Javascript, :JQuery, :Scripting) + end + + def test_python + assert_platform('python', :Python, :Scripting) + end + + def test_mac + assert_platform('mac', :Mac) + end + + def test_plist + assert_platform('plist', :Mac) + end + + def test_posix + assert_platform('posix', :POSIX) + end + + def test_x_windows + assert_platform('xwindows', :XWindows) + end + + def test_kde + assert_platform('kde', :KDE) + end + + def test_msdos + assert_platform('msdos', :MSDos) + end + + def test_gtk + assert_platform('gtk', :GTK) + end + + def test_drupal + assert_platform('drupal', :PHP, :Drupal, :Scripting) + end + + def test_vs_1 + assert_tool('vs_1', :VisualStudio) + end + + def test_eclipse + assert_tool('eclipse', :Eclipse) + end + + def test_netbeans + assert_tool('netbeans', :NetBeans) + end + + def test_java_imports_from_java_file + java = SourceFile.new("foo.java", :contents => <<-INLINE_C + import com.foo; + import net.ohloh; + import com.foo; + // import dont.import.this; + INLINE_C + ) + + expected_gestalts = [ + Base.new(:java_import, 'com.foo', 2), + Base.new(:java_import, 'net.ohloh'), + Base.new(:platform, 'Java'), + ] + + assert_equal expected_gestalts.sort, java.gestalts.sort + end + + def test_arm + asm = SourceFile.new("foo.S", :contents => <<-INLINE_ASM + orrs 3, eax + INLINE_ASM + ) + + expected_gestalts = [ + Base.new(:platform, 'arm') + ] + + assert_equal expected_gestalts.sort, asm.gestalts.sort + end + + def test_arm_neon + asm = SourceFile.new("foo.S", :contents => <<-INLINE_ASM + vmov u8, s + INLINE_ASM + ) + + expected_gestalts = [ + Base.new(:platform, 'arm'), + Base.new(:platform, 'arm_neon') + ] + + assert_equal expected_gestalts.sort, asm.gestalts.sort + end + + def test_imports_from_java_file + jar = SourceFile.new("foo/foo.jar", :contents => '') + + expected_gestalts = [ + Base.new(:java_jar, 'foo.jar'), + ] + + assert_equal expected_gestalts.sort, jar.gestalts.sort + end + + protected + + def assert_tool(path, *tools) + gestalts = tools.map do |t| + Base.new(:tool, t.to_s) + end + assert_gestalts path, gestalts + end + + def assert_platform(path, *platforms) + gestalts = platforms.map do |p| + Base.new(:platform, p.to_s) + end + assert_gestalts path, gestalts + end + + def assert_gestalts(path, expected_gestalts) + sfl = SourceFileList.new() + sfl.add_directory(test_dir(path)) + sfl.analyze_gestalt + assert_equal expected_gestalts.sort, sfl.gestalts.sort + end + + def test_dir(d) + File.expand_path(File.dirname(__FILE__) + "/../../gestalt_files/#{ d }") + end +end diff --git a/test/unit/gestalt/file_rule_test.rb b/test/unit/gestalt/file_rule_test.rb new file mode 100644 index 0000000..a2e4955 --- /dev/null +++ b/test/unit/gestalt/file_rule_test.rb @@ -0,0 +1,54 @@ +require 'test/unit' +require '../../../ruby/gestalt' + +class FileRuleTest < Test::Unit::TestCase + include Ohcount::Gestalt + + def test_initialize + r = FileRule.new(:min => 5) + assert_equal 5, r.min_count + end + + def test_initialize_wrong_args + assert_raise ArgumentError do + r = FileRule.new(:boo => 1) + end + end + +# def test_trigger_c_header +# r = Ohcount::Gestalt::CHeaderRule.new('foo.h') +# s = Ohcount::SourceFile.new('header.h', :contents => <<-H_FILE +# // a comment +# include 'foo.h' +# H_FILE +# ) +# assert r.trigger_file?(s) +# end +# +# def test_c_keyword_rule +# r = Ohcount::Gestalt::CKeywordRule.new('WM_PAINT') +# s = Ohcount::SourceFile.new('header.h', :contents => <<-H_FILE +# // a comment +# (WM_PAINT) +# H_FILE +# ) +# assert r.trigger_file?(s) +# end +# +# def test_filename_rule +# r = Ohcount::Gestalt::FilenameRule.new('header.h') +# s = Ohcount::SourceFile.new('header.h') +# assert r.trigger_file?(s) +# end +# +# def test_filename_rule_advanced +# r = Ohcount::Gestalt::FilenameRule.new('f[ab]o', 'foo') +# assert r.trigger_file?(Ohcount::SourceFile.new('fao')) +# assert r.trigger_file?(Ohcount::SourceFile.new('fbo')) +# assert r.trigger_file?(Ohcount::SourceFile.new('foo')) +# assert !r.trigger_file?(Ohcount::SourceFile.new('fco')) +# end +end + + + diff --git a/test/unit/gestalt/filename_rule_test.rb b/test/unit/gestalt/filename_rule_test.rb new file mode 100644 index 0000000..2798394 --- /dev/null +++ b/test/unit/gestalt/filename_rule_test.rb @@ -0,0 +1,19 @@ +require 'test/unit' +require '../../../ruby/gestalt' + +class FilenameRuleTest < Test::Unit::TestCase + include Ohcount::Gestalt + + def test_process_file + r = FilenameRule.new('foo\.rb') + s = Ohcount::SourceFile.new('/bar/com/foo.rb', :contents => <<-RUBY_CODE + # comment + code = 1 + RUBY_CODE + ) + assert r.process_source_file(s) + assert_equal 1, r.count + end +end + + diff --git a/test/unit/gestalt/keyword_rule_test.rb b/test/unit/gestalt/keyword_rule_test.rb new file mode 100644 index 0000000..2292f0f --- /dev/null +++ b/test/unit/gestalt/keyword_rule_test.rb @@ -0,0 +1,20 @@ +require 'test/unit' +require '../../../ruby/gestalt' + +class KeywordRuleTest < Test::Unit::TestCase + include Ohcount::Gestalt + + def test_process_file + r = KeywordRule.new('c', 'WIN32') + s = Ohcount::SourceFile.new('header.c', :contents => <<-C_CODE + // a comment + #ifdef WIN32 + ..some code.. + #endif + C_CODE + ) + assert r.process_source_file(s) + assert_equal 1, r.count + end +end + diff --git a/test/unit/gestalt/rule_test.rb b/test/unit/gestalt/rule_test.rb new file mode 100644 index 0000000..2a6714a --- /dev/null +++ b/test/unit/gestalt/rule_test.rb @@ -0,0 +1,11 @@ +require 'test/unit' +require '../../../ruby/gestalt' + +class RuleTest < Test::Unit::TestCase + + def test_here + + end +end + + From d230cca99abe477ef1e390e330fb1f6a8d73c69f Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 24 May 2009 01:07:04 -0400 Subject: [PATCH 156/387] Added documentation for compiling Ruby extension; src/ohcount.h --- src/ohcount.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/ohcount.h b/src/ohcount.h index 485cb90..3de15fe 100644 --- a/src/ohcount.h +++ b/src/ohcount.h @@ -73,6 +73,18 @@ * * You may then link or copy 'bin/ohcount' to your system's PATH. * + * Building the Ruby extension of Ohcount requires: + * + * @li Ruby - http://ruby-lang.org/ + * @li Swig - http://swig.org/ + * + * @code + * $ ./build ruby + * @endcode + * + * You may then link or copy 'ruby/ohcount.{rb,so}' and 'ruby/gestalt{/,.rb}' + * to the appropriate places in your Ruby installation. + * * @section start First Steps * * To measure lines of code, simply pass file or directory names to the From a628ee131d08e7493be3584b75bf97b86c517f65 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 24 May 2009 01:10:00 -0400 Subject: [PATCH 157/387] Forgot to delete hash/*.h files in build. --- build | 1 + 1 file changed, 1 insertion(+) diff --git a/build b/build index 89f1c84..f25e4f4 100755 --- a/build +++ b/build @@ -113,6 +113,7 @@ then rm test/unit/run_tests rm src/parser.o rm src/parsers/*.h + rm src/hash/*.h rm src/hash/*.c else echo "Usage: build [all|ohcount|shared|tests|ruby|clean]" From 149055efbc4e9857a616095ef00973e93767d29d Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 24 May 2009 10:55:05 -0400 Subject: [PATCH 158/387] Added gestalt_test.rb helper and run it on build of Ruby extension. --- build | 1 + test/unit/gestalt/gestalt_test.rb | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 test/unit/gestalt/gestalt_test.rb diff --git a/build b/build index f25e4f4..24bd7a8 100755 --- a/build +++ b/build @@ -82,6 +82,7 @@ build_ruby_bindings() sh -c "swig -ruby -o ruby/ohcount_wrap.c ruby/ohcount.i" || exit 1 sh -c "$cc -shared ruby/ohcount_wrap.c $files -o ruby/ohcount.so \ -I/usr/lib/ruby/1.8/x86_64-linux/ -lpcre" || exit 1 + sh -c "cd test/unit/gestalt && ruby gestalt_test.rb" } if [ $# -eq 0 ] || [ $1 == "all" ] diff --git a/test/unit/gestalt/gestalt_test.rb b/test/unit/gestalt/gestalt_test.rb new file mode 100644 index 0000000..9daf474 --- /dev/null +++ b/test/unit/gestalt/gestalt_test.rb @@ -0,0 +1,6 @@ +require 'test/unit' +require 'definitions_test' +require 'file_rule_test' +require 'filename_rule_test' +require 'keyword_rule_test' +require 'rule_test' From 1babe2a8a497a473f09cf7db7a31d8b948bd9642 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 24 May 2009 10:56:57 -0400 Subject: [PATCH 159/387] Remove ruby/ohcount.so in build clean. --- build | 1 + 1 file changed, 1 insertion(+) diff --git a/build b/build index 24bd7a8..a71bfa6 100755 --- a/build +++ b/build @@ -116,6 +116,7 @@ then rm src/parsers/*.h rm src/hash/*.h rm src/hash/*.c + rm ruby/ohcount.so else echo "Usage: build [all|ohcount|shared|tests|ruby|clean]" fi From 2a6e3d82ddb08f612c4c64f146215bfb9369bd02 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 24 May 2009 11:59:45 -0400 Subject: [PATCH 160/387] ruby/gestalt.rb will print gestalts if it is run. --- ruby/gestalt.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ruby/gestalt.rb b/ruby/gestalt.rb index 3aad661..7f813d1 100644 --- a/ruby/gestalt.rb +++ b/ruby/gestalt.rb @@ -38,3 +38,19 @@ def gestalts end end end + +if __FILE__ == $0 + sourcefile_list = Ohcount::SourceFileList.new() + sourcefile_list.add_directory('.') if ARGV.size == 0 + ARGV.each do |file_or_path| + if File.directory?(file_or_path) + sourcefile_list.add_directory(file_or_path) + else + sourcefile_list.add_file(file_or_path) + end + end + sourcefile_list.analyze_gestalt() + sourcefile_list.gestalts.sort.each do |gestalt| + puts "#{gestalt.type}\t#{gestalt.count.to_s.rjust(8)}\t#{gestalt.name}" + end +end From 2c53002ee36ba5ada60c78c847d874f61768cc57 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 24 May 2009 12:24:24 -0400 Subject: [PATCH 161/387] Changed build to use platform-specific Ruby include directory via mkmf. --- build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build b/build index a71bfa6..8836e6f 100755 --- a/build +++ b/build @@ -81,7 +81,8 @@ build_ruby_bindings() echo "Generating Ruby bindings" sh -c "swig -ruby -o ruby/ohcount_wrap.c ruby/ohcount.i" || exit 1 sh -c "$cc -shared ruby/ohcount_wrap.c $files -o ruby/ohcount.so \ - -I/usr/lib/ruby/1.8/x86_64-linux/ -lpcre" || exit 1 + -I`ruby -rmkmf -e 'print Config::expand(CONFIG["archdir"])'` \ + -lpcre" || exit 1 sh -c "cd test/unit/gestalt && ruby gestalt_test.rb" } From bbd4e57d9cc5913f020b6ced8b990be05dbdf62e Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 24 May 2009 14:39:15 -0400 Subject: [PATCH 162/387] Fixed license detection for source files with no parsed languages. --- src/licenses.c | 136 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 69 insertions(+), 67 deletions(-) diff --git a/src/licenses.c b/src/licenses.c index 10db559..816ecf7 100644 --- a/src/licenses.c +++ b/src/licenses.c @@ -775,84 +775,86 @@ LicenseList *ohcount_detect_license(SourceFile *sourcefile) { ohcount_sourcefile_parse(sourcefile); - int potential_licenses_s[license_map_length]; - int potential_licenses_e[license_map_length]; - char *p, *q; int i, j, k; int ovector[30]; // recommended by PCRE ParsedLanguageList *iter; iter = ohcount_sourcefile_get_parsed_language_list(sourcefile)->head; - while (iter) { - char buffer[ohcount_sourcefile_get_contents_size(sourcefile)]; - p = iter->pl->comments; - q = buffer; - char *eof = p + strlen(p); - while (p < eof) { - // Strip leading whitespace and punctuation. - while (*p == ' ' || *p == '\t' || ispunct(*p)) p++; - // Copy line contents. - while (p < eof && *p != '\r' && *p != '\n') *q++ = *p++; - // Strip newline characters. - while (*p == '\r' || *p == '\n') p++; - // Add a trailing space. - *q++ = ' '; - } - *q = '\0'; + if (iter) { + int potential_licenses_s[license_map_length]; + int potential_licenses_e[license_map_length]; - for (j = 0; j < license_map_length; j++) { - potential_licenses_s[j] = -1; - potential_licenses_e[j] = -1; - if (pcre_exec(license_map[j].regexp, NULL, buffer, q - buffer, 0, 0, - ovector, 30) >= 0) { - int m0 = ovector[0], m1 = ovector[1]; - // Exclude terms that may not exist in the license. - if (license_map[j].exclude_re && - pcre_exec(license_map[j].exclude_regexp, NULL, buffer + m0, m1 - m0, - 0, 0, ovector, 30) >= 0) - continue; - potential_licenses_s[j] = m0; - potential_licenses_e[j] = m1; - for (k = 0; k < j; k++) { - // If this matched license is completely contained inside another one, - // do not include it. - if ((potential_licenses_s[k] < m0 && potential_licenses_e[k] >= m1) || - (potential_licenses_s[k] <= m0 && potential_licenses_e[k] > m1)) { - potential_licenses_s[j] = -1; - potential_licenses_e[j] = -1; - } - // If this matched license completely contains another one, do not - // include the latter. - if ((m0 < potential_licenses_s[k] && m1 >= potential_licenses_e[k]) || - (m0 <= potential_licenses_s[k] && m1 > potential_licenses_e[k])) { - potential_licenses_s[k] = -1; - potential_licenses_e[k] = -1; + while (iter) { + char buffer[ohcount_sourcefile_get_contents_size(sourcefile)]; + p = iter->pl->comments; + q = buffer; + char *eof = p + strlen(p); + while (p < eof) { + // Strip leading whitespace and punctuation. + while (*p == ' ' || *p == '\t' || ispunct(*p)) p++; + // Copy line contents. + while (p < eof && *p != '\r' && *p != '\n') *q++ = *p++; + // Strip newline characters. + while (*p == '\r' || *p == '\n') p++; + // Add a trailing space. + *q++ = ' '; + } + *q = '\0'; + + for (j = 0; j < license_map_length; j++) { + potential_licenses_s[j] = -1; + potential_licenses_e[j] = -1; + if (pcre_exec(license_map[j].regexp, NULL, buffer, q - buffer, 0, 0, + ovector, 30) >= 0) { + int m0 = ovector[0], m1 = ovector[1]; + // Exclude terms that may not exist in the license. + if (license_map[j].exclude_re && + pcre_exec(license_map[j].exclude_regexp, NULL, buffer + m0, m1 - m0, + 0, 0, ovector, 30) >= 0) + continue; + potential_licenses_s[j] = m0; + potential_licenses_e[j] = m1; + for (k = 0; k < j; k++) { + // If this matched license is completely contained inside another one, + // do not include it. + if ((potential_licenses_s[k] < m0 && potential_licenses_e[k] >= m1) || + (potential_licenses_s[k] <= m0 && potential_licenses_e[k] > m1)) { + potential_licenses_s[j] = -1; + potential_licenses_e[j] = -1; + } + // If this matched license completely contains another one, do not + // include the latter. + if ((m0 < potential_licenses_s[k] && m1 >= potential_licenses_e[k]) || + (m0 <= potential_licenses_s[k] && m1 > potential_licenses_e[k])) { + potential_licenses_s[k] = -1; + potential_licenses_e[k] = -1; + } } } } + iter = iter->next; } - iter = iter->next; - } - // Create the list of licenses from potential licenses. - for (i = 0; i < license_map_length; i++) { - if (potential_licenses_s[i] > -1) { - int overridden = 0; - OVERRIDE_LICENSE(LIC_GPL, LIC_GPL3); - OVERRIDE_LICENSE(LIC_GPL, LIC_GPL3_OR_LATER); - OVERRIDE_LICENSE(LIC_GPL3, LIC_GPL3_OR_LATER); - OVERRIDE_LICENSE(LIC_BSD_2CLAUSE_ISH, LIC_BSD_ISH); - if (!overridden) { - if (list->head == NULL) { // empty list - list->head = list; - list->tail = list; - list->head->lic = &license_map[i]; - list->next = NULL; - } else { - LicenseList *item = ohcount_license_list_new(); - item->lic = &license_map[i]; - list->tail->next = item; - list->tail = item; + // Create the list of licenses from potential licenses. + for (i = 0; i < license_map_length; i++) { + if (potential_licenses_s[i] > -1) { + int overridden = 0; + OVERRIDE_LICENSE(LIC_GPL, LIC_GPL3); + OVERRIDE_LICENSE(LIC_GPL, LIC_GPL3_OR_LATER); + OVERRIDE_LICENSE(LIC_GPL3, LIC_GPL3_OR_LATER); + OVERRIDE_LICENSE(LIC_BSD_2CLAUSE_ISH, LIC_BSD_ISH); + if (!overridden) { + if (list->head == NULL) { // empty list + list->head = list; + list->tail = list; + list->head->lic = &license_map[i]; + list->next = NULL; + } else { + LicenseList *item = ohcount_license_list_new(); + item->lic = &license_map[i]; + list->tail->next = item; + list->tail = item; + } } } } From fd78713d6fcd44efde51ac78e9430099d4ab8365 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 24 May 2009 14:41:12 -0400 Subject: [PATCH 163/387] Removed gestalt options from C ohcount (use ruby/gestalt.rb). --- src/hash/options.gperf | 2 -- src/ohcount.c | 8 -------- src/ohcount.h | 9 ++++----- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/src/hash/options.gperf b/src/hash/options.gperf index 4df3769..97ccf35 100644 --- a/src/hash/options.gperf +++ b/src/hash/options.gperf @@ -9,8 +9,6 @@ struct OhcountOption { const char *key; int value; }; --detect, COMMAND_DETECT -h, COMMAND_HELP --help, COMMAND_HELP --g, COMMAND_GESTALT ---gestalt, COMMAND_GESTALT -i, COMMAND_INDIVIDUAL --individual, COMMAND_INDIVIDUAL -l, COMMAND_LICENSES diff --git a/src/ohcount.c b/src/ohcount.c index 4b7d528..4a0bb72 100644 --- a/src/ohcount.c +++ b/src/ohcount.c @@ -76,7 +76,6 @@ void help() { " -a, --annotate\n" " -d, --detect\n" " -h, --help\n" - " -g, --gestalt\n" " -i, --individual\n" " -l, --license\n" " -re\n" @@ -97,11 +96,6 @@ void help() { "\n" "-h, --help Display this message\n" "\n" - "-g, --gestalt Project Properties\n" - "\n" - " Inspects project contents to determine what platform(s) the project\n" - " runs on, as well as any detected tools/IDEs used to develop it.\n" - "\n" "-i, --individual Count lines of code per file\n" "\n" " Count lines in all source code files within the given paths, and\n" @@ -295,8 +289,6 @@ int main(int argc, char *argv[]) { case COMMAND_HELP: help(); break; - case COMMAND_GESTALT: - break; case COMMAND_INDIVIDUAL: individual(list); break; diff --git a/src/ohcount.h b/src/ohcount.h index 3de15fe..231f3ff 100644 --- a/src/ohcount.h +++ b/src/ohcount.h @@ -132,10 +132,9 @@ #define COMMAND_ANNOTATE 1 #define COMMAND_DETECT 2 #define COMMAND_HELP 3 -#define COMMAND_GESTALT 4 -#define COMMAND_INDIVIDUAL 5 -#define COMMAND_LICENSES 6 -#define COMMAND_RAWENTITIES 7 -#define COMMAND_SUMMARY 8 +#define COMMAND_INDIVIDUAL 4 +#define COMMAND_LICENSES 5 +#define COMMAND_RAWENTITIES 6 +#define COMMAND_SUMMARY 7 #endif From f0542f8212b4f4ed9db0dba6d82c0a3e18488233 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 24 May 2009 14:50:16 -0400 Subject: [PATCH 164/387] Added documentation to src/ohcount.h noting gestalts require Ruby extension. --- src/ohcount.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ohcount.h b/src/ohcount.h index 231f3ff..86e9bda 100644 --- a/src/ohcount.h +++ b/src/ohcount.h @@ -39,7 +39,7 @@ * source file. * @li Another detector which tries to determine the license(s) the source file * is licensed under. - * @li A final detector for gestalts. + * @li A final detector for gestalts (via the Ruby extension). * * The command line tool allows you to profile individual files or whole * directory trees. From 410c38fb54799132909d36c7cf94ec58d44f2ca2 Mon Sep 17 00:00:00 2001 From: mitchell Date: Sun, 24 May 2009 15:18:43 -0400 Subject: [PATCH 165/387] Updated test/unit/sourcefile_test.h for completeness. --- test/unit/sourcefile_test.h | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/test/unit/sourcefile_test.h b/test/unit/sourcefile_test.h index e93eeb6..ea54dd0 100644 --- a/test/unit/sourcefile_test.h +++ b/test/unit/sourcefile_test.h @@ -35,14 +35,6 @@ void test_sourcefile_language_breakdowns() { ohcount_sourcefile_free(sf); } -void test_sourcefile_parse() { - // This was a Ruby-specific test case. -} - -void test_sourcefile_realize_file() { - -} - void test_sourcefile_diff() { SourceFile *old = ohcount_sourcefile_new("foo.c"); ohcount_sourcefile_set_contents(old, "int i;"); @@ -199,20 +191,13 @@ void test_sourcefile_list_language_facts() { ohcount_loc_list_free(list); } -void test_sourcefile_list_gestalt_facts() { - -} - void all_sourcefile_tests() { test_sourcefile_initialize(); test_sourcefile_language_breakdowns(); - test_sourcefile_parse(); - test_sourcefile_realize_file(); test_sourcefile_diff(); test_sourcefile_calc_diff2(); test_sourcefile_diff_longer(); test_sourcefile_calc_diff(); test_sourcefile_list_language_facts(); - test_sourcefile_list_gestalt_facts(); } From 308f885855d6c8d5ac9a841aee6bf316dff0dcd9 Mon Sep 17 00:00:00 2001 From: mitchell Date: Tue, 26 May 2009 21:43:05 -0400 Subject: [PATCH 166/387] Since directories are added to SourceFileLists, don't mistake as extensions. --- src/sourcefile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sourcefile.c b/src/sourcefile.c index 8b2d114..ef08872 100644 --- a/src/sourcefile.c +++ b/src/sourcefile.c @@ -25,7 +25,7 @@ SourceFile *ohcount_sourcefile_new(const char *filepath) { while (p > sourcefile->filepath && *(p - 1) != '.' && *(p - 1) != '/' && *(p - 1) != '\\') p--; - sourcefile->ext = p; + sourcefile->ext = (*(p - 1) == '.') ? p : sourcefile->filepath + length; while (p > sourcefile->filepath && *(p - 1) != '/' && *(p - 1) != '\\') p--; From 0fa50f064a5263e8f7b37c87c591c3311bf967ef Mon Sep 17 00:00:00 2001 From: andy verprauskus Date: Mon, 1 Jun 2009 12:53:12 -0700 Subject: [PATCH 167/387] [FIX] force build to use bash instead of default shell, makes build work on ubuntu --- build | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build b/build index 8836e6f..3a3465e 100755 --- a/build +++ b/build @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Build script for Ohcount. # Written by Mitchell Foral. mitchellcaladbolg.net. @@ -34,9 +34,9 @@ build_parser_o() if [[ ! -f src/parser.o || ! -z `find src/parsers/*.{h,rl} -newer src/parser.o` ]] then - sh -c "cd src/parsers/ && ./compile" || exit 1 + bash -c "cd src/parsers/ && bash ./compile" || exit 1 echo "Building src/parser.c (will take a while)" - sh -c "$cc -c src/parser.c -o src/parser.o" || exit 1 + bash -c "$cc -c src/parser.c -o src/parser.o" || exit 1 fi } From e37571e9612b549e3a7731af5763f1a9e37d452b Mon Sep 17 00:00:00 2001 From: mitchell Date: Mon, 1 Jun 2009 17:39:41 -0400 Subject: [PATCH 168/387] Change shbang so build runs on Ubuntu. --- build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build b/build index 8836e6f..ae9dd81 100755 --- a/build +++ b/build @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Build script for Ohcount. # Written by Mitchell Foral. mitchellcaladbolg.net. From df71cf014dc571daa17aa5d5eb65b6894137a5e5 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Fri, 5 Jun 2009 08:37:13 -0700 Subject: [PATCH 169/387] [FIX] make src/parsers/compile work on MACOS --- src/parsers/compile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/parsers/compile b/src/parsers/compile index a6c7680..946f8b2 100755 --- a/src/parsers/compile +++ b/src/parsers/compile @@ -11,14 +11,15 @@ do ragel $file -o "`cut -d '.' -f1 <<< "$file"`.h" else # embedded language(s) - elangs=`grep -o "#EMBED([a-z_]\+)" $file | - sed -e 's/#EMBED(\([a-z_]\+\))/\1/'` + elangs=`grep -o "#EMBED([a-z_][a-z_]*)" $file | + sed -e 's/#EMBED(\([a-z_][a-z_]*\))/\1/'` # embed all languages into this temporary file to be compiled parser=${file}.tmp # grab all lines before #EMBED statements - e_line=`grep -n -m 1 "#EMBED([a-z_]\+)" $file | cut -d ':' -f1` + e_line=`grep -n -m 1 "#EMBED([a-z_][a-z_]*)" $file | cut -d ':' -f1` + sed -n -e "1,$e_line p" $file > $parser # embed each language in the temporary file @@ -39,7 +40,7 @@ do done # grab all lines after #EMBED statements - s_line=`grep -n "#EMBED([a-z_]\+)" $file | cut -d ':' -f1 | sort -r | + s_line=`grep -n "#EMBED([a-z_][a-z_]*)" $file | cut -d ':' -f1 | sort -r | grep -m 1 "^[0-9]\+"` sed -n -e "$s_line,$ p" $file >> $parser From 9f1874d871815108dfb0d3bd43198e3526cb1540 Mon Sep 17 00:00:00 2001 From: mitchell Date: Wed, 10 Jun 2009 04:47:11 -0700 Subject: [PATCH 170/387] Fixed build regexen to compile on Mac OSX. --- src/parsers/compile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/parsers/compile b/src/parsers/compile index 946f8b2..1327c59 100755 --- a/src/parsers/compile +++ b/src/parsers/compile @@ -34,14 +34,14 @@ do s_line=`expr $s_line + 1` e_line=`expr $e_line - 1` sed -n "$s_line,$e_line p;" $e_parser | - sed -e "s/^[ \t]*machine[^;]\+;//; - s/^[ \t]*write[^;]\+;//; - s/^[ \t]*include[^;]\+;//;" >> $parser + sed -e "s/^[ \t]*machine[^;][^;]*;//; + s/^[ \t]*write[^;][^;]*;//; + s/^[ \t]*include[^;][^;]*;//;" >> $parser done # grab all lines after #EMBED statements s_line=`grep -n "#EMBED([a-z_][a-z_]*)" $file | cut -d ':' -f1 | sort -r | - grep -m 1 "^[0-9]\+"` + grep -m 1 "^[0-9][0-9]*"` sed -n -e "$s_line,$ p" $file >> $parser ragel $parser -o "`cut -d '.' -f1 <<< "$file"`.h" From 9de396212e89631dee415ff68fc2e66a87c2ad50 Mon Sep 17 00:00:00 2001 From: mitchell Date: Thu, 11 Jun 2009 05:11:46 -0700 Subject: [PATCH 171/387] Edited build to build on Mac OSX. --- build | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/build b/build index 3a3465e..5f7256d 100755 --- a/build +++ b/build @@ -2,8 +2,35 @@ # Build script for Ohcount. # Written by Mitchell Foral. mitchellcaladbolg.net. +# Options +# Change these for your system configuration. +if [ `uname` != "Darwin" ] +then + # Linux + INC_DIR= + LIB_DIR= + # You shouldn't have to change the following. + CFLAGS= + WARN="-Wall -Wno-pointer-to-int-cast -Wno-parentheses" + SHARED=-shared + SHARED_NAME=libohcount.so + RB_SHARED=-shared + RB_SHARED_NAME=ohcount.so +else + # Mac OSX + INC_DIR=/opt/local/include + LIB_DIR=/opt/local/lib + # You shouldn't have to change the following. + CFLAGS=-fno-common + WARN="-Wall -Wno-parentheses" + SHARED="-dynamiclib -L$LIB_DIR -lpcre" + SHARED_NAME=libohcount.dylib + RB_SHARED="-dynamic -bundle -lruby" + RB_SHARED_NAME=ohcount.bundle +fi + # C compiler and flags -cc="gcc -fPIC -g -Wall -Wno-pointer-to-int-cast -Wno-parentheses" +cc="gcc -fPIC -g $CFLAGS $WARN -I$INC_DIR -L$LIB_DIR" # Ohcount source files files="src/sourcefile.c \ @@ -44,11 +71,11 @@ build_shared() { build_hash_headers build_parser_o - if [[ ! -f src/libohcount.so || - ! -z `find src/*.{h,c} -newer src/libohcount.so` ]] + if [[ ! -f src/$SHARED_NAME || + ! -z `find src/*.{h,c} -newer src/$SHARED_NAME` ]] then echo "Building shared library" - sh -c "$cc -shared $files -o src/libohcount.so" || exit 1 + sh -c "$cc $SHARED $files -o src/$SHARED_NAME" || exit 1 fi } @@ -80,7 +107,7 @@ build_ruby_bindings() { echo "Generating Ruby bindings" sh -c "swig -ruby -o ruby/ohcount_wrap.c ruby/ohcount.i" || exit 1 - sh -c "$cc -shared ruby/ohcount_wrap.c $files -o ruby/ohcount.so \ + sh -c "$cc $RB_SHARED ruby/ohcount_wrap.c $files -o ruby/$RB_SHARED_NAME \ -I`ruby -rmkmf -e 'print Config::expand(CONFIG["archdir"])'` \ -lpcre" || exit 1 sh -c "cd test/unit/gestalt && ruby gestalt_test.rb" @@ -95,7 +122,7 @@ then elif [ $1 == "shared" ] then build_shared - echo "Build successful; libohcount.so is in src/" + echo "Build successful; $SHARED_NAME is in src/" elif [ $1 == "ohcount" ] then build_ohcount @@ -107,17 +134,17 @@ then elif [ $1 == "ruby" ] then build_ruby_bindings - echo "Build successful; ohcount.so is in ruby/" + echo "Build successful; $RB_SHARED_NAME is in ruby/" elif [ $1 == "clean" ] then - rm src/libohcount.so rm bin/ohcount rm test/unit/run_tests rm src/parser.o rm src/parsers/*.h rm src/hash/*.h rm src/hash/*.c - rm ruby/ohcount.so + rm src/$SHARED_NAME + rm ruby/$RB_SHARED_NAME else echo "Usage: build [all|ohcount|shared|tests|ruby|clean]" fi From d533854b9a912c8b3853259257f2f1c3dbdf4411 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Fri, 19 Jun 2009 15:19:08 -0700 Subject: [PATCH 172/387] [CHANGE] change src/diff.c for mitchell --- src/diff.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/diff.c b/src/diff.c index 399cb2d..ce7082e 100644 --- a/src/diff.c +++ b/src/diff.c @@ -252,14 +252,15 @@ struct cand { int x; int y; int pred; -} cand; +}; struct line { int serial; int value; -} *file[2], line; +}; int len[2]; +struct line *file[2]; struct line *sfile[2]; // shortened by pruning common prefix and suffix int slen[2]; int pref, suff; // length of prefix and suffix From fd06960d729e7e2c53c2a7fe4ffcc2361b931878 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Fri, 19 Jun 2009 15:20:47 -0700 Subject: [PATCH 173/387] [FIX] temp fix for missing language in language_percents --- ruby/gestalt/gestalt_engine.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ruby/gestalt/gestalt_engine.rb b/ruby/gestalt/gestalt_engine.rb index 2ccd6b4..a7ecae0 100644 --- a/ruby/gestalt/gestalt_engine.rb +++ b/ruby/gestalt/gestalt_engine.rb @@ -109,8 +109,10 @@ def includes_language?(language, min_percent = 0) def language_percents @language_percents ||= begin total = 0 - @language_counts.each do |name,code_count| - next if Ohcount.ohcount_hash_language_from_name(name.to_s).category == 1 + @language_counts.each_pair do |name,code_count| + language = Ohcount.ohcount_hash_language_from_name(name.to_s) + STDOUT.puts "Warning: Couldn't find #{name} in ohcount_hash_language_from_name" if language.nil? + next if language.nil? || language.category == 1 total += code_count end From 8802ffed7e0ea0fd978863e5935560c0796fde2c Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Fri, 19 Jun 2009 23:56:16 -0700 Subject: [PATCH 174/387] [NEW] add tests (currently broken) for source_file_list --- build | 3 ++- test/unit/ruby/ruby_test.rb | 1 + test/unit/ruby/source_file_list_test.rb | 7 +++++++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 test/unit/ruby/ruby_test.rb create mode 100644 test/unit/ruby/source_file_list_test.rb diff --git a/build b/build index 5f7256d..8d61c00 100755 --- a/build +++ b/build @@ -110,7 +110,8 @@ build_ruby_bindings() sh -c "$cc $RB_SHARED ruby/ohcount_wrap.c $files -o ruby/$RB_SHARED_NAME \ -I`ruby -rmkmf -e 'print Config::expand(CONFIG["archdir"])'` \ -lpcre" || exit 1 - sh -c "cd test/unit/gestalt && ruby gestalt_test.rb" + sh -c "cd test/unit/gestalt && ruby gestalt_test.rb" || exit 1 + sh -c "cd test/unit/ruby && ruby ruby_test.rb" || exit 1 } if [ $# -eq 0 ] || [ $1 == "all" ] diff --git a/test/unit/ruby/ruby_test.rb b/test/unit/ruby/ruby_test.rb new file mode 100644 index 0000000..d916a0b --- /dev/null +++ b/test/unit/ruby/ruby_test.rb @@ -0,0 +1 @@ +require 'source_file_list_test.rb' diff --git a/test/unit/ruby/source_file_list_test.rb b/test/unit/ruby/source_file_list_test.rb new file mode 100644 index 0000000..9d7c2dc --- /dev/null +++ b/test/unit/ruby/source_file_list_test.rb @@ -0,0 +1,7 @@ +require 'test/unit' +require '../../../ruby/gestalt' + +class SourceFileListTest < Test::Unit::TestCase + paths = [File.dirname(__FILE__)] + assert Ohcount::SourceFileList.new(:paths => paths).size > 0 +end From f349ffa82ad3bf6ab350e7a171f7dcf2d46146e5 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Sun, 21 Jun 2009 09:03:52 -0700 Subject: [PATCH 175/387] [CHANGE] complete last commit, add second necessary test --- test/unit/ruby/source_file_list_test.rb | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/test/unit/ruby/source_file_list_test.rb b/test/unit/ruby/source_file_list_test.rb index 9d7c2dc..7093fe2 100644 --- a/test/unit/ruby/source_file_list_test.rb +++ b/test/unit/ruby/source_file_list_test.rb @@ -2,6 +2,16 @@ require '../../../ruby/gestalt' class SourceFileListTest < Test::Unit::TestCase - paths = [File.dirname(__FILE__)] - assert Ohcount::SourceFileList.new(:paths => paths).size > 0 + + def test_source_file_list_initializes + paths = [File.dirname(__FILE__)] + assert Ohcount::SourceFileList.new(:paths => paths).size > 0 + end + + def test_source_file_filenames + filenames = ["x", "y", "z"] + sf = Ohcount::SourceFile.new("foo", :contents => "bar", :filenames => filenames) + assert_equal filenames, sf.filenames + end end + From 2271beacdd0d9d33196207b717ff2948991b31d1 Mon Sep 17 00:00:00 2001 From: mitchell Date: Mon, 22 Jun 2009 17:10:05 -0400 Subject: [PATCH 176/387] Fixed bugs in src/hash/languages.gperf related to 'cmake'. --- src/hash/languages.gperf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index 21dca50..2387b70 100644 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -14,8 +14,9 @@ blitzmax, LANG_BLITZMAX, "BlitzMax", 0 boo, LANG_BOO, "Boo", 0 c, LANG_C, "C", 0 classic_basic, LANG_CLASSIC_BASIC, "Classic Basic", 0 -clearsilver, LANG_CLEARSILVER, "Cmake script", 2 +clearsilver, LANG_CLEARSILVER, "ClearSilver", 0 clearsilver_template, LANG_CLEARSILVER_TEMPLATE, "ClearSilver", 0 +cmake, LANG_CMAKE, "Cmake script", 2 cpp, LANG_CPP, "C++", 0 cs_aspx, LANG_CS_ASPX, "", 0 csharp, LANG_CSHARP, "C#", 0 From 72409f9713460ac69b73a68551cb76a61e06da69 Mon Sep 17 00:00:00 2001 From: mitchell Date: Mon, 22 Jun 2009 18:29:28 -0400 Subject: [PATCH 177/387] Added code to Ruby extension to pass failing tests. --- ruby/ohcount.i | 24 ++++++++++++++++++++++-- ruby/ohcount.rb | 10 ++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/ruby/ohcount.i b/ruby/ohcount.i index a42f326..aecdc1d 100644 --- a/ruby/ohcount.i +++ b/ruby/ohcount.i @@ -14,6 +14,14 @@ $2 = RSTRING($input)->len; }; +%typemap(out) char ** { + VALUE arr = rb_ary_new(); + int i; + for (i = 0; $1[i] != NULL; i++) + rb_ary_push(arr, rb_str_new2($1[i])); + $result = arr; +}; + %nodefaultctor SourceFile; %immutable; %include "../src/languages.h" @@ -82,8 +90,20 @@ }; %extend SourceFileList { - SourceFileList() { - return ohcount_sourcefile_list_new(); + static VALUE rb_add_directory(VALUE directory, SourceFileList *list) { + if (directory && rb_type(directory) == T_STRING) + ohcount_sourcefile_list_add_directory(list, STR2CSTR(directory)); + return Qnil; + } + SourceFileList(VALUE opt_hash=NULL) { + SourceFileList *list = ohcount_sourcefile_list_new(); + if (opt_hash) { + VALUE val; + val = rb_hash_aref(opt_hash, ID2SYM(rb_intern("paths"))); + if (val && rb_type(val) == T_ARRAY) + rb_iterate(rb_each, val, SourceFileList_rb_add_directory, (VALUE)list); + } + return list; } ~SourceFileList() { ohcount_sourcefile_list_free($self); diff --git a/ruby/ohcount.rb b/ruby/ohcount.rb index 2d2ae6b..c7d98c3 100644 --- a/ruby/ohcount.rb +++ b/ruby/ohcount.rb @@ -67,6 +67,16 @@ def each_source_file iter = iter.next end end + + def size + count = 0 + iter = self.head + while (iter) + count += 1 + iter = iter.next + end + return count + end end class Detector From 0bdfc155e5720792e2551b57edab214fc9de4f73 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Mon, 22 Jun 2009 21:42:48 -0700 Subject: [PATCH 178/387] [CHANGE] add next set of failures to tests --- test/unit/ruby/source_file_list_test.rb | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/test/unit/ruby/source_file_list_test.rb b/test/unit/ruby/source_file_list_test.rb index 7093fe2..e750ef0 100644 --- a/test/unit/ruby/source_file_list_test.rb +++ b/test/unit/ruby/source_file_list_test.rb @@ -3,15 +3,26 @@ class SourceFileListTest < Test::Unit::TestCase - def test_source_file_list_initializes + def test_source_file_list_supports_analyze paths = [File.dirname(__FILE__)] - assert Ohcount::SourceFileList.new(:paths => paths).size > 0 + sf = Ohcount::SourceFileList.new(:paths => paths) + assert sf.size > 0 + # assume: the paths variable points to the directory containing this and other simple ruby test files + gestalts = [ + Ohcount::Gestalt::Base.new(:platform, 'Ruby'), + Ohcount::Gestalt::Base.new(:platform, 'Scripting') + ] + sf.analyze # this should work + assert_equal gestalts, sf.gestalts # and should produce something similar to the above gestalts list end def test_source_file_filenames filenames = ["x", "y", "z"] sf = Ohcount::SourceFile.new("foo", :contents => "bar", :filenames => filenames) assert_equal filenames, sf.filenames + sf.each do |filename| + assert filenames.include?(filename) + end end end From 862eab465e7dd0ac2ac248c392f1747d10913950 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Mon, 22 Jun 2009 21:48:02 -0700 Subject: [PATCH 179/387] [FIX] broken unit test: sort the gestalt list before comparing --- test/unit/ruby/source_file_list_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/ruby/source_file_list_test.rb b/test/unit/ruby/source_file_list_test.rb index e750ef0..ededa63 100644 --- a/test/unit/ruby/source_file_list_test.rb +++ b/test/unit/ruby/source_file_list_test.rb @@ -13,7 +13,7 @@ def test_source_file_list_supports_analyze Ohcount::Gestalt::Base.new(:platform, 'Scripting') ] sf.analyze # this should work - assert_equal gestalts, sf.gestalts # and should produce something similar to the above gestalts list + assert_equal gestalts.sort, sf.gestalts.sort # and should produce something similar to the above gestalts list end def test_source_file_filenames From bec57ccd3526efc1f8c6d4a19802996ae9c0cacf Mon Sep 17 00:00:00 2001 From: mitchell Date: Tue, 23 Jun 2009 17:12:01 -0400 Subject: [PATCH 180/387] Fixes to pass Ruby extension tests. --- ruby/gestalt.rb | 5 +++++ ruby/ohcount.i | 3 +++ ruby/ohcount.rb | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/ruby/gestalt.rb b/ruby/gestalt.rb index 7f813d1..80e72bb 100644 --- a/ruby/gestalt.rb +++ b/ruby/gestalt.rb @@ -36,6 +36,11 @@ def analyze_gestalt def gestalts @gestalt_engine.gestalts if @gestalt_engine end + + def analyze + analyze_languages() + analyze_gestalt() + end end end diff --git a/ruby/ohcount.i b/ruby/ohcount.i index aecdc1d..6ab88b9 100644 --- a/ruby/ohcount.i +++ b/ruby/ohcount.i @@ -114,6 +114,9 @@ void add_directory(const char *directory) { ohcount_sourcefile_list_add_directory($self, directory); } + LocList *analyze_languages() { + return ohcount_sourcefile_list_analyze_languages($self); + } } int ohcount_is_binary_filename(const char *filename); diff --git a/ruby/ohcount.rb b/ruby/ohcount.rb index c7d98c3..4f104a4 100644 --- a/ruby/ohcount.rb +++ b/ruby/ohcount.rb @@ -46,6 +46,10 @@ def loc_deltas() self end return ret end + def each + filenames.each { |f| yield f } + end + private def array_from_list(list, method) From 62426250f0a4fbdfa6effe291f6cae90972e9b68 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Wed, 24 Jun 2009 02:28:41 -0700 Subject: [PATCH 181/387] [FIX] fix SourceFileList.analyze to accept an argument; my mistake in not specifying this [CHANGE] add .each for SourceFileList to test - result should be yielding filenames --- ruby/gestalt.rb | 30 ++++++++++++++++++++++++++---- ruby/ohcount.rb | 9 +++++++++ test/unit/ruby/source_file_list_test.rb | 13 +++++++++---- 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/ruby/gestalt.rb b/ruby/gestalt.rb index 80e72bb..6c40ac3 100644 --- a/ruby/gestalt.rb +++ b/ruby/gestalt.rb @@ -37,10 +37,32 @@ def gestalts @gestalt_engine.gestalts if @gestalt_engine end - def analyze - analyze_languages() - analyze_gestalt() - end + # call analyze to generate facts from a collection of files (typically a + # project directory). Because deducing different facts often requires doing + # similar work, this function allows multiple facts to be extracted in one + # single pass + # + # *Fact* *Types* + # + # :gestalt:: platform dependencies and tools usage + # :languages:: detailed programming languages facts + # :java:: java-related dependencies (jars & imports) + # + # Examples + # + # sfl = SourceFileList.new(:dir => '/foo/bar') + # sfl.analyze(:languages) + # puts sfl.ruby.code.count + # + def analyze(what = [:*]) + what = [what] unless what.is_a?(Array) + + do_gestalt = what.include?(:gestalt) || what.include?(:*) + do_languages = what.include?(:language) || what.include?(:*) + + analyze_languages() if do_languages + analyze_gestalt() if do_gestalt + end end end diff --git a/ruby/ohcount.rb b/ruby/ohcount.rb index 4f104a4..21cae02 100644 --- a/ruby/ohcount.rb +++ b/ruby/ohcount.rb @@ -72,6 +72,15 @@ def each_source_file end end + # this should yield each filename, not an sf object + def each + iter = self.head + while (iter) + yield iter.sf + iter = iter.next + end + end + def size count = 0 iter = self.head diff --git a/test/unit/ruby/source_file_list_test.rb b/test/unit/ruby/source_file_list_test.rb index ededa63..7e83360 100644 --- a/test/unit/ruby/source_file_list_test.rb +++ b/test/unit/ruby/source_file_list_test.rb @@ -5,17 +5,22 @@ class SourceFileListTest < Test::Unit::TestCase def test_source_file_list_supports_analyze paths = [File.dirname(__FILE__)] - sf = Ohcount::SourceFileList.new(:paths => paths) - assert sf.size > 0 + list = Ohcount::SourceFileList.new(:paths => paths) + assert list.size > 0 # assume: the paths variable points to the directory containing this and other simple ruby test files gestalts = [ Ohcount::Gestalt::Base.new(:platform, 'Ruby'), Ohcount::Gestalt::Base.new(:platform, 'Scripting') ] - sf.analyze # this should work - assert_equal gestalts.sort, sf.gestalts.sort # and should produce something similar to the above gestalts list + list.analyze(:gestalt) # this should work + assert_equal gestalts.sort, list.gestalts.sort # and should produce something similar to the above gestalts list + list.each do |filename| + assert_equal String, filename.class + end end +end +class SourceFileTest < Test::Unit::TestCase def test_source_file_filenames filenames = ["x", "y", "z"] sf = Ohcount::SourceFile.new("foo", :contents => "bar", :filenames => filenames) From 77d59f59afdfca94f2d713d3311f7414594f5868 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Wed, 24 Jun 2009 13:44:28 -0700 Subject: [PATCH 182/387] [FIX] make SourceFileList.each work --- ruby/ohcount.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/ohcount.rb b/ruby/ohcount.rb index 21cae02..2a21e92 100644 --- a/ruby/ohcount.rb +++ b/ruby/ohcount.rb @@ -76,7 +76,7 @@ def each_source_file def each iter = self.head while (iter) - yield iter.sf + yield iter.sf.filename if iter.sf iter = iter.next end end From 1f624d6469c248b1d5fe4984b2bbfd8926e49556 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Thu, 2 Jul 2009 01:24:41 -0700 Subject: [PATCH 183/387] [CHANGE] copy over changes to add more gestalts, by Robin and Andy --- build | 2 +- ruby/gestalt/definition.rb | 3 + ruby/gestalt/dot_net_definitions.rb | 90 ++++++++++ ruby/gestalt/java_definitions.rb | 245 +++++++++++++++++++++++++++ ruby/gestalt/rules/csharp_using_rule.rb | 25 +++ ruby/gestalt/rules/find_java_imports_rule.rb | 11 +- ruby/gestalt/rules/java_import_rule.rb | 2 +- ruby/gestalt/rules/logical_rule.rb | 12 ++ ruby/gestalt/rules/maven_parser.rb | 52 ++++++ ruby/gestalt/rules/maven_rule.rb | 40 +++++ 10 files changed, 478 insertions(+), 4 deletions(-) create mode 100644 ruby/gestalt/dot_net_definitions.rb create mode 100644 ruby/gestalt/java_definitions.rb create mode 100644 ruby/gestalt/rules/csharp_using_rule.rb create mode 100755 ruby/gestalt/rules/maven_parser.rb create mode 100644 ruby/gestalt/rules/maven_rule.rb diff --git a/build b/build index 8d61c00..5f71dd0 100755 --- a/build +++ b/build @@ -22,7 +22,7 @@ else LIB_DIR=/opt/local/lib # You shouldn't have to change the following. CFLAGS=-fno-common - WARN="-Wall -Wno-parentheses" + WARN="-Wall -Wno-parentheses -O3 -Oz" SHARED="-dynamiclib -L$LIB_DIR -lpcre" SHARED_NAME=libohcount.dylib RB_SHARED="-dynamic -bundle -lruby" diff --git a/ruby/gestalt/definition.rb b/ruby/gestalt/definition.rb index b6d0bcc..b8729d6 100644 --- a/ruby/gestalt/definition.rb +++ b/ruby/gestalt/definition.rb @@ -11,7 +11,10 @@ require 'gestalt/rules/c_keyword_rule' require 'gestalt/rules/gestalt_rule' require 'gestalt/rules/java_import_rule' +require 'gestalt/rules/csharp_using_rule' require 'gestalt/rules/find_java_imports_rule' +require 'gestalt/rules/maven_parser' +require 'gestalt/rules/maven_rule' module Ohcount module Gestalt diff --git a/ruby/gestalt/dot_net_definitions.rb b/ruby/gestalt/dot_net_definitions.rb new file mode 100644 index 0000000..8c4f363 --- /dev/null +++ b/ruby/gestalt/dot_net_definitions.rb @@ -0,0 +1,90 @@ +module Ohcount + module Gestalt + + define_platform 'Dot_NET' do + language :csharp, :min_percent => 10 + end + + define_platform 'ASP_NET' do + filenames('\.(aspx|ascx|ashx|asax|axd)$') + end + + define_platform 'NUnit' do + _and do + gestalt(:platform, 'Dot_NET') + csharp_using /^NUnit\b/ + end + end + + define_platform 'NHibernate' do + _and do + gestalt(:platform, 'Dot_NET') + csharp_using /^NHibernate\b/ + end + end + + # BizTalk + define_platform 'Dot_NET_BizTalk' do + _and do + gestalt(:platform, 'Dot_NET') + _or do + csharp_using /^Microsoft\.Solutions\b/ + csharp_using /^Microsoft\.BizTalk\b/ + end + end + end + + # Connected Services Framework + define_platform 'Dot_NET_Csf' do + _and do + gestalt(:platform, 'Dot_NET') + csharp_using /^Microsoft\.Csf\b/ + end + end + + # Microsoft Content Management Server + define_platform 'Dot_NET_CMS' do + _and do + gestalt(:platform, 'Dot_NET') + csharp_using /^Microsoft\.ContentManagement\b/ + end + end + + # Exchange + define_platform 'Dot_NET_Exchange' do + _and do + gestalt(:platform, 'Dot_NET') + csharp_using /^Microsoft\.Exchange\b/ + end + end + + # Microsoft Operations Manager (Mom) + define_platform 'Dot_NET_Mom' do + _and do + gestalt(:platform, 'Dot_NET') + csharp_using /^Microsoft\.EnterpriseManagement\.Mom\b/ + end + end + + # A general category of software. + # Not a particular technology, but it "smells" like middle-tier/enterprise software. + define_platform 'Dot_NET_Enterprise' do + _and do + gestalt(:platform, 'Dot_NET') + _or do + gestalt(:platform, 'Dot_NET_BizTalk') + gestalt(:platform, 'Dot_NET_Exchange') + gestalt(:platform, 'Dot_NET_Cms') + gestalt(:platform, 'Dot_NET_Csf') + gestalt(:platform, 'Dot_NET_Mom') + csharp_using /^System\.Runtime\.Remoting\b/ + csharp_using /^System\.DirectoryServices\b/ + csharp_using /^System\.ServiceModel\b/ + csharp_using /^System\.(Data\.)?Linq\b/ + csharp_using /^System\.Data\b/ + end + end + end + + end +end diff --git a/ruby/gestalt/java_definitions.rb b/ruby/gestalt/java_definitions.rb new file mode 100644 index 0000000..e9ff400 --- /dev/null +++ b/ruby/gestalt/java_definitions.rb @@ -0,0 +1,245 @@ +module Ohcount + module Gestalt + + define_java_jar do + find_filenames /([^\\^\/]*\.(jar|JAR))/, :name_from_match => 1 + end + + define_java_import do + find_java_imports + end + + # Java Application Servers + + define_platform 'GlassFish' do + _and do + gestalt(:platform, 'Java') + _or do + find_filenames /\b(sun\-web|sun\-ejb\-jar|sun\-application(\-client))\.xml\b/ + maven_dependency /^org.glassfish\b/ + end + end + end + + define_platform 'JBoss' do + _and do + gestalt(:platform, 'Java') + _or do + find_filenames /\bjboss(\-app|cmp\-jdbc|\-web|\-build|\-client)\.xml\b/ + maven_dependency /^org.jboss\b/ + end + end + end + + define_platform 'WebLogic' do + _and do + gestalt(:platform, 'Java') + _or do + find_filenames /\bweblogic(\-ejb\-jar|\-ra|\-application|\-cmp\-rdbms\jar)\.xml\b/ + maven_plugin /^org\.codehaus\.mojo\b/, /^weblogic\-maven\-plugin\b/ + end + end + end + + define_platform 'Jonas' do + _and do + gestalt(:platform, 'Java') + find_filenames /\bjonas\-ejb\-jar\.xml\b/ + end + end + + define_platform 'WebSphere' do + _and do + gestalt(:platform, 'Java') + find_filenames /\bibm\-(application|web|webservices|webservicesclient)\-.+\.xmi$/ + end + end + + define_platform 'Tomcat' do + _and do + gestalt(:platform, 'Java') + _or do + java_import /^org\.apache\.tomcat\b/ + maven_dependency /^org\.apache\.tomcat\b/ + end + end + end + + define_platform 'AppServer' do + _or do + gestalt(:platform, 'GlassFish') + gestalt(:platform, 'JBoss') + gestalt(:platform, 'WebLogic') + gestalt(:platform, 'Tomcat') + gestalt(:platform, 'Jonas') + gestalt(:platform, 'WebSphere') + end + end + + define_platform 'EJB2' do + _and do + gestalt(:platform, 'Java') + _or do + find_filenames /(.+\-)ejb\-jar\.xml\b/ + java_keywords 'EJBHome', 'EJBRemote', 'SessionBean' + end + end + end + + define_platform 'EJB3' do + _and do + gestalt(:platform, 'Java') + _or do + java_keywords '@Stateless', '@Statefull', '@Entity', '@Remote', '@Local', '@BusinessMethod' + java_import /^javax\.persistence\b/ + end + end + end + + define_platform 'Servlet' do + _and do + gestalt(:platform, 'Java') + _or do + java_import /^javax\.servlet\b/ + maven_dependency /^javax\.servlet\b/ + end + end + end + + define_platform 'SpringFramework' do + _and do + gestalt(:platform,'Java') + _or do + filenames('spring\.jar$') + java_import /^org\.springframework\b/ + maven_dependency /^org\.springframework\b/ + end + end + end + + define_platform 'JSF' do + _and do + gestalt(:platform, 'Java') + _or do + java_import /^javax\.faces\b/ + maven_dependency /^javax\.faces\b/ + end + end + end + + define_platform 'GoogleWebToolkit' do + _and do + gestalt(:platform, 'Java') + java_import /^com\.google\.gwt\b/ + end + end + + define_platform 'Flex' do + _and do + gestalt(:platform, 'Java') + java_import /^(mx|flash)\..+/ + end + end + + # Java Persistence Frameworks + + define_platform 'Hibernate' do + _and do + gestalt(:platform, 'Java') + _or do + filenames '\bhibernate\d\.jar$' + java_import /^org\.hibernate\b/ + maven_dependency 'org.hibernate' + end + end + end + + define_platform 'JPA' do + _and do + gestalt(:platform, 'Java') + java_import /^javax\.persistence\b/ + end + end + + define_platform 'TopLink' do + _and do + gestalt(:platform, 'Java') + java_import /^oracle\.toplink\b/ + end + end + + define_platform 'Castor' do + _and do + gestalt(:platform, 'Java') + java_import /^org\.exolab\.castor\b/ + end + end + + define_platform 'db4o' do + _and do + gestalt(:platform, 'Java') + java_import /^com\.db4o\b/ + end + end + + # Java Enterprise Service Buses + + define_platform 'OpenESB' do + _and do + gestalt(:platform, 'Java') + java_import /^org\.openesb\b/ + end + end + + define_platform 'MuleESB' do + _and do + gestalt(:platform, 'Java') + java_import /^org\.mule\b/ + end + end + + define_platform 'ServiceMIX' do + _and do + gestalt(:platform, 'Java') + _or do + java_import /^org\.apache\.servicemix\b/ + maven_dependency /^org.apache.servicemix\b/ + end + end + end + + define_platform 'JBossESB' do + _and do + gestalt(:platform, 'Java') + java_import /^org\.jboss\.soa\.esb\b/ + end + end + + define_platform 'OpenESB' do + _and do + gestalt(:platform, 'Java') + java_import /^org\.openesb\b/ + end + end + + # Other Java Technologies + + define_platform 'OpenSSO' do + _and do + gestalt(:platform, 'Java') + _or do + filenames '\bopensso\.war$' + java_import /^com\.sun\.identity\.(authentication|agents)\b/ + end + end + end + + define_platform 'Maven' do + _and do + gestalt(:platform, 'Java') + find_filenames /\bpom\.xml$/ + end + end + + end +end diff --git a/ruby/gestalt/rules/csharp_using_rule.rb b/ruby/gestalt/rules/csharp_using_rule.rb new file mode 100644 index 0000000..7de2488 --- /dev/null +++ b/ruby/gestalt/rules/csharp_using_rule.rb @@ -0,0 +1,25 @@ +module Ohcount + module Gestalt + + # Triggers if a matching C# 'using' library include statement is present + class CSharpUsingRule < FileRule + + def initialize(*args) + @regex = args.shift + super(args) + end + + def process_source_file(source_file) + return false unless source_file.language_breakdown('csharp') + + source_file.language_breakdown('csharp').code.scan(using_regexp).each do |match| + @count += 1 if match[0] =~ @regex + end + end + + def using_regexp + @@using_regexp ||= /^\s*using\s+([a-zA-Z][\w\.\*\-]*)\s*;/ + end + end + end +end diff --git a/ruby/gestalt/rules/find_java_imports_rule.rb b/ruby/gestalt/rules/find_java_imports_rule.rb index 818b379..3625706 100644 --- a/ruby/gestalt/rules/find_java_imports_rule.rb +++ b/ruby/gestalt/rules/find_java_imports_rule.rb @@ -33,13 +33,20 @@ def clone def triggers(gestalt_engine) triggers = [] @trigger_hash.each do |k,v| - triggers << Trigger.new(:name => k, :count => v) + triggers << Trigger.new(:name => FindJavaImportsRule.truncate_name(k, 3), :count => v) end triggers end def import_regexp - /\bimport\s+([a-zA-Z][\w\.\*\-]*)/ + /^\s*import\s+([a-zA-Z][\w\.\*\-]*)\b/ + end + + # Truncates the java import namespace to a maximum depth. + # For instance, + # truncate_name("com.sun.identity.authentication", 3) => "com.sun.identity" + def self.truncate_name(s, max_depth) + s.to_s.split('.')[0, max_depth].join('.') end end diff --git a/ruby/gestalt/rules/java_import_rule.rb b/ruby/gestalt/rules/java_import_rule.rb index 863f7e5..cbadc8b 100644 --- a/ruby/gestalt/rules/java_import_rule.rb +++ b/ruby/gestalt/rules/java_import_rule.rb @@ -21,7 +21,7 @@ def process_source_file(source_file) end def import_regexp - /\bimport\s+([a-zA-Z][\w\.\*\-]*)/ + /^\s*import\s+([a-zA-Z][\w\.\*\-]*)\b/ end end end diff --git a/ruby/gestalt/rules/logical_rule.rb b/ruby/gestalt/rules/logical_rule.rb index 6fccce7..c3626cc 100644 --- a/ruby/gestalt/rules/logical_rule.rb +++ b/ruby/gestalt/rules/logical_rule.rb @@ -40,6 +40,14 @@ def language(*args) new_rule LanguageRule, *args end + def maven_dependency(*args) + new_rule MavenRule, *(['dependency'] + args) + end + + def maven_plugin(*args) + new_rule MavenRule, *(['plugin'] + args) + end + # file rules def c_headers(*args) new_rule CHeaderRule, *args @@ -57,6 +65,10 @@ def java_import(*args) new_rule JavaImportRule, *args end + def csharp_using(*args) + new_rule CSharpUsingRule, *args + end + def find_filenames(*args) new_rule FindFilenamesRule, *args end diff --git a/ruby/gestalt/rules/maven_parser.rb b/ruby/gestalt/rules/maven_parser.rb new file mode 100755 index 0000000..305468e --- /dev/null +++ b/ruby/gestalt/rules/maven_parser.rb @@ -0,0 +1,52 @@ +#!/usr/bin/env ruby +require 'rexml/document' +require 'rexml/streamlistener' + +class MavenListener + include REXML::StreamListener + + attr_accessor :group_id, :artifact_id, :text + + attr_accessor :callback + def initialize(callback) + @callback = callback + @is_pom_file = false + end + + def tag_start(name, attrs) + case name + when 'project' + @is_pom_file = true + if attrs['xmlns'] and attrs['xmlns'] !~ /^http:\/\/maven\.apache\.org\/POM\// + # False alarm -- it contains a project element, but of another namespace + @is_pom_file = false + end + when 'plugin', 'dependency' + @group_id = nil + @artifact_id = nil + end + end + + def tag_end(name) + case name + when 'groupId' + @group_id = clean(@text) + when 'artifactId' + @artifact_id = clean(@text) + when /^(plugin|dependency)$/ + if @is_pom_file && @group_id && @artifact_id + @callback.call($1, @group_id, @artifact_id) + end + end + end + + # Remove whitespace from text values. + # Also, clear out variable substitutions, which we are incapable of performing correctly + def clean(s) + s.strip.gsub(/\$\{.*\}/, '') + end + + def text(text) + @text = text + end +end diff --git a/ruby/gestalt/rules/maven_rule.rb b/ruby/gestalt/rules/maven_rule.rb new file mode 100644 index 0000000..5ce0da3 --- /dev/null +++ b/ruby/gestalt/rules/maven_rule.rb @@ -0,0 +1,40 @@ +require 'rexml/document' +module Ohcount + module Gestalt + class MavenRule < FileRule + + attr_accessor :group, :artifact, :type + + # Type is either 'dependency' or 'plugin' + def initialize(*args) + @type = args.shift + + @group = args.shift + @group = /^#{Regexp.escape(@group.to_s)}$/ unless @group.is_a? Regexp + + @artifact = args.shift || /.*/ + @artifact = /^#{Regexp.escape(@artifact.to_s)}$/ unless @artifact.is_a? Regexp + + super(args) + end + + def process_source_file(source_file) + callback = lambda do |type, group, artifact| + if type == @type and group =~ @group and artifact =~ @artifact + @count += 1 + end + end + + if source_file.filename =~ /\bpom\.xml$/ && source_file.language_breakdown('xml') + begin + REXML::Document.parse_stream(source_file.language_breakdown('xml').code, MavenListener.new(callback)) + rescue REXML::ParseException + # Malformed XML! -- ignore and move on + end + end + end + + end + end +end + From 4b7b8e09336e9aa7c004ecf55421964423c1a9c8 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Thu, 2 Jul 2009 14:12:12 -0700 Subject: [PATCH 184/387] [FIX] new gestalts, step 2/2 [FIX] add "#import" as an objective_c tell --- build | 1 - ruby/gestalt.rb | 5 + ruby/gestalt/definitions.rb | 120 ++++-- src/detector.c | 4 +- test/gestalt_files/weblogic_descriptor/foo.java | 4 + .../weblogic_descriptor/weblogic-application.xml | 1 + test/gestalt_files/weblogic_maven/foo.java | 4 + test/gestalt_files/weblogic_maven/pom.xml | 9 + test/gestalt_files/websphere/foo.java | 4 + .../websphere/ibm-webservices-bnd.xmi | 0 test/unit/ruby/gestalt/csharp_using_rule_test.rb | 33 ++ test/unit/ruby/gestalt/definitions_test.rb | 402 +++++++++++++++++++++ test/unit/ruby/gestalt/dot_net_definitions_test.rb | 63 ++++ test/unit/ruby/gestalt/file_rule_test.rb | 54 +++ test/unit/ruby/gestalt/filename_rule_test.rb | 19 + .../ruby/gestalt/find_java_imports_rule_test.rb | 32 ++ test/unit/ruby/gestalt/gestalt_test.rb | 6 + test/unit/ruby/gestalt/java_definitions_test.rb | 31 ++ test/unit/ruby/gestalt/keyword_rule_test.rb | 20 + .../ruby/gestalt/maven_dependency_rule_test.rb | 60 +++ test/unit/ruby/gestalt/rule_test.rb | 11 + test/unit/ruby/ruby_test.rb | 4 +- test/unit/ruby/source_file_list_test.rb | 14 +- test/unit/ruby/test_helper.rb | 60 +++ test/unit/sourcefile_test.h | 1 + 25 files changed, 920 insertions(+), 42 deletions(-) create mode 100644 test/gestalt_files/weblogic_descriptor/foo.java create mode 100644 test/gestalt_files/weblogic_descriptor/weblogic-application.xml create mode 100644 test/gestalt_files/weblogic_maven/foo.java create mode 100644 test/gestalt_files/weblogic_maven/pom.xml create mode 100644 test/gestalt_files/websphere/foo.java create mode 100644 test/gestalt_files/websphere/ibm-webservices-bnd.xmi create mode 100644 test/unit/ruby/gestalt/csharp_using_rule_test.rb create mode 100644 test/unit/ruby/gestalt/definitions_test.rb create mode 100644 test/unit/ruby/gestalt/dot_net_definitions_test.rb create mode 100644 test/unit/ruby/gestalt/file_rule_test.rb create mode 100644 test/unit/ruby/gestalt/filename_rule_test.rb create mode 100644 test/unit/ruby/gestalt/find_java_imports_rule_test.rb create mode 100644 test/unit/ruby/gestalt/gestalt_test.rb create mode 100644 test/unit/ruby/gestalt/java_definitions_test.rb create mode 100644 test/unit/ruby/gestalt/keyword_rule_test.rb create mode 100644 test/unit/ruby/gestalt/maven_dependency_rule_test.rb create mode 100644 test/unit/ruby/gestalt/rule_test.rb create mode 100644 test/unit/ruby/test_helper.rb diff --git a/build b/build index 5f71dd0..aca8ec6 100755 --- a/build +++ b/build @@ -110,7 +110,6 @@ build_ruby_bindings() sh -c "$cc $RB_SHARED ruby/ohcount_wrap.c $files -o ruby/$RB_SHARED_NAME \ -I`ruby -rmkmf -e 'print Config::expand(CONFIG["archdir"])'` \ -lpcre" || exit 1 - sh -c "cd test/unit/gestalt && ruby gestalt_test.rb" || exit 1 sh -c "cd test/unit/ruby && ruby ruby_test.rb" || exit 1 } diff --git a/ruby/gestalt.rb b/ruby/gestalt.rb index 6c40ac3..d437ace 100644 --- a/ruby/gestalt.rb +++ b/ruby/gestalt.rb @@ -10,7 +10,11 @@ require "gestalt/definition" require "gestalt/base" require "gestalt/definitions" +require "gestalt/dot_net_definitions" +require "gestalt/java_definitions" require "gestalt/gestalt_engine" +require "gestalt/gestalt_facts" + module Ohcount class SourceFile @@ -76,6 +80,7 @@ def analyze(what = [:*]) sourcefile_list.add_file(file_or_path) end end + STDOUT.puts "Examining #{sourcefile_list.size} file(s) for gestalts." sourcefile_list.analyze_gestalt() sourcefile_list.gestalts.sort.each do |gestalt| puts "#{gestalt.type}\t#{gestalt.count.to_s.rjust(8)}\t#{gestalt.name}" diff --git a/ruby/gestalt/definitions.rb b/ruby/gestalt/definitions.rb index 37fe678..2881e96 100644 --- a/ruby/gestalt/definitions.rb +++ b/ruby/gestalt/definitions.rb @@ -30,18 +30,10 @@ module Gestalt filenames '\.xaml$' end - define_platform 'Dot_NET' do - language :csharp, :min_percent => 10 - end - define_platform 'VisualBasic' do language :visualbasic, :min_percent => 5 end - define_platform 'ASP_NET' do - filenames('\.(aspx|ascx|ashx|asax|axd)$') - end - define_platform 'Ruby' do language :ruby, :min_percent => 15 end @@ -65,13 +57,6 @@ module Gestalt filenames 'jquery-\d.\d.\d.min.js' end - define_platform 'SpringFramework' do - _and do - gestalt(:platform,'Java') - filenames('spring\.jar$') - end - end - define_platform 'XWindows' do c_headers 'Xlib.h', 'X11\/xpm.h', 'X11/Xlib.h' end @@ -201,35 +186,104 @@ module Gestalt filenames '\.nbm$' end + ############################ ARM ################################### + + define_platform 'arm' do + c_headers "arm4.h", "arm3.h" + c_keywords "arm_int32_t", "arm_start_application", "__arm__" + make_keywords '\b-mabi\b','\barmcc\b' + java_keywords '\barm-eabi' + assembler_keywords '\bsmlal\b', '\bsmulw\b', '\borrs\b' + gestalt(:platform, 'arm_neon') + java_import /org\.opengroup\.arm/ + end + + ########################## ARM NEON ################################ + + define_platform 'arm_neon' do + assembler_keywords '\bvld1.\d\d\b', '\bvld1.\d\d\b','\bvmov\b','\bvmov.u8\b' + make_keywords '\bneon\b','\bNEON\b' + end - ########################## Java Jars ############################### + ############################ ATOM ################################## + # Atom is hard to detect, since it implements x86 instruction set - define_java_jar do - find_filenames /([^\\^\/]*\.(jar|JAR))/, :name_from_match => 1 + define_platform 'sse3_atom_flag' do + make_keywords 'SSE3_ATOM' end + define_platform 'xL_flag' do + make_keywords 'xL', '\/QxL' + end - ######################## Java Imports ############################## + define_platform 'atom' do + gestalt(:platform, 'sse3_atom_flag') + gestalt(:platform, 'xL_flag') + end - define_java_import do - find_java_imports - end + ####################### INTEL COMPILER ############################# + define_platform 'intel_compiler' do + make_keywords '\bicc\b' + end + ########################### MOBLIN ################################# - ############################ ARM ################################### + define_platform 'clutter' do + c_keywords "ClutterActor", '\bclutter_actor_', "ClutterStage", "ClutterBehavior", "clutter_main" + perl_keywords "Clutter::Behavior", "Clutter::Actor", "Clutter::Stage" + java_keywords "ClutterActor", "ClutterStage", "ClutterShader" + ruby_keywords "Clutter::Actor", "Clutter::Stage", "Clutter::Shader", "Clutter::Cairo" + end - define_platform 'arm' do - makefile_keywords '\b-mabi\b','\barmcc\b' - assembler_keywords '\bsmlal\b', '\bsmulw\b', '\borrs\b' - gestalt(:platform, 'arm_neon') - end + define_platform 'moblin' do + c_keywords '\"org\.moblin\.', 'MOBLIN_NETBOOK_SYSTEM_TRAY_H', 'org_Moblin_', '\"org\.Moblin\.', "url=\"http://moblin.org\">http://moblin.org" + make_keywords "org.moblin.", "moblin-netbook" + filenames 'moblin-netbook-system-tray.h$' + end - ########################## ARM NEON ################################ + define_platform 'nbtk' do + c_keywords '\bnbtk_[a-z]+', '\bNbtk[A-Z][a-z]+' + java_keywords '\bnbtk_[a-z]+', '\bNbtk[A-Z][a-z]+' + ruby_keywords '\bnbtk_[a-z]+', '\bNbtk[A-Z][a-z]+' + filenames 'nbtk\/nbtk.h' + end - define_platform 'arm_neon' do - assembler_keywords '\bvld1.\d\d\b', '\bvld1.\d\d\b','\bvmov\b','\bvmov.u8\b' - makefile_keywords '\bneon\b','\bNEON\b' - end + define_platform 'moblin_all' do + gestalt(:platform, 'clutter') + gestalt(:platform, 'moblin') + gestalt(:platform, 'nbtk') + end + ########################### ANDROID ################################# + + define_platform 'android' do + java_import /\bandroid\./ + end + + ############################ iPhone ################################# + + define_platform 'iPhone' do + objective_c_keywords '\bUIApplicationMain', '\bUIWindow', '\bUIView', '\bUIResponder' + end + + ############################ Maemo ################################# + + define_platform 'hildon' do + c_keywords '\bHildonFile', '\bhildon_file_', '\bHildonProgram', '\bHildonWindow', '\bhildon_window' + c_headers 'hildon/hildon.h' + _and do + python_keywords '\bimport hildon' + python_keywords '\bimport gtk' + end + end + define_platform 'maemo' do + gestalt(:platform, 'hildon') + end + + ############################ Windows CE ############################ + define_platform 'windows_ce_incomplete' do + csharp_keywords 'Microsoft.WindowsCE', 'Microsoft.WindowsMobile' + vb_keywords 'Microsoft.WindowsCE', 'Microsoft.WindowsMobile' + end end end diff --git a/src/detector.c b/src/detector.c index c8ff3b9..c23b9f6 100644 --- a/src/detector.c +++ b/src/detector.c @@ -506,6 +506,8 @@ const char *disambiguate_m(SourceFile *sourcefile) { while (*p == ' ' || *p == '\t') p++; if (*p == '%') { // Matlab comment matlab_score++; + } else if (*p == '#' && strncmp(p, "#import", 7) == 0) { // Objective C + objective_c_score++; } else if (*p == '#') { // Limbo or Octave comment while (*p == '#') p++; if (*p == ' ' || *p == '\t') { @@ -517,7 +519,7 @@ const char *disambiguate_m(SourceFile *sourcefile) { objective_c_score++; // Objective C comment } else if (*p == '+' || *p == '-') { // Objective C method signature objective_c_score++; - } else if (*p == '@') { // Objective C method signature + } else if (*p == '@' || *p == '#') { // Objective C method signature if (strncmp(p, "@implementation", 15) == 0 || strncmp(p, "@interface", 10) == 0) objective_c_score++; diff --git a/test/gestalt_files/weblogic_descriptor/foo.java b/test/gestalt_files/weblogic_descriptor/foo.java new file mode 100644 index 0000000..a6f7059 --- /dev/null +++ b/test/gestalt_files/weblogic_descriptor/foo.java @@ -0,0 +1,4 @@ +/* Just a comment */ +{ + return a_few_lines_of_java_to_trigger_the_java_platform(); +} diff --git a/test/gestalt_files/weblogic_descriptor/weblogic-application.xml b/test/gestalt_files/weblogic_descriptor/weblogic-application.xml new file mode 100644 index 0000000..fc65d56 --- /dev/null +++ b/test/gestalt_files/weblogic_descriptor/weblogic-application.xml @@ -0,0 +1 @@ + diff --git a/test/gestalt_files/weblogic_maven/foo.java b/test/gestalt_files/weblogic_maven/foo.java new file mode 100644 index 0000000..a6f7059 --- /dev/null +++ b/test/gestalt_files/weblogic_maven/foo.java @@ -0,0 +1,4 @@ +/* Just a comment */ +{ + return a_few_lines_of_java_to_trigger_the_java_platform(); +} diff --git a/test/gestalt_files/weblogic_maven/pom.xml b/test/gestalt_files/weblogic_maven/pom.xml new file mode 100644 index 0000000..041a4ea --- /dev/null +++ b/test/gestalt_files/weblogic_maven/pom.xml @@ -0,0 +1,9 @@ + + + + org.codehaus.mojo + weblogic-maven-plugin + + + diff --git a/test/gestalt_files/websphere/foo.java b/test/gestalt_files/websphere/foo.java new file mode 100644 index 0000000..a6f7059 --- /dev/null +++ b/test/gestalt_files/websphere/foo.java @@ -0,0 +1,4 @@ +/* Just a comment */ +{ + return a_few_lines_of_java_to_trigger_the_java_platform(); +} diff --git a/test/gestalt_files/websphere/ibm-webservices-bnd.xmi b/test/gestalt_files/websphere/ibm-webservices-bnd.xmi new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/ruby/gestalt/csharp_using_rule_test.rb b/test/unit/ruby/gestalt/csharp_using_rule_test.rb new file mode 100644 index 0000000..182c0f4 --- /dev/null +++ b/test/unit/ruby/gestalt/csharp_using_rule_test.rb @@ -0,0 +1,33 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class CSharpUsingRuleTest < Test::Unit::TestCase + include Ohcount::Gestalt + + + def test_sample + cs = SourceFile.new("hello.cs", :contents => <<-INLINE +using System; +using System.Foo; +using NUnit.Framework; + +namespace Hello +{ + /// Hi there +} + INLINE + ) + + r = CSharpUsingRule.new(/System/) + r.process_source_file(cs) + assert_equal 2, r.count + + r = CSharpUsingRule.new(/^System$/) + r.process_source_file(cs) + assert_equal 1, r.count + + r = CSharpUsingRule.new(/.+/) + r.process_source_file(cs) + assert_equal 3, r.count + + end +end diff --git a/test/unit/ruby/gestalt/definitions_test.rb b/test/unit/ruby/gestalt/definitions_test.rb new file mode 100644 index 0000000..4c47556 --- /dev/null +++ b/test/unit/ruby/gestalt/definitions_test.rb @@ -0,0 +1,402 @@ +require 'test/unit' +require File.dirname(__FILE__) + '/../../../../ruby/gestalt' + +include Ohcount +include Ohcount::Gestalt + +class PlatformTest < Ohcount::Test + + def test_zend_framework + assert_gestalts 'zend_framework', [ + Base.new(:platform,'PHP'), + Base.new(:platform,'ZendFramework'), + Base.new(:platform,'Scripting') + ] + end + + def test_php + assert_gestalts 'php', [ + Base.new(:platform,'PHP'), + Base.new(:platform,'Scripting') + ] + end + + def test_wx_widgets + assert_gestalts 'wx_widgets', [ + Base.new(:platform,'WxWidgets') + ] + end + + def test_eclipse_platform + assert_gestalts 'eclipse_platform', [ + Base.new(:platform,'Java'), + Base.new(:platform,'EclipsePlatform'), + Base.new(:java_import,"java.text.SimpleDateFormat"), + Base.new(:java_import,"java.util.Map"), + Base.new(:java_import,"org.eclipse.core") + ] + end + + def test_win32_not_enough + assert_gestalts 'win32_not_enough', [] + end + + def test_win32_enough + assert_gestalts 'win32_enough', [ + Base.new(:platform, 'Win32') + ] + end + + def test_wpf + assert_gestalts 'wpf', [ + Base.new(:platform, 'WPF') + ] + end + + def test_asp_net + assert_gestalts 'asp_net', [ + Base.new(:platform, 'ASP_NET') + ] + end + + def test_ruby_just_enough + assert_gestalts 'ruby_just_enough', [ + Base.new(:platform, 'Ruby'), + Base.new(:platform, 'Scripting') + ] + end + + def test_ruby_not_enough + assert_gestalts 'ruby_not_enough', [] + end + + def test_cakephp + assert_gestalts 'cakephp', [ + Base.new(:platform, 'PHP'), + Base.new(:platform, 'CakePHP'), + Base.new(:platform, 'Scripting'), + ] + end + + def test_symfony + assert_platform('symfony', :PHP, :Symfony, :Scripting) + end + + def test_pear + assert_platform('pear', :PHP, :Pear, :Scripting) + end + + def test_moodle + assert_platform('moodle', :PHP, :Moodle, :Scripting) + end + + def test_spring_framework + assert_gestalts 'spring_framework', [ + Base.new(:platform, 'Java'), + Base.new(:platform, 'SpringFramework'), + Base.new(:java_jar, 'spring.jar'), + ] + end + + def test_rails + assert_platform('rails', :Ruby, :Rails, :Scripting) + end + + def test_jquery + assert_platform('jquery', :Javascript, :JQuery, :Scripting) + end + + def test_python + assert_platform('python', :Python, :Scripting) + end + + def test_mac + assert_platform('mac', :Mac) + end + + def test_plist + assert_platform('plist', :Mac) + end + + def test_posix + assert_platform('posix', :POSIX) + end + + def test_x_windows + assert_platform('xwindows', :XWindows) + end + + def test_kde + assert_platform('kde', :KDE) + end + + def test_msdos + assert_platform('msdos', :MSDos) + end + + def test_gtk + assert_platform('gtk', :GTK) + end + + def test_drupal + assert_platform('drupal', :PHP, :Drupal, :Scripting) + end + + def test_vs_1 + assert_tool('vs_1', :VisualStudio) + end + + def test_eclipse + assert_tool('eclipse', :Eclipse) + end + + def test_netbeans + assert_tool('netbeans', :NetBeans) + end + + def test_java_imports_from_java_file + java = SourceFile.new("foo.java", :contents => <<-INLINE_C + import com.foo; + import net.ohloh; + import com.foo; + // import dont.import.this; + INLINE_C + ) + + expected_gestalts = [ + Base.new(:java_import, 'com.foo', 2), + Base.new(:java_import, 'net.ohloh'), + Base.new(:platform, 'Java'), + ] + + assert_equal expected_gestalts.sort, java.gestalts.sort + end + + def test_arm + asm = SourceFile.new("foo.S", :contents => <<-INLINE_ASM + orrs 3, eax + INLINE_ASM + ) + + expected_gestalts = [ + Base.new(:platform, 'arm') + ] + + assert_equal expected_gestalts.sort, asm.gestalts.sort + end + + def test_arm_from_c_keywords + c = SourceFile.new("foo.c", :contents => <<-INLINE_C + #define __arm__ + INLINE_C + ) + expected_gestalts = [ + Base.new(:platform, 'arm') + ] + assert_equal expected_gestalts, c.gestalts + end + + def test_arm_neon + asm = SourceFile.new("foo.S", :contents => <<-INLINE_ASM + vmov u8, s + INLINE_ASM + ) + + expected_gestalts = [ + Base.new(:platform, 'arm'), + Base.new(:platform, 'arm_neon') + ] + + assert_equal expected_gestalts.sort, asm.gestalts.sort + end + + def test_imports_from_java_file + jar = SourceFile.new("foo/foo.jar", :contents => '') + + expected_gestalts = [ + Base.new(:java_jar, 'foo.jar'), + ] + + assert_equal expected_gestalts.sort, jar.gestalts.sort + end + + def test_moblin_clutter + c = SourceFile.new("foo.c", :contents => <<-INLINE_C + clutter_actor_queue_redraw (CLUTTER_ACTOR(label)); + INLINE_C + ) + expected_gestalts = [ + Base.new(:platform, 'clutter'), + Base.new(:platform, 'moblin_all') + ] + + assert_equal expected_gestalts.sort, c.gestalts.sort + end + + def test_moblin_by_filename + c = SourceFile.new("moblin-netbook-system-tray.h", :contents => <<-INLINE_PERL + #include "foo" + INLINE_PERL + ) + expected_gestalts = [ + Base.new(:platform, 'moblin'), + Base.new(:platform, 'moblin_all') + ] + + assert_equal expected_gestalts.sort, c.gestalts.sort + end + + def test_moblin_by_keyword + c = SourceFile.new("foo.c", :contents => <<-INLINE_PERL + proxy = dbus_g_proxy_new_for_name (conn, "org.moblin.connman", + INLINE_PERL + ) + expected_gestalts = [ + Base.new(:platform, 'moblin'), + Base.new(:platform, 'moblin_all') + ] + + assert_equal expected_gestalts.sort, c.gestalts.sort + end + + def test_nbtk + c = SourceFile.new("foo.c", :contents => <<-INLINE_C + button = nbtk_button_new_with_label ("Back"); + INLINE_C + ) + expected_gestalts = [ + Base.new(:platform, 'nbtk'), + Base.new(:platform, 'moblin_all') + ] + + assert_equal expected_gestalts.sort, c.gestalts.sort + end + + + def test_android + java = SourceFile.new("foo.java", :contents => <<-INLINE_C + import android.app.Activity; + // import dont.import.this; + INLINE_C + ) + + expected_gestalts = [ + Base.new(:java_import, 'android.app.Activity'), + Base.new(:platform, 'Java'), + Base.new(:platform, 'android'), + ] + + assert_equal expected_gestalts.sort, java.gestalts.sort + end + + def test_iphone + objective_c = SourceFile.new("foo.m", :contents => <<-OBJECTIVE_C + #import + #import + #import "WhackABugApp.h" + + int main(int argc, char *argv[]) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + int ret = UIApplicationMain(argc, argv, [WhackABugApp class]); + [pool release]; + return ret; + } + OBJECTIVE_C + ) + + expected_gestalts = [ + Base.new(:platform, 'iPhone'), + ] + + assert_equal expected_gestalts.sort, objective_c.gestalts.sort + end + + def test_hildon + c = SourceFile.new("foo.c", :contents => <<-INLINE_C + HildonWindow *window; + INLINE_C + ) + expected_gestalts = [ + Base.new(:platform, 'hildon'), + Base.new(:platform, 'maemo') + ] + + assert_equal expected_gestalts.sort, c.gestalts.sort + end + + def test_atom_linux + make = SourceFile.new("makefile", :contents => <<-INLINE_MAKEFILE + COMPILE_FLAGS=/QxL + INLINE_MAKEFILE + ) + expected_gestalts = [ + Base.new(:platform, 'xL_flag'), + Base.new(:platform, 'atom') + ] + assert_equal expected_gestalts.sort, make.gestalts.sort + end + + def test_atom_windows + make = SourceFile.new("makefile", :contents => <<-INLINE_MAKEFILE + CCFLAGS = -xL + INLINE_MAKEFILE + ) + expected_gestalts = [ + Base.new(:platform, 'xL_flag'), + Base.new(:platform, 'atom') + ] + assert_equal expected_gestalts.sort, make.gestalts.sort + end + + def test_atom_sse3 + make = SourceFile.new("makefile", :contents => <<-INLINE_MAKEFILE + COMPILE_FLAGS=-xSSE3_ATOM_FLAG + INLINE_MAKEFILE + ) + expected_gestalts = [ + Base.new(:platform, 'sse3_atom_flag'), + Base.new(:platform, 'atom') + ] + assert_equal expected_gestalts.sort, make.gestalts.sort + end + + def test_intel_compiler + + make = SourceFile.new("Makefile", :contents => <<-INLINE_MAKEFILE + CC = icc + INLINE_MAKEFILE + ) + expected_gestalts = [ + Base.new(:platform, 'intel_compiler'), + ] + assert_equal expected_gestalts.sort, make.gestalts.sort + end + + def test_opensso + java = SourceFile.new("foo.java", :contents => <<-INLINE_JAVA +import com.sun.identity.authentication; + INLINE_JAVA + ) + expected_gestalts = [ + Base.new(:platform, 'Java'), + Base.new(:platform, 'OpenSSO'), + Base.new(:java_import, 'com.sun.identity') + ] + + assert_equal expected_gestalts.sort, java.gestalts.sort + end + + def test_windows_ce + csharp = SourceFile.new("bam.cs", :contents => <<-INLINE_CSHARP + using System; + using Microsoft.WindowsMobile.DirectX; + INLINE_CSHARP + ) + expected_gestalts = [ + Base.new(:platform, 'windows_ce_incomplete'), + Base.new(:platform, 'Dot_NET'), + ] + + assert_equal expected_gestalts.sort, csharp.gestalts.sort + end +end diff --git a/test/unit/ruby/gestalt/dot_net_definitions_test.rb b/test/unit/ruby/gestalt/dot_net_definitions_test.rb new file mode 100644 index 0000000..9e6aafc --- /dev/null +++ b/test/unit/ruby/gestalt/dot_net_definitions_test.rb @@ -0,0 +1,63 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +include Ohcount +include Ohcount::Gestalt + +class DotNetDefinitionsTest < Test::Unit::TestCase + + def test_nunit + sf = SourceFile.new('foo.cs', :contents => <<-CONTENTS +using NUnit.Framework; +CONTENTS + ) + assert_equal [ + Gestalt::Base.new(:platform, 'Dot_NET'), + Gestalt::Base.new(:platform, 'NUnit') + ], sf.gestalts.sort + end + + def test_nhibernate + sf = SourceFile.new('foo.cs', :contents => <<-CONTENTS +using NHibernate.Connection.DriverConnectionProvider; +CONTENTS + ) + assert_equal [ + Gestalt::Base.new(:platform, 'Dot_NET'), + Gestalt::Base.new(:platform, 'NHibernate') + ], sf.gestalts.sort + end + + def test_remoting_implies_enterprise + sf = SourceFile.new('foo.cs', :contents => <<-CONTENTS +using System.Runtime.Remoting; +CONTENTS + ) + assert_equal [ + Gestalt::Base.new(:platform, 'Dot_NET'), + Gestalt::Base.new(:platform, 'Dot_NET_Enterprise') + ], sf.gestalts.sort + end + + def test_biztalk_implies_enterprise + sf = SourceFile.new('foo.cs', :contents => <<-CONTENTS +using Microsoft.BizTalk; +CONTENTS + ) + assert_equal [ + Gestalt::Base.new(:platform, 'Dot_NET'), + Gestalt::Base.new(:platform, 'Dot_NET_BizTalk'), + Gestalt::Base.new(:platform, 'Dot_NET_Enterprise') + ], sf.gestalts.sort + end + + def test_linq_implies_enterprise + sf = SourceFile.new('foo.cs', :contents => <<-CONTENTS +using System.Data.Linq; +CONTENTS + ) + assert_equal [ + Gestalt::Base.new(:platform, 'Dot_NET'), + Gestalt::Base.new(:platform, 'Dot_NET_Enterprise') + ], sf.gestalts.sort + end +end diff --git a/test/unit/ruby/gestalt/file_rule_test.rb b/test/unit/ruby/gestalt/file_rule_test.rb new file mode 100644 index 0000000..0274bf6 --- /dev/null +++ b/test/unit/ruby/gestalt/file_rule_test.rb @@ -0,0 +1,54 @@ +require 'test/unit' +require File.dirname(__FILE__) + '/../../../../ruby/gestalt' + +class FileRuleTest < Test::Unit::TestCase + include Ohcount::Gestalt + + def test_initialize + r = FileRule.new(:min => 5) + assert_equal 5, r.min_count + end + + def test_initialize_wrong_args + assert_raise ArgumentError do + r = FileRule.new(:boo => 1) + end + end + +# def test_trigger_c_header +# r = Ohcount::Gestalt::CHeaderRule.new('foo.h') +# s = Ohcount::SourceFile.new('header.h', :contents => <<-H_FILE +# // a comment +# include 'foo.h' +# H_FILE +# ) +# assert r.trigger_file?(s) +# end +# +# def test_c_keyword_rule +# r = Ohcount::Gestalt::CKeywordRule.new('WM_PAINT') +# s = Ohcount::SourceFile.new('header.h', :contents => <<-H_FILE +# // a comment +# (WM_PAINT) +# H_FILE +# ) +# assert r.trigger_file?(s) +# end +# +# def test_filename_rule +# r = Ohcount::Gestalt::FilenameRule.new('header.h') +# s = Ohcount::SourceFile.new('header.h') +# assert r.trigger_file?(s) +# end +# +# def test_filename_rule_advanced +# r = Ohcount::Gestalt::FilenameRule.new('f[ab]o', 'foo') +# assert r.trigger_file?(Ohcount::SourceFile.new('fao')) +# assert r.trigger_file?(Ohcount::SourceFile.new('fbo')) +# assert r.trigger_file?(Ohcount::SourceFile.new('foo')) +# assert !r.trigger_file?(Ohcount::SourceFile.new('fco')) +# end +end + + + diff --git a/test/unit/ruby/gestalt/filename_rule_test.rb b/test/unit/ruby/gestalt/filename_rule_test.rb new file mode 100644 index 0000000..5992f70 --- /dev/null +++ b/test/unit/ruby/gestalt/filename_rule_test.rb @@ -0,0 +1,19 @@ +require 'test/unit' +require File.dirname(__FILE__) + '/../../../../ruby/gestalt' + +class FilenameRuleTest < Test::Unit::TestCase + include Ohcount::Gestalt + + def test_process_file + r = FilenameRule.new('foo\.rb') + s = Ohcount::SourceFile.new('/bar/com/foo.rb', :contents => <<-RUBY_CODE + # comment + code = 1 + RUBY_CODE + ) + assert r.process_source_file(s) + assert_equal 1, r.count + end +end + + diff --git a/test/unit/ruby/gestalt/find_java_imports_rule_test.rb b/test/unit/ruby/gestalt/find_java_imports_rule_test.rb new file mode 100644 index 0000000..932d787 --- /dev/null +++ b/test/unit/ruby/gestalt/find_java_imports_rule_test.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class FindJavaImportsRuleTest < Test::Unit::TestCase + include Ohcount::Gestalt + + def test_truncate_name + assert_equal "", FindJavaImportsRule.truncate_name(nil, 3) + assert_equal "", FindJavaImportsRule.truncate_name("", 3) + assert_equal "", FindJavaImportsRule.truncate_name("net.ohloh.ohcount.test", 0) + assert_equal "net", FindJavaImportsRule.truncate_name("net.ohloh.ohcount.test", 1) + assert_equal "net.ohloh", FindJavaImportsRule.truncate_name("net.ohloh.ohcount.test", 2) + assert_equal "net.ohloh.ohcount", FindJavaImportsRule.truncate_name("net.ohloh.ohcount.test", 3) + assert_equal "net.ohloh.ohcount.test", FindJavaImportsRule.truncate_name("net.ohloh.ohcount.test", 4) + assert_equal "net.ohloh.ohcount.test", FindJavaImportsRule.truncate_name("net.ohloh.ohcount.test", 5) + end + + def test_arm_from_java_import + java = SourceFile.new("foo.java", :contents => <<-INLINE_C + import org.opengroup.arm40.transaction.ArmConstants; + // import dont.import.this; + INLINE_C + ) + + expected_gestalts = [ + Base.new(:java_import, 'org.opengroup.arm40'), + Base.new(:platform, 'Java'), + Base.new(:platform, 'arm'), + ] + + assert_equal expected_gestalts.sort, java.gestalts.sort + end +end diff --git a/test/unit/ruby/gestalt/gestalt_test.rb b/test/unit/ruby/gestalt/gestalt_test.rb new file mode 100644 index 0000000..ae9ad29 --- /dev/null +++ b/test/unit/ruby/gestalt/gestalt_test.rb @@ -0,0 +1,6 @@ +require 'test/unit' +require File.dirname(__FILE__) + '/definitions_test' +require File.dirname(__FILE__) + '/file_rule_test' +require File.dirname(__FILE__) + '/filename_rule_test' +require File.dirname(__FILE__) + '/keyword_rule_test' +require File.dirname(__FILE__) + '/rule_test' diff --git a/test/unit/ruby/gestalt/java_definitions_test.rb b/test/unit/ruby/gestalt/java_definitions_test.rb new file mode 100644 index 0000000..f7c84fe --- /dev/null +++ b/test/unit/ruby/gestalt/java_definitions_test.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '/../../test_helper' +include Ohcount +include Ohcount::Gestalt + +class JavaDefinitionsTest < Ohcount::Test + + def test_weblogic_via_maven + assert_gestalts 'weblogic_maven', [ + Base.new(:platform, 'AppServer'), + Base.new(:platform, 'Java'), + Base.new(:platform, 'Maven'), + Base.new(:platform, 'WebLogic') + ] + end + + def test_weblogic_via_descriptor + assert_gestalts 'weblogic_descriptor', [ + Base.new(:platform, 'AppServer'), + Base.new(:platform, 'Java'), + Base.new(:platform, 'WebLogic') + ] + end + + def test_webshpere_via_descriptor + assert_gestalts 'websphere', [ + Base.new(:platform, 'AppServer'), + Base.new(:platform, 'Java'), + Base.new(:platform, 'WebSphere') + ] + end +end diff --git a/test/unit/ruby/gestalt/keyword_rule_test.rb b/test/unit/ruby/gestalt/keyword_rule_test.rb new file mode 100644 index 0000000..4fa1045 --- /dev/null +++ b/test/unit/ruby/gestalt/keyword_rule_test.rb @@ -0,0 +1,20 @@ +require 'test/unit' +require File.dirname(__FILE__) + '/../../../../ruby/gestalt' + +class KeywordRuleTest < Test::Unit::TestCase + include Ohcount::Gestalt + + def test_process_file + r = KeywordRule.new('c', 'WIN32') + s = Ohcount::SourceFile.new('header.c', :contents => <<-C_CODE + // a comment + #ifdef WIN32 + ..some code.. + #endif + C_CODE + ) + assert r.process_source_file(s) + assert_equal 1, r.count + end +end + diff --git a/test/unit/ruby/gestalt/maven_dependency_rule_test.rb b/test/unit/ruby/gestalt/maven_dependency_rule_test.rb new file mode 100644 index 0000000..332dee3 --- /dev/null +++ b/test/unit/ruby/gestalt/maven_dependency_rule_test.rb @@ -0,0 +1,60 @@ +require File.dirname(__FILE__) + '/../../test_helper' + +class MavenDependencyTest < Test::Unit::TestCase + include Ohcount::Gestalt + + + def test_dependency + pom = SourceFile.new("pom.xml", :contents => <<-INLINE + + + + + test_group_1 + test_artifact_1A + + + test_group_1 + test_artifact_1B + + + test_group_2 + test_artifact_2A + + + test_group_2 + test_artifact_2B + + + + INLINE + ) + + r = MavenRule.new('dependency', /1$/, /B$/) + + r.process_source_file(pom) + assert_equal 1, r.count + + end + + def test_plugin + pom = SourceFile.new("pom.xml", :contents => <<-INLINE + + + + foobar + baz + + + + INLINE + ) + + r = MavenRule.new('plugin', /^foobar\b/, /^baz\b/) + + r.process_source_file(pom) + assert_equal 1, r.count + end +end diff --git a/test/unit/ruby/gestalt/rule_test.rb b/test/unit/ruby/gestalt/rule_test.rb new file mode 100644 index 0000000..459bd18 --- /dev/null +++ b/test/unit/ruby/gestalt/rule_test.rb @@ -0,0 +1,11 @@ +require 'test/unit' +require File.dirname(__FILE__) + '/../../../../ruby/gestalt' + +class RuleTest < Test::Unit::TestCase + + def test_here + + end +end + + diff --git a/test/unit/ruby/ruby_test.rb b/test/unit/ruby/ruby_test.rb index d916a0b..90fee5f 100644 --- a/test/unit/ruby/ruby_test.rb +++ b/test/unit/ruby/ruby_test.rb @@ -1 +1,3 @@ -require 'source_file_list_test.rb' +require File.dirname(__FILE__) + '/test_helper.rb' +require File.dirname(__FILE__) + '/source_file_list_test.rb' +require File.dirname(__FILE__) + '/gestalt/gestalt_test' diff --git a/test/unit/ruby/source_file_list_test.rb b/test/unit/ruby/source_file_list_test.rb index 7e83360..f50c8e5 100644 --- a/test/unit/ruby/source_file_list_test.rb +++ b/test/unit/ruby/source_file_list_test.rb @@ -1,5 +1,5 @@ require 'test/unit' -require '../../../ruby/gestalt' +require File.dirname(__FILE__) + '/../../../ruby/gestalt' class SourceFileListTest < Test::Unit::TestCase @@ -8,12 +8,14 @@ def test_source_file_list_supports_analyze list = Ohcount::SourceFileList.new(:paths => paths) assert list.size > 0 # assume: the paths variable points to the directory containing this and other simple ruby test files - gestalts = [ - Ohcount::Gestalt::Base.new(:platform, 'Ruby'), - Ohcount::Gestalt::Base.new(:platform, 'Scripting') - ] + + ruby = Ohcount::Gestalt::Base.new(:platform, 'Ruby') + scripting = Ohcount::Gestalt::Base.new(:platform, 'Scripting') + list.analyze(:gestalt) # this should work - assert_equal gestalts.sort, list.gestalts.sort # and should produce something similar to the above gestalts list + assert list.gestalts.include?(ruby) + assert list.gestalts.include?(scripting) + list.each do |filename| assert_equal String, filename.class end diff --git a/test/unit/ruby/test_helper.rb b/test/unit/ruby/test_helper.rb new file mode 100644 index 0000000..93bd79b --- /dev/null +++ b/test/unit/ruby/test_helper.rb @@ -0,0 +1,60 @@ +require 'test/unit' +require 'fileutils' +require 'find' +require File.dirname(__FILE__) + '/../../../ruby/ohcount.rb' # .rb is to specify the .rb instead of .bundle +require File.dirname(__FILE__) + '/../../../ruby/gestalt' # .rb is to specify the .rb instead of .bundle + +unless defined?(TEST_DIR) + TEST_DIR = File.dirname(__FILE__) +end + +module Ohcount +end + +# Ohcount::Test is a base class which includes several helper methods for parser testing. +# All unit tests in Ohcount should derive from this class. +# +# ==== Manual Testing +# +# To manually test a parser, rebuild ohcount and run it against your test file: +# +# rake +# bin/ohcount --annotate test/src_dir/my_file.ext +# +# The +annotate+ option will emit your test file to the console, and each line will be +# labeled as code, comment, or blank. +# +class Ohcount::Test < Test::Unit::TestCase + + # For reasons unknown, the base class defines a default_test method to throw a failure. + # We override it with a no-op to prevent this 'helpful' feature. + def default_test; end + + protected + + def assert_tool(path, *tools) + gestalts = tools.map do |t| + Base.new(:tool, t.to_s) + end + assert_gestalts path, gestalts + end + + def assert_platform(path, *platforms) + gestalts = platforms.map do |p| + Base.new(:platform, p.to_s) + end + assert_gestalts path, gestalts + end + + def assert_gestalts(path, expected_gestalts) + sfl = SourceFileList.new(:paths => [test_dir(path)]) + assert sfl.size > 0 + sfl.analyze(:gestalt) + assert_equal expected_gestalts.sort, sfl.gestalts.sort + end + + def test_dir(d) + File.expand_path(File.dirname(__FILE__) + "/../../gestalt_files/#{ d }") + end +end + diff --git a/test/unit/sourcefile_test.h b/test/unit/sourcefile_test.h index ea54dd0..b9c4ccc 100644 --- a/test/unit/sourcefile_test.h +++ b/test/unit/sourcefile_test.h @@ -182,6 +182,7 @@ void test_sourcefile_list_language_facts() { SourceFileList *sfl = ohcount_sourcefile_list_new(); ohcount_sourcefile_list_add_directory(sfl, "../gestalt_files/win32_enough/"); LocList *list = ohcount_sourcefile_list_analyze_languages(sfl); + printf("%d", ohcount_loc_list_filecount(list)); assert(ohcount_loc_list_filecount(list) == 2); Loc *loc = ohcount_loc_list_get_loc(list, "c"); assert(loc->code == 2); From f967eadc23c42c049cd7640ccb6fb5489aa09dda Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Tue, 7 Jul 2009 10:36:25 -0700 Subject: [PATCH 185/387] [NEW] add chunk of javascript extracted from firebug.js to test files; it is not parsed correctly --- test/expected_dir/fb.js | 9 +++++++++ test/src_dir/fb.js | 9 +++++++++ test/unit/parser_test.h | 5 ++++- 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 test/expected_dir/fb.js create mode 100644 test/src_dir/fb.js diff --git a/test/expected_dir/fb.js b/test/expected_dir/fb.js new file mode 100644 index 0000000..ba222ec --- /dev/null +++ b/test/expected_dir/fb.js @@ -0,0 +1,9 @@ +javascript code function escapeHTML(value) +javascript code { +javascript code return String(value).replace(/[<>&"']/g, replaceChars); +javascript code } +javascript blank +javascript code window.onerror = onError; +javascript blank +javascript code if (document.documentElement.getAttribute("debug") == "true") +javascript code toggleConsole(true); diff --git a/test/src_dir/fb.js b/test/src_dir/fb.js new file mode 100644 index 0000000..f71c201 --- /dev/null +++ b/test/src_dir/fb.js @@ -0,0 +1,9 @@ +function escapeHTML(value) +{ + return String(value).replace(/[<>&"']/g, replaceChars); +} + +window.onerror = onError; + +if (document.documentElement.getAttribute("debug") == "true") + toggleConsole(true); diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index d4a11f7..026368f 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -166,7 +166,10 @@ void test_parser_callback(const char *language, const char *entity, strncpy(line2 + strlen(language) + strlen(entity) + 2, buffer + start, end - start); line2[strlen(language) + strlen(entity) + 2 + (end - start)] = '\0'; - assert(strcmp(line, line2) == 0); + if (strcmp(line, line2) != 0) { + fprintf(stderr, "lines didn't match:\n1: '%s'\n2: '%s'\n", line, line2); + assert(strcmp(line, line2) == 0); + } } char *test_parser_filenames[] = { "", 0 }; From 217e6712eb49f9adbc72f59a4b6191e47cb37af1 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Tue, 7 Jul 2009 10:59:28 -0700 Subject: [PATCH 186/387] [FIX] remove bogus debug printf --- test/unit/sourcefile_test.h | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unit/sourcefile_test.h b/test/unit/sourcefile_test.h index b9c4ccc..ea54dd0 100644 --- a/test/unit/sourcefile_test.h +++ b/test/unit/sourcefile_test.h @@ -182,7 +182,6 @@ void test_sourcefile_list_language_facts() { SourceFileList *sfl = ohcount_sourcefile_list_new(); ohcount_sourcefile_list_add_directory(sfl, "../gestalt_files/win32_enough/"); LocList *list = ohcount_sourcefile_list_analyze_languages(sfl); - printf("%d", ohcount_loc_list_filecount(list)); assert(ohcount_loc_list_filecount(list) == 2); Loc *loc = ohcount_loc_list_get_loc(list, "c"); assert(loc->code == 2); From f8bbd3ea5312eb1fabdb1fcca73af3c4432decb9 Mon Sep 17 00:00:00 2001 From: mitchell Date: Wed, 8 Jul 2009 22:30:08 -0400 Subject: [PATCH 187/387] Added regex to Javascript parser to fix failing test. --- src/parsers/javascript.rl | 3 ++- test/expected_dir/fb.js | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/parsers/javascript.rl b/src/parsers/javascript.rl index 242bd94..1f34177 100644 --- a/src/parsers/javascript.rl +++ b/src/parsers/javascript.rl @@ -79,7 +79,8 @@ enum { | '\\' nonnewline @code )* '"'; - js_string = js_sq_str | js_dq_str; + js_regex_str = '/' [^/*] ([^\r\n\f/\\] | '\\' nonnewline)* '/' @code; + js_string = js_sq_str | js_dq_str | js_regex_str; js_line := |* spaces ${ entity = JS_SPACE; } => js_ccallback; diff --git a/test/expected_dir/fb.js b/test/expected_dir/fb.js index ba222ec..0f7000e 100644 --- a/test/expected_dir/fb.js +++ b/test/expected_dir/fb.js @@ -2,8 +2,8 @@ javascript code function escapeHTML(value) javascript code { javascript code return String(value).replace(/[<>&"']/g, replaceChars); javascript code } -javascript blank +javascript blank javascript code window.onerror = onError; -javascript blank +javascript blank javascript code if (document.documentElement.getAttribute("debug") == "true") javascript code toggleConsole(true); From e5bb762fc96dbe85acbb151a2a0e623f9016a7b7 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Fri, 10 Jul 2009 14:01:54 -0700 Subject: [PATCH 188/387] [CHANGE] build ruby bindings per architecture; useful for Ohloh since we run different plaforms on Server and Dev machine --- build | 8 +++++--- ruby/ohcount.rb | 9 ++++++++- test/unit/parser_test.h | 5 ++++- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/build b/build index aca8ec6..9ac1c1a 100755 --- a/build +++ b/build @@ -105,9 +105,11 @@ run_test_suite() build_ruby_bindings() { - echo "Generating Ruby bindings" - sh -c "swig -ruby -o ruby/ohcount_wrap.c ruby/ohcount.i" || exit 1 - sh -c "$cc $RB_SHARED ruby/ohcount_wrap.c $files -o ruby/$RB_SHARED_NAME \ + arch=`ruby -rmkmf -e 'print Config::expand(CONFIG["arch"])'` + echo "Generating Ruby bindings for $arch" + sh -c "swig -ruby -o ruby/ohcount_wrap.c ruby/ohcount.i" || exit 1 + mkdir -p ruby/$arch + sh -c "$cc $RB_SHARED ruby/ohcount_wrap.c $files -o ruby/$arch/$RB_SHARED_NAME \ -I`ruby -rmkmf -e 'print Config::expand(CONFIG["archdir"])'` \ -lpcre" || exit 1 sh -c "cd test/unit/ruby && ruby ruby_test.rb" || exit 1 diff --git a/ruby/ohcount.rb b/ruby/ohcount.rb index 2a21e92..c238bc0 100644 --- a/ruby/ohcount.rb +++ b/ruby/ohcount.rb @@ -3,7 +3,14 @@ # Ohcount module tweaked for use by Ohloh. $: << File.expand_path(File.dirname(__FILE__)) -require 'ohcount.so' + +begin + require 'ohcount.so' +rescue LoadError + require 'rbconfig' + include Config + require "#{Config::CONFIG['arch']}/ohcount.so" +end module Ohcount class SourceFile diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index 026368f..84fc605 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -168,7 +168,10 @@ void test_parser_callback(const char *language, const char *entity, line2[strlen(language) + strlen(entity) + 2 + (end - start)] = '\0'; if (strcmp(line, line2) != 0) { fprintf(stderr, "lines didn't match:\n1: '%s'\n2: '%s'\n", line, line2); - assert(strcmp(line, line2) == 0); + if (strcmp(line, line2) != 0) { + fprintf(stderr, "lines didn't match:\n1: '%s'\n2: '%s'\n", line, line2); + assert(strcmp(line, line2) == 0); + } } } From 6316a85424f318d4325454266695918421058554 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Mon, 13 Jul 2009 11:29:55 -0700 Subject: [PATCH 189/387] [NEW] add simple README --- README | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 README diff --git a/README b/README new file mode 100644 index 0000000..b94bced --- /dev/null +++ b/README @@ -0,0 +1,10 @@ +To build docs, do + > cd doc + > Doxygen Doxyfile + +To read docs, open html/index.html in a browser. First build them, as described above. + +To add support for a new language, you'll need to implement both a detector and a parser. Documentation at + +* doc/html/detector_doc.html +* doc/html/parser_doc.html From 160ff23209bfd8e7260c890809dd7e649592a146 Mon Sep 17 00:00:00 2001 From: andy Date: Tue, 14 Jul 2009 01:30:59 -0700 Subject: [PATCH 190/387] [NEW] add new gestalts; from me and Robin --- README | 7 + ruby/gestalt/definition.rb | 1 + ruby/gestalt/definitions.rb | 26 ++- ruby/gestalt/java_definitions.rb | 38 +++- ruby/gestalt/rules/logical_rule.rb | 4 + ruby/gestalt/rules/not_rule.rb | 16 ++ test/unit/gestalt/definitions_test.rb | 238 ------------------------ test/unit/gestalt/file_rule_test.rb | 54 ------ test/unit/gestalt/filename_rule_test.rb | 19 -- test/unit/gestalt/gestalt_test.rb | 6 - test/unit/gestalt/keyword_rule_test.rb | 20 -- test/unit/gestalt/rule_test.rb | 11 -- test/unit/ruby/gestalt/definitions_test.rb | 90 +++++++-- test/unit/ruby/gestalt/java_definitions_test.rb | 44 +++++ 14 files changed, 203 insertions(+), 371 deletions(-) create mode 100644 ruby/gestalt/rules/not_rule.rb delete mode 100644 test/unit/gestalt/definitions_test.rb delete mode 100644 test/unit/gestalt/file_rule_test.rb delete mode 100644 test/unit/gestalt/filename_rule_test.rb delete mode 100644 test/unit/gestalt/gestalt_test.rb delete mode 100644 test/unit/gestalt/keyword_rule_test.rb delete mode 100644 test/unit/gestalt/rule_test.rb diff --git a/README b/README index b94bced..d520d97 100644 --- a/README +++ b/README @@ -4,7 +4,14 @@ To build docs, do To read docs, open html/index.html in a browser. First build them, as described above. +Most info is available in docs. + To add support for a new language, you'll need to implement both a detector and a parser. Documentation at * doc/html/detector_doc.html * doc/html/parser_doc.html + + +DEPENDENCIES +============ +SWIG, pcre, ragel diff --git a/ruby/gestalt/definition.rb b/ruby/gestalt/definition.rb index b8729d6..c8e884b 100644 --- a/ruby/gestalt/definition.rb +++ b/ruby/gestalt/definition.rb @@ -2,6 +2,7 @@ require 'gestalt/rules/logical_rule' require 'gestalt/rules/or_rule' require 'gestalt/rules/and_rule' +require 'gestalt/rules/not_rule' require 'gestalt/rules/language_rule' require 'gestalt/rules/file_rule' require 'gestalt/rules/filename_rule' diff --git a/ruby/gestalt/definitions.rb b/ruby/gestalt/definitions.rb index 2881e96..d9f9779 100644 --- a/ruby/gestalt/definitions.rb +++ b/ruby/gestalt/definitions.rb @@ -213,7 +213,7 @@ module Gestalt end define_platform 'xL_flag' do - make_keywords 'xL', '\/QxL' + make_keywords '\bxL\b', '\/QxL\b' end define_platform 'atom' do @@ -221,11 +221,15 @@ module Gestalt gestalt(:platform, 'xL_flag') end - ####################### INTEL COMPILER ############################# + ########################## COMPILER ################################ define_platform 'intel_compiler' do make_keywords '\bicc\b' end + define_platform 'gcc' do + make_keywords '\bgcc\b' + end + ########################### MOBLIN ################################# define_platform 'clutter' do @@ -280,10 +284,28 @@ module Gestalt gestalt(:platform, 'hildon') end + define_platform 'MID_combined' do + gestalt(:platform, 'clutter') + gestalt(:platform, 'nbtk') + gestalt(:platform, 'moblin') + gestalt(:platform, 'maemo') + gestalt(:platform, 'android') + gestalt(:platform, 'iPhone') + end + + ############################ Windows CE ############################ define_platform 'windows_ce_incomplete' do csharp_keywords 'Microsoft.WindowsCE', 'Microsoft.WindowsMobile' vb_keywords 'Microsoft.WindowsCE', 'Microsoft.WindowsMobile' end + + ######################### Native Code ############################## + define_platform 'native_code' do + language :c, :min_percent => 5 + language :cpp, :min_percent => 5 + language :cncpp, :min_percent => 5 + language :assembly, :min_percent => 5 + end end end diff --git a/ruby/gestalt/java_definitions.rb b/ruby/gestalt/java_definitions.rb index e9ff400..0606f90 100644 --- a/ruby/gestalt/java_definitions.rb +++ b/ruby/gestalt/java_definitions.rb @@ -86,15 +86,38 @@ module Gestalt end end - define_platform 'EJB3' do + # Caution! The EJB platform definitions are senstive to their order -- do not reorder! + # The gestalt engine iterates over definitions in the order they are defined. + # + # First, look for the subset of new features that definitely indicate EJB 3.1 + define_platform 'EJB3.1' do _and do gestalt(:platform, 'Java') _or do - java_keywords '@Stateless', '@Statefull', '@Entity', '@Remote', '@Local', '@BusinessMethod' + java_keywords '@Schedule', '@Singleton', '@Asynchronous' + java_keywords /@EJB\(.*\bmappedName\s*=\s*"java:(global|app|module)\/.+".*\)/ + java_keywords /\blookup\(\s*"java:(global|app|module)\/.+"\s*\)/ + end + end + end + # Next, look for the basic attributes that can mean either EJB 3.0 or 3.1 + define_platform 'EJB3+' do + _and do + gestalt(:platform, 'Java') + _or do + gestalt(:platform, 'EJB3.1') + java_keywords '@EJB', '@Stateless', '@Statefull', '@Entity', '@Remote', '@Local', '@BusinessMethod' java_import /^javax\.persistence\b/ end end end + # Finally, if we found EJB3+ and not EJB 3.1, then you must be using EJB 3.0 only. + define_platform 'EJB3.0' do + _and do + gestalt(:platform, 'EJB3+') + _not { gestalt(:platform, 'EJB3.1') } + end + end define_platform 'Servlet' do _and do @@ -106,6 +129,17 @@ module Gestalt end end + define_platform 'Struts' do + _and do + gestalt(:platform, 'Java') + _or do + filenames('\bstruts(\-config)?\.xml$', '\bstruts\.jar$') + java_import /^org\.apache\.struts\b/ + maven_dependency /^org\.apache\.struts\b/ + end + end + end + define_platform 'SpringFramework' do _and do gestalt(:platform,'Java') diff --git a/ruby/gestalt/rules/logical_rule.rb b/ruby/gestalt/rules/logical_rule.rb index c3626cc..6953301 100644 --- a/ruby/gestalt/rules/logical_rule.rb +++ b/ruby/gestalt/rules/logical_rule.rb @@ -32,6 +32,10 @@ def _and(*args, &block) new_rule AndRule, *args, &block end + def _not(*args, &block) + new_rule NotRule, *args, &block + end + def gestalt(*args) new_rule GestaltRule, *args end diff --git a/ruby/gestalt/rules/not_rule.rb b/ruby/gestalt/rules/not_rule.rb new file mode 100644 index 0000000..d782537 --- /dev/null +++ b/ruby/gestalt/rules/not_rule.rb @@ -0,0 +1,16 @@ +module Ohcount + module Gestalt + class NotRule < LogicalRule + def triggers(gestalt_engine) + rules.first && rules.first.triggers(gestalt_engine).any? ? [] : [Trigger.new] + end + + def new_rule(r_class, *args, &block) + raise ArgumentError.new("_not() accepts only a single rule") unless rules.empty? + super(r_class, *args, &block) + end + + end + end +end + diff --git a/test/unit/gestalt/definitions_test.rb b/test/unit/gestalt/definitions_test.rb deleted file mode 100644 index 78dd565..0000000 --- a/test/unit/gestalt/definitions_test.rb +++ /dev/null @@ -1,238 +0,0 @@ -require 'test/unit' -require '../../../ruby/gestalt' - -include Ohcount -include Ohcount::Gestalt - -class PlatformTest < Test::Unit::TestCase - - def test_zend_framework - assert_gestalts 'zend_framework', [ - Base.new(:platform,'PHP'), - Base.new(:platform,'ZendFramework'), - Base.new(:platform,'Scripting') - ] - end - - def test_php - assert_gestalts 'php', [ - Base.new(:platform,'PHP'), - Base.new(:platform,'Scripting') - ] - end - - def test_wx_widgets - assert_gestalts 'wx_widgets', [ - Base.new(:platform,'WxWidgets') - ] - end - - def test_eclipse_platform - assert_gestalts 'eclipse_platform', [ - Base.new(:platform,'Java'), - Base.new(:platform,'EclipsePlatform'), - Base.new(:java_import,"java.text.SimpleDateFormat"), - Base.new(:java_import,"java.util.Map"), - Base.new(:java_import,"org.eclipse.core.lotsa_stuff") - ] - end - - def test_win32_not_enough - assert_gestalts 'win32_not_enough', [] - end - - def test_win32_enough - assert_gestalts 'win32_enough', [ - Base.new(:platform, 'Win32') - ] - end - - def test_wpf - assert_gestalts 'wpf', [ - Base.new(:platform, 'WPF') - ] - end - - def test_asp_net - assert_gestalts 'asp_net', [ - Base.new(:platform, 'ASP_NET') - ] - end - - def test_ruby_just_enough - assert_gestalts 'ruby_just_enough', [ - Base.new(:platform, 'Ruby'), - Base.new(:platform, 'Scripting') - ] - end - - def test_ruby_not_enough - assert_gestalts 'ruby_not_enough', [] - end - - def test_cakephp - assert_gestalts 'cakephp', [ - Base.new(:platform, 'PHP'), - Base.new(:platform, 'CakePHP'), - Base.new(:platform, 'Scripting'), - ] - end - - def test_symfony - assert_platform('symfony', :PHP, :Symfony, :Scripting) - end - - def test_pear - assert_platform('pear', :PHP, :Pear, :Scripting) - end - - def test_moodle - assert_platform('moodle', :PHP, :Moodle, :Scripting) - end - - def test_spring_framework - assert_gestalts 'spring_framework', [ - Base.new(:platform, 'Java'), - Base.new(:platform, 'SpringFramework'), - Base.new(:java_jar, 'spring.jar'), - ] - end - - def test_rails - assert_platform('rails', :Ruby, :Rails, :Scripting) - end - - def test_jquery - assert_platform('jquery', :Javascript, :JQuery, :Scripting) - end - - def test_python - assert_platform('python', :Python, :Scripting) - end - - def test_mac - assert_platform('mac', :Mac) - end - - def test_plist - assert_platform('plist', :Mac) - end - - def test_posix - assert_platform('posix', :POSIX) - end - - def test_x_windows - assert_platform('xwindows', :XWindows) - end - - def test_kde - assert_platform('kde', :KDE) - end - - def test_msdos - assert_platform('msdos', :MSDos) - end - - def test_gtk - assert_platform('gtk', :GTK) - end - - def test_drupal - assert_platform('drupal', :PHP, :Drupal, :Scripting) - end - - def test_vs_1 - assert_tool('vs_1', :VisualStudio) - end - - def test_eclipse - assert_tool('eclipse', :Eclipse) - end - - def test_netbeans - assert_tool('netbeans', :NetBeans) - end - - def test_java_imports_from_java_file - java = SourceFile.new("foo.java", :contents => <<-INLINE_C - import com.foo; - import net.ohloh; - import com.foo; - // import dont.import.this; - INLINE_C - ) - - expected_gestalts = [ - Base.new(:java_import, 'com.foo', 2), - Base.new(:java_import, 'net.ohloh'), - Base.new(:platform, 'Java'), - ] - - assert_equal expected_gestalts.sort, java.gestalts.sort - end - - def test_arm - asm = SourceFile.new("foo.S", :contents => <<-INLINE_ASM - orrs 3, eax - INLINE_ASM - ) - - expected_gestalts = [ - Base.new(:platform, 'arm') - ] - - assert_equal expected_gestalts.sort, asm.gestalts.sort - end - - def test_arm_neon - asm = SourceFile.new("foo.S", :contents => <<-INLINE_ASM - vmov u8, s - INLINE_ASM - ) - - expected_gestalts = [ - Base.new(:platform, 'arm'), - Base.new(:platform, 'arm_neon') - ] - - assert_equal expected_gestalts.sort, asm.gestalts.sort - end - - def test_imports_from_java_file - jar = SourceFile.new("foo/foo.jar", :contents => '') - - expected_gestalts = [ - Base.new(:java_jar, 'foo.jar'), - ] - - assert_equal expected_gestalts.sort, jar.gestalts.sort - end - - protected - - def assert_tool(path, *tools) - gestalts = tools.map do |t| - Base.new(:tool, t.to_s) - end - assert_gestalts path, gestalts - end - - def assert_platform(path, *platforms) - gestalts = platforms.map do |p| - Base.new(:platform, p.to_s) - end - assert_gestalts path, gestalts - end - - def assert_gestalts(path, expected_gestalts) - sfl = SourceFileList.new() - sfl.add_directory(test_dir(path)) - sfl.analyze_gestalt - assert_equal expected_gestalts.sort, sfl.gestalts.sort - end - - def test_dir(d) - File.expand_path(File.dirname(__FILE__) + "/../../gestalt_files/#{ d }") - end -end diff --git a/test/unit/gestalt/file_rule_test.rb b/test/unit/gestalt/file_rule_test.rb deleted file mode 100644 index a2e4955..0000000 --- a/test/unit/gestalt/file_rule_test.rb +++ /dev/null @@ -1,54 +0,0 @@ -require 'test/unit' -require '../../../ruby/gestalt' - -class FileRuleTest < Test::Unit::TestCase - include Ohcount::Gestalt - - def test_initialize - r = FileRule.new(:min => 5) - assert_equal 5, r.min_count - end - - def test_initialize_wrong_args - assert_raise ArgumentError do - r = FileRule.new(:boo => 1) - end - end - -# def test_trigger_c_header -# r = Ohcount::Gestalt::CHeaderRule.new('foo.h') -# s = Ohcount::SourceFile.new('header.h', :contents => <<-H_FILE -# // a comment -# include 'foo.h' -# H_FILE -# ) -# assert r.trigger_file?(s) -# end -# -# def test_c_keyword_rule -# r = Ohcount::Gestalt::CKeywordRule.new('WM_PAINT') -# s = Ohcount::SourceFile.new('header.h', :contents => <<-H_FILE -# // a comment -# (WM_PAINT) -# H_FILE -# ) -# assert r.trigger_file?(s) -# end -# -# def test_filename_rule -# r = Ohcount::Gestalt::FilenameRule.new('header.h') -# s = Ohcount::SourceFile.new('header.h') -# assert r.trigger_file?(s) -# end -# -# def test_filename_rule_advanced -# r = Ohcount::Gestalt::FilenameRule.new('f[ab]o', 'foo') -# assert r.trigger_file?(Ohcount::SourceFile.new('fao')) -# assert r.trigger_file?(Ohcount::SourceFile.new('fbo')) -# assert r.trigger_file?(Ohcount::SourceFile.new('foo')) -# assert !r.trigger_file?(Ohcount::SourceFile.new('fco')) -# end -end - - - diff --git a/test/unit/gestalt/filename_rule_test.rb b/test/unit/gestalt/filename_rule_test.rb deleted file mode 100644 index 2798394..0000000 --- a/test/unit/gestalt/filename_rule_test.rb +++ /dev/null @@ -1,19 +0,0 @@ -require 'test/unit' -require '../../../ruby/gestalt' - -class FilenameRuleTest < Test::Unit::TestCase - include Ohcount::Gestalt - - def test_process_file - r = FilenameRule.new('foo\.rb') - s = Ohcount::SourceFile.new('/bar/com/foo.rb', :contents => <<-RUBY_CODE - # comment - code = 1 - RUBY_CODE - ) - assert r.process_source_file(s) - assert_equal 1, r.count - end -end - - diff --git a/test/unit/gestalt/gestalt_test.rb b/test/unit/gestalt/gestalt_test.rb deleted file mode 100644 index 9daf474..0000000 --- a/test/unit/gestalt/gestalt_test.rb +++ /dev/null @@ -1,6 +0,0 @@ -require 'test/unit' -require 'definitions_test' -require 'file_rule_test' -require 'filename_rule_test' -require 'keyword_rule_test' -require 'rule_test' diff --git a/test/unit/gestalt/keyword_rule_test.rb b/test/unit/gestalt/keyword_rule_test.rb deleted file mode 100644 index 2292f0f..0000000 --- a/test/unit/gestalt/keyword_rule_test.rb +++ /dev/null @@ -1,20 +0,0 @@ -require 'test/unit' -require '../../../ruby/gestalt' - -class KeywordRuleTest < Test::Unit::TestCase - include Ohcount::Gestalt - - def test_process_file - r = KeywordRule.new('c', 'WIN32') - s = Ohcount::SourceFile.new('header.c', :contents => <<-C_CODE - // a comment - #ifdef WIN32 - ..some code.. - #endif - C_CODE - ) - assert r.process_source_file(s) - assert_equal 1, r.count - end -end - diff --git a/test/unit/gestalt/rule_test.rb b/test/unit/gestalt/rule_test.rb deleted file mode 100644 index 2a6714a..0000000 --- a/test/unit/gestalt/rule_test.rb +++ /dev/null @@ -1,11 +0,0 @@ -require 'test/unit' -require '../../../ruby/gestalt' - -class RuleTest < Test::Unit::TestCase - - def test_here - - end -end - - diff --git a/test/unit/ruby/gestalt/definitions_test.rb b/test/unit/ruby/gestalt/definitions_test.rb index 4c47556..e56638e 100644 --- a/test/unit/ruby/gestalt/definitions_test.rb +++ b/test/unit/ruby/gestalt/definitions_test.rb @@ -4,7 +4,7 @@ include Ohcount include Ohcount::Gestalt -class PlatformTest < Ohcount::Test +class DefinitionsTest < Ohcount::Test def test_zend_framework assert_gestalts 'zend_framework', [ @@ -23,7 +23,8 @@ def test_php def test_wx_widgets assert_gestalts 'wx_widgets', [ - Base.new(:platform,'WxWidgets') + Base.new(:platform,'WxWidgets'), + Base.new(:platform, 'native_code') ] end @@ -38,12 +39,15 @@ def test_eclipse_platform end def test_win32_not_enough - assert_gestalts 'win32_not_enough', [] + assert_gestalts 'win32_not_enough', [ + Base.new(:platform, 'native_code') + ] end def test_win32_enough assert_gestalts 'win32_enough', [ - Base.new(:platform, 'Win32') + Base.new(:platform, 'Win32'), + Base.new(:platform, 'native_code') ] end @@ -62,12 +66,15 @@ def test_asp_net def test_ruby_just_enough assert_gestalts 'ruby_just_enough', [ Base.new(:platform, 'Ruby'), - Base.new(:platform, 'Scripting') + Base.new(:platform, 'Scripting'), + Base.new(:platform, 'native_code'), ] end def test_ruby_not_enough - assert_gestalts 'ruby_not_enough', [] + assert_gestalts 'ruby_not_enough', [ + Base.new(:platform, 'native_code') + ] end def test_cakephp @@ -111,7 +118,7 @@ def test_python end def test_mac - assert_platform('mac', :Mac) + assert_platform('mac', :Mac, :native_code) end def test_plist @@ -119,23 +126,23 @@ def test_plist end def test_posix - assert_platform('posix', :POSIX) + assert_platform('posix', :POSIX, :native_code) end def test_x_windows - assert_platform('xwindows', :XWindows) + assert_platform('xwindows', :XWindows, :native_code) end def test_kde - assert_platform('kde', :KDE) + assert_platform('kde', :KDE, :native_code) end def test_msdos - assert_platform('msdos', :MSDos) + assert_platform('msdos', :MSDos, :native_code) end def test_gtk - assert_platform('gtk', :GTK) + assert_platform('gtk', :GTK, :native_code) end def test_drupal @@ -191,7 +198,8 @@ def test_arm_from_c_keywords INLINE_C ) expected_gestalts = [ - Base.new(:platform, 'arm') + Base.new(:platform, 'arm'), + Base.new(:platform, 'native_code') ] assert_equal expected_gestalts, c.gestalts end @@ -227,7 +235,9 @@ def test_moblin_clutter ) expected_gestalts = [ Base.new(:platform, 'clutter'), - Base.new(:platform, 'moblin_all') + Base.new(:platform, 'moblin_all'), + Base.new(:platform, 'MID_combined'), + Base.new(:platform, 'native_code') ] assert_equal expected_gestalts.sort, c.gestalts.sort @@ -240,7 +250,9 @@ def test_moblin_by_filename ) expected_gestalts = [ Base.new(:platform, 'moblin'), - Base.new(:platform, 'moblin_all') + Base.new(:platform, 'moblin_all'), + Base.new(:platform, 'MID_combined'), + Base.new(:platform, 'native_code') ] assert_equal expected_gestalts.sort, c.gestalts.sort @@ -253,7 +265,9 @@ def test_moblin_by_keyword ) expected_gestalts = [ Base.new(:platform, 'moblin'), - Base.new(:platform, 'moblin_all') + Base.new(:platform, 'moblin_all'), + Base.new(:platform, 'MID_combined'), + Base.new(:platform, 'native_code') ] assert_equal expected_gestalts.sort, c.gestalts.sort @@ -266,7 +280,9 @@ def test_nbtk ) expected_gestalts = [ Base.new(:platform, 'nbtk'), - Base.new(:platform, 'moblin_all') + Base.new(:platform, 'MID_combined'), + Base.new(:platform, 'moblin_all'), + Base.new(:platform, 'native_code') ] assert_equal expected_gestalts.sort, c.gestalts.sort @@ -284,6 +300,7 @@ def test_android Base.new(:java_import, 'android.app.Activity'), Base.new(:platform, 'Java'), Base.new(:platform, 'android'), + Base.new(:platform, 'MID_combined') ] assert_equal expected_gestalts.sort, java.gestalts.sort @@ -306,6 +323,7 @@ def test_iphone expected_gestalts = [ Base.new(:platform, 'iPhone'), + Base.new(:platform, 'MID_combined') ] assert_equal expected_gestalts.sort, objective_c.gestalts.sort @@ -318,7 +336,9 @@ def test_hildon ) expected_gestalts = [ Base.new(:platform, 'hildon'), - Base.new(:platform, 'maemo') + Base.new(:platform, 'maemo'), + Base.new(:platform, 'native_code'), + Base.new(:platform, 'MID_combined') ] assert_equal expected_gestalts.sort, c.gestalts.sort @@ -348,6 +368,15 @@ def test_atom_windows assert_equal expected_gestalts.sort, make.gestalts.sort end + def test_not_atom_windows + make = SourceFile.new("makefile", :contents => <<-INLINE_MAKEFILE + CCFLAGS = -xLo + INLINE_MAKEFILE + ) + expected_gestalts = [] + assert_equal expected_gestalts.sort, make.gestalts.sort + end + def test_atom_sse3 make = SourceFile.new("makefile", :contents => <<-INLINE_MAKEFILE COMPILE_FLAGS=-xSSE3_ATOM_FLAG @@ -397,6 +426,29 @@ def test_windows_ce Base.new(:platform, 'Dot_NET'), ] - assert_equal expected_gestalts.sort, csharp.gestalts.sort + assert_equal expected_gestalts.sort, csharp.gestalts.sort + end + + def test_gcc + make = SourceFile.new("Makefile", :contents => <<-INLINE_MAKEFILE + CC = gcc + INLINE_MAKEFILE + ) + expected_gestalts = [ + Base.new(:platform, 'gcc'), + ] + assert_equal expected_gestalts.sort, make.gestalts.sort + end + + def test_native_code + c = SourceFile.new("foo.c", :contents => <<-INLINE_C + int *pcode = NULL; + INLINE_C + ) + expected_gestalts = [ + Base.new(:platform, 'native_code'), + ] + assert_equal expected_gestalts.sort, c.gestalts.sort end + end diff --git a/test/unit/ruby/gestalt/java_definitions_test.rb b/test/unit/ruby/gestalt/java_definitions_test.rb index f7c84fe..7da4f03 100644 --- a/test/unit/ruby/gestalt/java_definitions_test.rb +++ b/test/unit/ruby/gestalt/java_definitions_test.rb @@ -28,4 +28,48 @@ def test_webshpere_via_descriptor Base.new(:platform, 'WebSphere') ] end + + def test_ejb30_by_default + sf = SourceFile.new('hello.java', :contents => <<-JAVA + @Stateless + public class HelloBean { } + JAVA + ) + assert_equal [ + Base.new(:platform, 'Java'), + Base.new(:platform, 'EJB3+'), + Base.new(:platform, 'EJB3.0') + ].sort, sf.gestalts.sort + end + + + def test_ejb31_through_annotation + sf = SourceFile.new('hello.java', :contents => <<-JAVA + @Stateless + public class HelloBean { + @Asynchronous public Future getHelloValue() {} + } + JAVA + ) + assert_equal [ + Base.new(:platform, 'Java'), + Base.new(:platform, 'EJB3+'), + Base.new(:platform, 'EJB3.1') + ].sort, sf.gestalts.sort + end + + def test_ejb31_through_global_jndi + sf = SourceFile.new('hello.java', :contents => <<-JAVA + public class PlaceBidClient { + context.lookup("java:global/action-bazaar/PlaceBid"); + } + JAVA + ) + assert_equal [ + Base.new(:platform, 'Java'), + Base.new(:platform, 'EJB3+'), + Base.new(:platform, 'EJB3.1') + ].sort, sf.gestalts.sort + end + end From 250008fcaa2d1af5d4afdc5ef6d3b79d37332c6a Mon Sep 17 00:00:00 2001 From: andy Date: Tue, 14 Jul 2009 02:43:17 -0700 Subject: [PATCH 191/387] [CHANGE] from robin: [CHANGE] The phrase "MIT/X11 licensed" is now accepted as a trigger for the MIT license --- src/licenses.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/licenses.c b/src/licenses.c index 816ecf7..5405244 100644 --- a/src/licenses.c +++ b/src/licenses.c @@ -383,7 +383,7 @@ License license_map[] = { LIC_MIT, "http://www.opensource.org/licenses/mit-license.php", "MIT license", - "(\\bmit\\s*license\\b)|(\\bMIT\\/X11\\s*license\\b)", + "(\\bmit\\s*license\\b)|(\\bMIT\\/X11\\s*licensed?\\b)", PCRE_CASELESS, NULL, 0, From 1a00414ef0c0338ac741ebebe3367599c4dc513c Mon Sep 17 00:00:00 2001 From: andy Date: Tue, 14 Jul 2009 02:44:05 -0700 Subject: [PATCH 192/387] [FIX] allow gestalts tests to be run by individually --- test/unit/ruby/gestalt/gestalt_test.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/test/unit/ruby/gestalt/gestalt_test.rb b/test/unit/ruby/gestalt/gestalt_test.rb index ae9ad29..ebb9846 100644 --- a/test/unit/ruby/gestalt/gestalt_test.rb +++ b/test/unit/ruby/gestalt/gestalt_test.rb @@ -1,4 +1,5 @@ require 'test/unit' +require File.dirname(__FILE__) + '/../test_helper.rb' require File.dirname(__FILE__) + '/definitions_test' require File.dirname(__FILE__) + '/file_rule_test' require File.dirname(__FILE__) + '/filename_rule_test' From 8d2ec6e3af58240143168811649d5f3ea987d86f Mon Sep 17 00:00:00 2001 From: andy Date: Tue, 14 Jul 2009 11:56:43 -0700 Subject: [PATCH 193/387] [NEW] adding ubuntu-amd 64 binaries to files; the ohcount binary should be in an architecture specific directory --- bin/ohcount | Bin 0 -> 2500419 bytes ruby/x86_64-linux/ohcount.so | Bin 0 -> 2680693 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100755 bin/ohcount create mode 100755 ruby/x86_64-linux/ohcount.so diff --git a/bin/ohcount b/bin/ohcount new file mode 100755 index 0000000000000000000000000000000000000000..3164ae9612d55e20f270681329f3065289e53285 GIT binary patch literal 2500419 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ʀ(mULQ`sp2W*CvhZdh951W8201kOB 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

ofU!mIRqBn{odw*tj+q^%dujX-tn* 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

-
Generated on Fri Aug 28 15:20:08 2009 for ohcount by  +
Generated on Fri Aug 28 16:26:52 2009 for ohcount by  doxygen 1.5.9
diff --git a/src/ohcount.h b/src/ohcount.h index 86e9bda..f9f1182 100644 --- a/src/ohcount.h +++ b/src/ohcount.h @@ -54,7 +54,7 @@ * * Ohcount source code is available as a Git repository: * - * git clone http://git.ohloh.net/git/ohcount.git + * git clone git://ohcount.git.sourceforge.net/gitroot/ohcount/ohcount * * @section build Building Ohcount * From abc4e1019fe742ecd8c54f8739ed160ed123320e Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Tue, 1 Sep 2009 11:15:48 -0700 Subject: [PATCH 220/387] [FIX] Allocate large buffer on heap, not stack. --- test/unit/sourcefile_test.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/unit/sourcefile_test.h b/test/unit/sourcefile_test.h index 3c44d5a..1c03d07 100644 --- a/test/unit/sourcefile_test.h +++ b/test/unit/sourcefile_test.h @@ -127,15 +127,15 @@ void test_sourcefile_diff_longer() { } void test_sourcefile_diff_very_long() { - char a[5500000]; - memset(a, 'i', sizeof(a)); - a[sizeof(a)] = '\0'; - a[sizeof(a)-1] = '\n'; + int len = 5500000; + char *a = malloc(len); + memset(a, 'i', len); + a[len-1] = '\0'; + a[len-2] = '\n'; SourceFile *old = ohcount_sourcefile_new("foo.c"); ohcount_sourcefile_set_contents(old, a); strncpy(a, "int = 1;\n", strlen("int = 1;\n")); - if (strlen(a) < 100) exit(0) ; SourceFile *new = ohcount_sourcefile_new("foo.c"); ohcount_sourcefile_set_contents(new, a); LocDeltaList *list = ohcount_sourcefile_diff(old, new); From 1cb8a01d577e48ae47341235bdc47720e70c9309 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Tue, 1 Sep 2009 11:16:33 -0700 Subject: [PATCH 221/387] [FIX] large files crashed during license detection; allocate buffer on heap, not stack --- src/licenses.c | 35 +++++++++++++++++++++++------------ test/unit/license_test.h | 23 ++++++++++++++++++++--- 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/src/licenses.c b/src/licenses.c index 5405244..7c68712 100644 --- a/src/licenses.c +++ b/src/licenses.c @@ -3,6 +3,7 @@ #include #include +#include #include "licenses.h" #include "parser.h" @@ -778,28 +779,38 @@ LicenseList *ohcount_detect_license(SourceFile *sourcefile) { char *p, *q; int i, j, k; int ovector[30]; // recommended by PCRE - ParsedLanguageList *iter; - iter = ohcount_sourcefile_get_parsed_language_list(sourcefile)->head; - if (iter) { + ParsedLanguageList *iter_language; + iter_language = ohcount_sourcefile_get_parsed_language_list(sourcefile)->head; + if (iter_language) { int potential_licenses_s[license_map_length]; int potential_licenses_e[license_map_length]; - while (iter) { - char buffer[ohcount_sourcefile_get_contents_size(sourcefile)]; - p = iter->pl->comments; + while (iter_language) { + // Before looking for licenses, strip whitespace and newlines + p = iter_language->pl->comments; + int buffer_len = p ? strlen(p) : 0; + char *p_max = p + buffer_len; + + char *buffer = malloc(buffer_len+1); + if (buffer == NULL) { + fprintf(stderr, "out of memory in ohcount_detect_license"); + exit -1; + } q = buffer; - char *eof = p + strlen(p); - while (p < eof) { + char *q_max = buffer + buffer_len + 1; + + while (p < p_max && q < q_max) { // Strip leading whitespace and punctuation. while (*p == ' ' || *p == '\t' || ispunct(*p)) p++; // Copy line contents. - while (p < eof && *p != '\r' && *p != '\n') *q++ = *p++; + while (p < p_max && *p != '\r' && *p != '\n' && q < q_max) + *q++ = *p++; // Strip newline characters. while (*p == '\r' || *p == '\n') p++; // Add a trailing space. - *q++ = ' '; + if (q < q_max) *q++ = ' '; } - *q = '\0'; + if (q < q_max) *q = '\0'; for (j = 0; j < license_map_length; j++) { potential_licenses_s[j] = -1; @@ -832,7 +843,7 @@ LicenseList *ohcount_detect_license(SourceFile *sourcefile) { } } } - iter = iter->next; + iter_language = iter_language->next; } // Create the list of licenses from potential licenses. diff --git a/test/unit/license_test.h b/test/unit/license_test.h index 57a818b..b804f37 100644 --- a/test/unit/license_test.h +++ b/test/unit/license_test.h @@ -8,7 +8,7 @@ #include "../../src/licenses.h" -void all_license_tests() { +void src_vs_expected_tests() { const char *src_licenses = "../src_licenses/"; char src[FILENAME_MAX]; strncpy(src, src_licenses, strlen(src_licenses)); @@ -42,13 +42,12 @@ void all_license_tests() { SourceFile *sf = ohcount_sourcefile_new((const char *)src); LicenseList *iter = ohcount_sourcefile_get_license_list(sf)->head; char line[40]; // max license name size - while (fgets(line, sizeof(line), f)) { + for (; fgets(line, sizeof(line), f); iter = iter->next) { p = strstr(line, "\r"); if (p == NULL) p = strstr(line, "\n"); if (p) *p = '\0'; assert(iter->lic->name); assert(strcmp(line, iter->lic->name) == 0); - iter = iter->next; } fclose(f); ohcount_sourcefile_free(sf); @@ -58,3 +57,21 @@ void all_license_tests() { closedir(d); } } + +void very_long_file_test() { + int len = 5500000; + char *a = malloc(len); + memset(a, 'i', len); + a[len-1] = '\0'; + a[len-2] = '\n'; + + SourceFile *sf = ohcount_sourcefile_new("foo.c"); + ohcount_sourcefile_set_contents(sf, a); + strncpy(a, "int = 1;\n", strlen("int = 1;\n")); + ohcount_sourcefile_get_license_list(sf); +} + +void all_license_tests() { + src_vs_expected_tests(); + very_long_file_test(); +} From 3a15ae896e367eb1cfed4868e8a80a012fbda6b7 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Tue, 1 Sep 2009 17:29:25 +0200 Subject: [PATCH 222/387] [FIX] sourcefile: detect errors from fread(3) --- src/sourcefile.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/sourcefile.c b/src/sourcefile.c index 0322c57..438e5c1 100644 --- a/src/sourcefile.c +++ b/src/sourcefile.c @@ -86,9 +86,14 @@ char *ohcount_sourcefile_get_contents(SourceFile *sourcefile) { int size = ftell(f); rewind(f); sourcefile->contents = malloc(size + 1); - fread(sourcefile->contents, 1, size, f); - sourcefile->contents[size] = '\0'; - sourcefile->size = size; + if (fread(sourcefile->contents, size, 1, f) != 1) { + free(sourcefile->contents); + sourcefile->contents = NULL; + sourcefile->size = 0; + } else { + sourcefile->size = size; + sourcefile->contents[size] = '\0'; + } fclose(f); } else { sourcefile->contents = NULL; From 002e863981eb3130fc00ac33610fafc934adb5f0 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Tue, 1 Sep 2009 17:31:25 +0200 Subject: [PATCH 223/387] [FIX] line was being used uninitialized --- src/detector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detector.c b/src/detector.c index 57865a0..f3c1ec9 100644 --- a/src/detector.c +++ b/src/detector.c @@ -56,7 +56,7 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { ohcount_hash_language_from_filename(sourcefile->filename, length); if (rf) return rf->value; - char line[81], buf[81]; + char line[81] = { '\0' }, buf[81]; // Attempt to detect using Emacs mode line (/^-\*-\s*mode[\s:]*\w/i). p = ohcount_sourcefile_get_contents(sourcefile); From e7a96991fbfa30fee7448d8fd3af26ba190ea358 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Tue, 1 Sep 2009 17:32:28 +0200 Subject: [PATCH 224/387] [FIX] work around some off-by-one errors --- src/detector.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/detector.c b/src/detector.c index f3c1ec9..8fde6a5 100644 --- a/src/detector.c +++ b/src/detector.c @@ -137,7 +137,7 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { pe = p; while (*p == ' ') p--; while (p != line && isalnum(*(p - 1))) p--; - if (*(p - 1) == '-') p--; + if (p != line && *(p - 1) == '-') p--; } while (*p == '-'); // Skip over any switches. length = pe - p; strncpy(buf, p, length); @@ -395,7 +395,7 @@ const char *disambiguate_h(SourceFile *sourcefile) { // Look for C++ keywords. p = line; while (p < eol) { - if (islower(*p) && !isalnum(*(p - 1)) && *(p - 1) != '_') { + if (islower(*p) && p != line && !isalnum(*(p - 1)) && *(p - 1) != '_') { pe = p; while (islower(*pe)) pe++; if (!isalnum(*pe) && *pe != '_') { @@ -563,7 +563,7 @@ const char *disambiguate_m(SourceFile *sourcefile) { // Look for Octave keywords. p = line; while (p < eol) { - if (islower(*p) && !isalnum(*(p - 1))) { + if (islower(*p) && p != line && !isalnum(*(p - 1))) { pe = p; while (islower(*pe) || *pe == '_') pe++; if (!isalnum(*pe)) { From 27c939328145d304adf5c274dcd0054d9fded08b Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Tue, 1 Sep 2009 18:33:26 +0200 Subject: [PATCH 225/387] [FIX] another off-by-one (forgot \0) --- src/detector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detector.c b/src/detector.c index 8fde6a5..70e41f1 100644 --- a/src/detector.c +++ b/src/detector.c @@ -111,7 +111,7 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { close(fd); tmpfile = 1; } - char command[strlen(path) + 10]; + char command[strlen(path) + 11]; sprintf(command, "file -b '%s'", path); FILE *f = popen(command, "r"); if (f) { From ed86a9e6b1b96fea0b058fd513b59344258b3d55 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Tue, 1 Sep 2009 19:25:18 +0200 Subject: [PATCH 226/387] [FIX] We really need those null bytes --- src/detector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detector.c b/src/detector.c index 70e41f1..4d0e1f4 100644 --- a/src/detector.c +++ b/src/detector.c @@ -32,7 +32,7 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { if (re) language = re->value; if (language == NULL) { // Try the lower-case version of this extension. - char lowerext[length]; + char lowerext[length + 1]; strncpy(lowerext, sourcefile->ext, length); lowerext[length] = '\0'; for (p = lowerext; p < lowerext + length; p++) *p = tolower(*p); From 9da48105ffbff6080820fb5079d34acc277704e3 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Tue, 1 Sep 2009 14:50:27 -0700 Subject: [PATCH 227/387] [FIX] exit is a function; why no error/warning on MAC? --- src/licenses.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/licenses.c b/src/licenses.c index 7c68712..f0cd90f 100644 --- a/src/licenses.c +++ b/src/licenses.c @@ -794,7 +794,7 @@ LicenseList *ohcount_detect_license(SourceFile *sourcefile) { char *buffer = malloc(buffer_len+1); if (buffer == NULL) { fprintf(stderr, "out of memory in ohcount_detect_license"); - exit -1; + exit(-1); } q = buffer; char *q_max = buffer + buffer_len + 1; From 18d52620ed25ef9b30b8261aacfbe1726f626ba5 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Wed, 2 Sep 2009 16:11:59 -0700 Subject: [PATCH 228/387] [FIX] Spelling correction for Objective-C --- src/hash/languages.gperf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index ed30e7e..0533950 100644 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -52,7 +52,7 @@ metapost, LANG_METAPOST, "MetaPost", 1 metapost_with_tex, LANG_METAPOST_WITH_TEX, "", 0 mxml, LANG_MXML, "MXML", 1 nix, LANG_NIX, "Nix", 0 -objective_c, LANG_OBJECTIVE_C, "Objective C", 0 +objective_c, LANG_OBJECTIVE_C, "Objective-C", 0 objective_j, LANG_OBJECTIVE_J, "Objective-J", 0 ocaml, LANG_OCAML, "Objective Caml", 0 octave, LANG_OCTAVE, "", 0 From badf6dc52c08cb8ac31bf35d24950f30128f4bbc Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Wed, 2 Sep 2009 16:37:26 -0700 Subject: [PATCH 229/387] [CHANGE] Add support for FreeBSD (submitted by eg) --- build | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/build b/build index 50329f7..4595cdd 100755 --- a/build +++ b/build @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Build script for Ohcount. # Written by Mitchell Foral. mitchellcaladbolg.net. @@ -9,6 +9,13 @@ then # Linux INC_DIR= LIB_DIR= + + if [ `uname` == "FreeBSD" ] + then + INC_DIR=/usr/local/include + LIB_DIR=/usr/local/lib + fi + # You shouldn't have to change the following. CFLAGS=-O3 WARN="-Wall -Wno-pointer-to-int-cast -Wno-parentheses" @@ -137,17 +144,17 @@ then elif [ $1 == "ruby" ] then build_ruby_bindings - echo "Build successful; $RB_SHARED_NAME is in ruby/" + echo "Build successful; $RB_SHARED_NAME is in ruby/$arch" elif [ $1 == "clean" ] then - rm bin/ohcount - rm test/unit/run_tests - rm src/parser.o - rm src/parsers/*.h - rm src/hash/*.h - rm src/hash/*.c - rm src/$SHARED_NAME - rm ruby/$RB_SHARED_NAME + rm -f bin/ohcount + rm -f test/unit/run_tests + rm -f src/parser.o + rm -f src/parsers/*.h + rm -f src/hash/*.h + rm -f src/hash/*.c + rm -f src/$SHARED_NAME + rm -f ruby/$RB_SHARED_NAME rm -rf ruby/`ruby -rmkmf -e 'print Config::expand(CONFIG["arch"])'`/* else echo "Usage: build [all|ohcount|shared|tests|ruby|clean]" From 5b2a44e698584e8c2bd13bc3f8fddbff76bea355 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Fri, 4 Sep 2009 15:07:43 -0700 Subject: [PATCH 230/387] [FIX] non-directory files in /tmp on CentOS have d_type of DT_UNKNOWN instead of DT_REG --- bin/ohcount | Bin 2013224 -> 2013308 bytes build | 1 + src/sourcefile.c | 6 +++++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/bin/ohcount b/bin/ohcount index 77c6880c500e005576b0e41a75024aa12bd98005..1359c797bd48cd348ed0404477b9770e5ae78308 100755 GIT binary patch literal 2013308 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

uLXZ-OZh|);hBFJCf**}$DLuMTTCCW-^nX0Fi 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%0AY!SdWgOT{k24q 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 Nef`gWel?rT{ulGNYsvrs literal 2013224 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�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∓nlX8@ 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%0A8jXf$vgo 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 U$rB{M%BN0WeEs$3v)Sx_0MeEs`v3p{ diff --git a/build b/build index 4595cdd..51d4611 100755 --- a/build +++ b/build @@ -18,6 +18,7 @@ then # You shouldn't have to change the following. CFLAGS=-O3 + CFLAGS="$CFLAGS TMP_FILES_ARE_DT_UNKNOWN" # workaround bug on centos/SF servers WARN="-Wall -Wno-pointer-to-int-cast -Wno-parentheses" SHARED=-shared SHARED_NAME=libohcount.so diff --git a/src/sourcefile.c b/src/sourcefile.c index 438e5c1..a46f755 100644 --- a/src/sourcefile.c +++ b/src/sourcefile.c @@ -438,7 +438,11 @@ void ohcount_sourcefile_list_add_directory(SourceFileList *list, if (file->d_type == DT_DIR && *file->d_name != '.') // no hidden dirs ohcount_sourcefile_list_add_directory(list, filepath); - else if (file->d_type == DT_REG) + else if (file->d_type == DT_REG +#ifdef TMP_FILES_ARE_DT_UNKNOWN + || file->d_type == DT_UNKNOWN +#endif + ) ohcount_sourcefile_list_add_file(list, filepath); } closedir(d); From 0ffdaa104711b8ab99e25f8fb3378ac043aaefaf Mon Sep 17 00:00:00 2001 From: pshiryaev Date: Mon, 7 Sep 2009 18:30:44 +0400 Subject: [PATCH 231/387] add support for F# --- src/hash/extensions.gperf | 1 + src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 2 + src/languages.h | 1 + src/parsers/fsharp.rl | 182 ++++++++++++++++++++++++++++++++++++++++ test/detect_files/fs1.fs | 3 + test/expected_dir/fs1.fs | 51 +++++++++++ test/src_dir/fs1.fs | 51 +++++++++++ test/unit/detector_test.h | 1 + test/unit/parser_test.h | 2 + test/unit/parsers/test_fsharp.h | 23 +++++ 11 files changed, 318 insertions(+) create mode 100644 src/parsers/fsharp.rl create mode 100644 test/detect_files/fs1.fs create mode 100644 test/expected_dir/fs1.fs create mode 100644 test/src_dir/fs1.fs create mode 100644 test/unit/parsers/test_fsharp.h diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index 18802cd..eba9a8f 100644 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -59,6 +59,7 @@ factor, LANG_FACTOR frag, LANG_GLSL frm, LANG_VISUALBASIC frx, LANG_VISUALBASIC +fs, LANG_FSHARP ftn, DISAMBIGUATE("fortran") gif, BINARY glsl, LANG_GLSL diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index 0533950..037b2bc 100644 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -32,6 +32,7 @@ exheres, LANG_EXHERES, "Exheres", 0 factor, LANG_FACTOR, "Factor", 0 fortranfixed, LANG_FORTRANFIXED, "Fortan (Fixed-format)", 0 fortranfree, LANG_FORTRANFREE, "Fortan (Free-format)", 0 +fsharp, LANG_FSHARP, "F#", 0 glsl, LANG_GLSL, "OpenGL Shading Language", 0 groovy, LANG_GROOVY, "Groovy", 0 haml, LANG_HAML, "Haml", 1 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index 003b06c..ae37503 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -25,6 +25,7 @@ #include "../parsers/factor.h" #include "../parsers/fortranfixed.h" #include "../parsers/fortranfree.h" +#include "../parsers/fsharp.h" #include "../parsers/glsl.h" #include "../parsers/groovy.h" #include "../parsers/haml.h" @@ -107,6 +108,7 @@ emacslisp, parse_emacslisp factor, parse_factor fortranfixed, parse_fortranfixed fortranfree, parse_fortranfree +fsharp, parse_fsharp glsl, parse_glsl groovy, parse_groovy haskell, parse_haskell diff --git a/src/languages.h b/src/languages.h index c74c27a..b19a649 100644 --- a/src/languages.h +++ b/src/languages.h @@ -35,6 +35,7 @@ #define LANG_FACTOR "factor" #define LANG_FORTRANFIXED "fortranfixed" #define LANG_FORTRANFREE "fortranfree" +#define LANG_FSHARP "fsharp" #define LANG_GLSL "glsl" #define LANG_GROOVY "groovy" #define LANG_HASKELL "haskell" diff --git a/src/parsers/fsharp.rl b/src/parsers/fsharp.rl new file mode 100644 index 0000000..7d2ee3c --- /dev/null +++ b/src/parsers/fsharp.rl @@ -0,0 +1,182 @@ +// fsharp.rl written by Pavel Shiryaev. + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_FSHARP_PARSER_H +#define OHCOUNT_FSHARP_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *FSHARP_LANG = LANG_FSHARP; + +// the languages entities +const char *fsharp_entities[] = { + "space", "comment", "string", "number", "preproc", + "keyword", "identifier", "operator", "any" +}; + +// constants associated with the entities +enum { + FSHARP_SPACE = 0, FSHARP_COMMENT, FSHARP_STRING, FSHARP_NUMBER, FSHARP_PREPROC, + FSHARP_KEYWORD, FSHARP_IDENTIFIER, FSHARP_OPERATOR, FSHARP_ANY +}; + +/*****************************************************************************/ + +%%{ + machine fsharp; + write data; + include common "common.rl"; + + # Line counting machine + + action fsharp_ccallback { + switch(entity) { + case FSHARP_SPACE: + ls + break; + case FSHARP_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(FSHARP_LANG) + break; + case NEWLINE: + std_newline(FSHARP_LANG) + } + } + + fsharp_line_comment = + '//' @comment ( + escaped_newline %{ entity = INTERNAL_NL; } %fsharp_ccallback + | + ws + | + (nonnewline - ws) @comment + )*; + fsharp_block_comment = + '(*' @comment ( + newline %{ entity = INTERNAL_NL; } %fsharp_ccallback + | + ws + | + (nonnewline - ws) @comment + )* :>> '*)'; + fsharp_comment = fsharp_line_comment | fsharp_block_comment; + + fsharp_sq_str = + '\'' @code ( + escaped_newline %{ entity = INTERNAL_NL; } %fsharp_ccallback + | + ws + | + [^\t '\\] @code + | + '\\' nonnewline @code + )* '\''; + fsharp_dq_str = + '"' @code ( + escaped_newline %{ entity = INTERNAL_NL; } %fsharp_ccallback + | + ws + | + [^\t "\\] @code + | + '\\' nonnewline @code + )* '"'; + fsharp_string = fsharp_sq_str | fsharp_dq_str; + + fsharp_line := |* + spaces ${ entity = FSHARP_SPACE; } => fsharp_ccallback; + fsharp_comment; + fsharp_string; + newline ${ entity = NEWLINE; } => fsharp_ccallback; + ^space ${ entity = FSHARP_ANY; } => fsharp_ccallback; + *|; + + # Entity machine + + action fsharp_ecallback { + callback(FSHARP_LANG, fsharp_entities[entity], cint(ts), cint(te), userdata); + } + + fsharp_line_comment_entity = '//' (escaped_newline | nonnewline)*; + fsharp_block_comment_entity = '(*' any* :>> '*)'; + fsharp_comment_entity = fsharp_line_comment_entity | fsharp_block_comment_entity; + + fsharp_string_entity = sq_str_with_escapes | dq_str_with_escapes; + + fsharp_number_entity = float | integer; + + fsharp_preproc_word = + 'define' | 'elif' | 'else' | 'endif' | 'error' | 'if' | 'ifdef' | + 'ifndef' | 'import' | 'include' | 'line' | 'pragma' | 'undef' | + 'using' | 'warning'; + # TODO: find some way of making preproc match the beginning of a line. + # Putting a 'when starts_line' conditional throws an assertion error. + fsharp_preproc_entity = + '#' space* (fsharp_block_comment_entity space*)? + fsharp_preproc_word (escaped_newline | nonnewline)*; + + fsharp_identifier_entity = (alpha | '_') (alnum | '_')*; + + fsharp_keyword_entity = + 'and' | 'and_eq' | 'asm' | 'auto' | 'bitand' | 'bitor' | 'bool' | + 'break' | 'case' | 'catch' | 'char' | 'class' | 'compl' | 'const' | + 'const_cast' | 'continue' | 'default' | 'delete' | 'do' | 'double' | + 'dynamic_cast' | 'else' | 'enum' | 'explicit' | 'export' | 'extern' | + 'false' | 'float' | 'for' | 'friend' | 'goto' | 'if' | 'inline' | 'int' | + 'long' | 'mutable' | 'namespace' | 'new' | 'not' | 'not_eq' | + 'operator' | 'or' | 'or_eq' | 'private' | 'protected' | 'public' | + 'register' | 'reinterpret_cast' | 'return' | 'short' | 'signed' | + 'sizeof' | 'static' | 'static_cast' | 'struct' | 'switch' | + 'template' | 'this' | 'throw' | 'true' | 'try' | 'typedef' | 'typeid' | + 'typename' | 'union' | 'unsigned' | 'using' | 'virtual' | 'void' | + 'volatile' | 'wchar_t' | 'while' | 'xor' | 'xor_eq'; + + fsharp_operator_entity = [+\-/*%<>!=^&|?~:;.,()\[\]{}]; + + fsharp_entity := |* + space+ ${ entity = FSHARP_SPACE; } => fsharp_ecallback; + fsharp_comment_entity ${ entity = FSHARP_COMMENT; } => fsharp_ecallback; + fsharp_string_entity ${ entity = FSHARP_STRING; } => fsharp_ecallback; + fsharp_number_entity ${ entity = FSHARP_NUMBER; } => fsharp_ecallback; + fsharp_preproc_entity ${ entity = FSHARP_PREPROC; } => fsharp_ecallback; + fsharp_identifier_entity ${ entity = FSHARP_IDENTIFIER; } => fsharp_ecallback; + fsharp_keyword_entity ${ entity = FSHARP_KEYWORD; } => fsharp_ecallback; + fsharp_operator_entity ${ entity = FSHARP_OPERATOR; } => fsharp_ecallback; + ^(space | digit) ${ entity = FSHARP_ANY; } => fsharp_ecallback; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with C/C++ code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_fsharp(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + %% write init; + cs = (count) ? fsharp_en_fsharp_line : fsharp_en_fsharp_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(FSHARP_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/test/detect_files/fs1.fs b/test/detect_files/fs1.fs new file mode 100644 index 0000000..acdf18d --- /dev/null +++ b/test/detect_files/fs1.fs @@ -0,0 +1,3 @@ +// a F# file + type FilterNode(provider, token, filter: FilterExpression, node_list) = + inherit TagNode(provider, token) diff --git a/test/expected_dir/fs1.fs b/test/expected_dir/fs1.fs new file mode 100644 index 0000000..2f632bb --- /dev/null +++ b/test/expected_dir/fs1.fs @@ -0,0 +1,51 @@ +fsharp comment (*************************************************************************** +fsharp comment * +fsharp comment * The Parser is free software: you can redistribute it and/or modify +fsharp comment * it under the terms of the GNU Lesser General Public License as published by +fsharp comment * the Free Software Foundation, either version 3 of the License, or +fsharp comment * (at your option) any later version. +fsharp comment * +fsharp comment ***************************************************************************) +fsharp blank +fsharp code namespace Tags +fsharp blank +fsharp code open System +fsharp code open System.Reflection; +fsharp code open System.Runtime.CompilerServices; +fsharp code open System.Runtime.InteropServices; +fsharp blank +fsharp code module internal Filter = +fsharp blank +fsharp code let FILTER_VARIABLE_NAME = "$filter" +fsharp blank +fsharp code type FilterNode(provider, token, filter: FilterExpression, node_list) = +fsharp code inherit TagNode(provider, token) +fsharp blank +fsharp code override this.walk manager walker = +fsharp code let reader = +fsharp code new NDjango.ASTWalker.Reader (manager, {walker with parent=None; nodes=node_list; context=walker.context}) +fsharp code match filter.ResolveForOutput manager +fsharp code {walker with context=walker.context.add(FILTER_VARIABLE_NAME, (reader.ReadToEnd():>obj))} +fsharp code with +fsharp code | Some w -> w +fsharp code | None -> walker +fsharp blank +fsharp comment /// Filters the contents of the block through variable filters. +fsharp comment /// +fsharp comment /// Filters can also be piped through each other, and they can have +fsharp comment /// arguments -- just like in variable syntax. +fsharp comment /// +fsharp comment /// Sample usage:: +fsharp comment /// +fsharp comment /// {% filter force_escape|lower %} +fsharp comment /// This text will be HTML-escaped, and will appear in lowercase. +fsharp comment /// {% endfilter %} +fsharp code type FilterTag() = +fsharp code interface ITag with +fsharp code member this.Perform token provider tokens = +fsharp code match token.Args with +fsharp code | filter::[] -> +fsharp code let filter_expr = new FilterExpression(provider, Block token, FILTER_VARIABLE_NAME + "|" + filter) +fsharp code let node_list, remaining = (provider :?> IParser).Parse (Some token) tokens ["endfilter"] +fsharp code (new FilterNode(provider, token, filter_expr, node_list) :> INodeImpl), remaining +fsharp code | _ -> raise (SyntaxError ("'filter' tag requires one argument")) diff --git a/test/src_dir/fs1.fs b/test/src_dir/fs1.fs new file mode 100644 index 0000000..433670d --- /dev/null +++ b/test/src_dir/fs1.fs @@ -0,0 +1,51 @@ +(*************************************************************************** + * + * The Parser is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + ***************************************************************************) + +namespace Tags + +open System +open System.Reflection; +open System.Runtime.CompilerServices; +open System.Runtime.InteropServices; + +module internal Filter = + + let FILTER_VARIABLE_NAME = "$filter" + + type FilterNode(provider, token, filter: FilterExpression, node_list) = + inherit TagNode(provider, token) + + override this.walk manager walker = + let reader = + new NDjango.ASTWalker.Reader (manager, {walker with parent=None; nodes=node_list; context=walker.context}) + match filter.ResolveForOutput manager + {walker with context=walker.context.add(FILTER_VARIABLE_NAME, (reader.ReadToEnd():>obj))} + with + | Some w -> w + | None -> walker + + /// Filters the contents of the block through variable filters. + /// + /// Filters can also be piped through each other, and they can have + /// arguments -- just like in variable syntax. + /// + /// Sample usage:: + /// + /// {% filter force_escape|lower %} + /// This text will be HTML-escaped, and will appear in lowercase. + /// {% endfilter %} + type FilterTag() = + interface ITag with + member this.Perform token provider tokens = + match token.Args with + | filter::[] -> + let filter_expr = new FilterExpression(provider, Block token, FILTER_VARIABLE_NAME + "|" + filter) + let node_list, remaining = (provider :?> IParser).Parse (Some token) tokens ["endfilter"] + (new FilterNode(provider, token, filter_expr, node_list) :> INodeImpl), remaining + | _ -> raise (SyntaxError ("'filter' tag requires one argument")) diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index 3aaf4d7..cd36b6d 100644 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -77,6 +77,7 @@ void test_detector_detect_polyglot() { ASSERT_DETECT(LANG_IDL_PVWAVE, "foo.pro"); ASSERT_DETECT(LANG_ASSEMBLER, "foo.z80"); ASSERT_DETECT(LANG_PHP, "php.inc"); + ASSERT_DETECT(LANG_FSHARP, "fs1.fs"); } void test_detector_upper_case_extensions() { diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index 66f174b..23291de 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -99,6 +99,7 @@ void test_parser_verify_entity(SourceFile *sf, const char *entity, #include "parsers/test_exheres.h" #include "parsers/test_factor.h" #include "parsers/test_fortran.h" +#include "parsers/test_fsharp.h" #include "parsers/test_glsl.h" #include "parsers/test_groovy.h" #include "parsers/test_haml.h" @@ -270,6 +271,7 @@ void all_parser_tests() { all_exheres_tests(); all_factor_tests(); all_fortran_tests(); + all_fsharp_tests(); all_glsl_tests(); all_groovy_tests(); all_haml_tests(); diff --git a/test/unit/parsers/test_fsharp.h b/test/unit/parsers/test_fsharp.h new file mode 100644 index 0000000..3289e92 --- /dev/null +++ b/test/unit/parsers/test_fsharp.h @@ -0,0 +1,23 @@ + +void test_fsharp_comments() { + test_parser_verify_parse( + test_parser_sourcefile("fsharp", " //comment"), + "fsharp", "", "//comment", 0 + ); +} + +void test_fsharp_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("fsharp", " //comment"), + "comment", "//comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("fsharp", " (*comment*)"), + "comment", "(*comment*)" + ); +} + +void all_fsharp_tests() { + test_fsharp_comments(); + test_fsharp_comment_entities(); +} From ca466eae2e711a8c2fa962fd09979328a8e0a032 Mon Sep 17 00:00:00 2001 From: pshiryaev Date: Mon, 7 Sep 2009 18:46:46 +0400 Subject: [PATCH 232/387] written by --- src/parsers/fsharp.rl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/parsers/fsharp.rl b/src/parsers/fsharp.rl index 7d2ee3c..64c85b1 100644 --- a/src/parsers/fsharp.rl +++ b/src/parsers/fsharp.rl @@ -1,4 +1,5 @@ -// fsharp.rl written by Pavel Shiryaev. +// fsharp.rl written by Pavel Shiryaev. Hill30 http://www.hill30.com +// based on c.rl /************************* Required for every parser *************************/ #ifndef OHCOUNT_FSHARP_PARSER_H From 27153b08d09679f5797352741c9d39fb84279a01 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Fri, 4 Sep 2009 15:26:01 -0700 Subject: [PATCH 233/387] [CHANGE] workaround: $self not working on centos with swig 1.3.29, use 'self'; doesn't seem to affect other platforms --- ruby/ohcount.i | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/ruby/ohcount.i b/ruby/ohcount.i index 6ab88b9..f0b4004 100644 --- a/ruby/ohcount.i +++ b/ruby/ohcount.i @@ -30,34 +30,34 @@ %extend SourceFile { void set_diskpath(const char *diskpath) { - ohcount_sourcefile_set_diskpath($self, diskpath); + ohcount_sourcefile_set_diskpath(self, diskpath); } void set_contents(const char *contents) { - ohcount_sourcefile_set_contents($self, contents); + ohcount_sourcefile_set_contents(self, contents); } char *get_contents() { - return ohcount_sourcefile_get_contents($self); + return ohcount_sourcefile_get_contents(self); } int contents_size() { - return ohcount_sourcefile_get_contents_size($self); + return ohcount_sourcefile_get_contents_size(self); } const char *get_language() { - return ohcount_sourcefile_get_language($self); + return ohcount_sourcefile_get_language(self); } void parse() { - ohcount_sourcefile_parse($self); + ohcount_sourcefile_parse(self); } ParsedLanguageList *get_parsed_language_list() { - return ohcount_sourcefile_get_parsed_language_list($self); + return ohcount_sourcefile_get_parsed_language_list(self); } LicenseList *get_license_list() { - return ohcount_sourcefile_get_license_list($self); + return ohcount_sourcefile_get_license_list(self); } LocList *get_loc_list() { - return ohcount_sourcefile_get_loc_list($self); + return ohcount_sourcefile_get_loc_list(self); } LocDeltaList *_diff(SourceFile *to) { - return ohcount_sourcefile_diff($self, to); + return ohcount_sourcefile_diff(self, to); } void set_filenames(VALUE filenames) { int i, length = RARRAY(filenames)->len; @@ -65,7 +65,7 @@ VALUE *iter = RARRAY(filenames)->ptr; for (i = 0; i < length; i++, iter++) fnames[i] = STR2CSTR(*iter); - ohcount_sourcefile_set_filenames($self, fnames); + ohcount_sourcefile_set_filenames(self, fnames); free(fnames); } SourceFile(const char *filepath, VALUE opt_hash=NULL) { @@ -85,7 +85,7 @@ return sourcefile; } ~SourceFile() { - ohcount_sourcefile_free($self); + ohcount_sourcefile_free(self); } }; @@ -106,16 +106,16 @@ return list; } ~SourceFileList() { - ohcount_sourcefile_list_free($self); + ohcount_sourcefile_list_free(self); } void add_file(const char *filepath) { - ohcount_sourcefile_list_add_file($self, filepath); + ohcount_sourcefile_list_add_file(self, filepath); } void add_directory(const char *directory) { - ohcount_sourcefile_list_add_directory($self, directory); + ohcount_sourcefile_list_add_directory(self, directory); } LocList *analyze_languages() { - return ohcount_sourcefile_list_analyze_languages($self); + return ohcount_sourcefile_list_analyze_languages(self); } } From 16768bd43f9a6a758cf466cdac9f6b57466866b7 Mon Sep 17 00:00:00 2001 From: pshiryaev Date: Mon, 7 Sep 2009 18:30:44 +0400 Subject: [PATCH 234/387] add support for F# --- src/hash/extensions.gperf | 1 + src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 2 + src/languages.h | 1 + src/parsers/fsharp.rl | 182 ++++++++++++++++++++++++++++++++++++++++ test/detect_files/fs1.fs | 3 + test/expected_dir/fs1.fs | 51 +++++++++++ test/src_dir/fs1.fs | 51 +++++++++++ test/unit/detector_test.h | 1 + test/unit/parser_test.h | 2 + test/unit/parsers/test_fsharp.h | 23 +++++ 11 files changed, 318 insertions(+) create mode 100644 src/parsers/fsharp.rl create mode 100644 test/detect_files/fs1.fs create mode 100644 test/expected_dir/fs1.fs create mode 100644 test/src_dir/fs1.fs create mode 100644 test/unit/parsers/test_fsharp.h diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index 18802cd..eba9a8f 100644 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -59,6 +59,7 @@ factor, LANG_FACTOR frag, LANG_GLSL frm, LANG_VISUALBASIC frx, LANG_VISUALBASIC +fs, LANG_FSHARP ftn, DISAMBIGUATE("fortran") gif, BINARY glsl, LANG_GLSL diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index 0533950..037b2bc 100644 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -32,6 +32,7 @@ exheres, LANG_EXHERES, "Exheres", 0 factor, LANG_FACTOR, "Factor", 0 fortranfixed, LANG_FORTRANFIXED, "Fortan (Fixed-format)", 0 fortranfree, LANG_FORTRANFREE, "Fortan (Free-format)", 0 +fsharp, LANG_FSHARP, "F#", 0 glsl, LANG_GLSL, "OpenGL Shading Language", 0 groovy, LANG_GROOVY, "Groovy", 0 haml, LANG_HAML, "Haml", 1 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index 003b06c..ae37503 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -25,6 +25,7 @@ #include "../parsers/factor.h" #include "../parsers/fortranfixed.h" #include "../parsers/fortranfree.h" +#include "../parsers/fsharp.h" #include "../parsers/glsl.h" #include "../parsers/groovy.h" #include "../parsers/haml.h" @@ -107,6 +108,7 @@ emacslisp, parse_emacslisp factor, parse_factor fortranfixed, parse_fortranfixed fortranfree, parse_fortranfree +fsharp, parse_fsharp glsl, parse_glsl groovy, parse_groovy haskell, parse_haskell diff --git a/src/languages.h b/src/languages.h index c74c27a..b19a649 100644 --- a/src/languages.h +++ b/src/languages.h @@ -35,6 +35,7 @@ #define LANG_FACTOR "factor" #define LANG_FORTRANFIXED "fortranfixed" #define LANG_FORTRANFREE "fortranfree" +#define LANG_FSHARP "fsharp" #define LANG_GLSL "glsl" #define LANG_GROOVY "groovy" #define LANG_HASKELL "haskell" diff --git a/src/parsers/fsharp.rl b/src/parsers/fsharp.rl new file mode 100644 index 0000000..7d2ee3c --- /dev/null +++ b/src/parsers/fsharp.rl @@ -0,0 +1,182 @@ +// fsharp.rl written by Pavel Shiryaev. + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_FSHARP_PARSER_H +#define OHCOUNT_FSHARP_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *FSHARP_LANG = LANG_FSHARP; + +// the languages entities +const char *fsharp_entities[] = { + "space", "comment", "string", "number", "preproc", + "keyword", "identifier", "operator", "any" +}; + +// constants associated with the entities +enum { + FSHARP_SPACE = 0, FSHARP_COMMENT, FSHARP_STRING, FSHARP_NUMBER, FSHARP_PREPROC, + FSHARP_KEYWORD, FSHARP_IDENTIFIER, FSHARP_OPERATOR, FSHARP_ANY +}; + +/*****************************************************************************/ + +%%{ + machine fsharp; + write data; + include common "common.rl"; + + # Line counting machine + + action fsharp_ccallback { + switch(entity) { + case FSHARP_SPACE: + ls + break; + case FSHARP_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(FSHARP_LANG) + break; + case NEWLINE: + std_newline(FSHARP_LANG) + } + } + + fsharp_line_comment = + '//' @comment ( + escaped_newline %{ entity = INTERNAL_NL; } %fsharp_ccallback + | + ws + | + (nonnewline - ws) @comment + )*; + fsharp_block_comment = + '(*' @comment ( + newline %{ entity = INTERNAL_NL; } %fsharp_ccallback + | + ws + | + (nonnewline - ws) @comment + )* :>> '*)'; + fsharp_comment = fsharp_line_comment | fsharp_block_comment; + + fsharp_sq_str = + '\'' @code ( + escaped_newline %{ entity = INTERNAL_NL; } %fsharp_ccallback + | + ws + | + [^\t '\\] @code + | + '\\' nonnewline @code + )* '\''; + fsharp_dq_str = + '"' @code ( + escaped_newline %{ entity = INTERNAL_NL; } %fsharp_ccallback + | + ws + | + [^\t "\\] @code + | + '\\' nonnewline @code + )* '"'; + fsharp_string = fsharp_sq_str | fsharp_dq_str; + + fsharp_line := |* + spaces ${ entity = FSHARP_SPACE; } => fsharp_ccallback; + fsharp_comment; + fsharp_string; + newline ${ entity = NEWLINE; } => fsharp_ccallback; + ^space ${ entity = FSHARP_ANY; } => fsharp_ccallback; + *|; + + # Entity machine + + action fsharp_ecallback { + callback(FSHARP_LANG, fsharp_entities[entity], cint(ts), cint(te), userdata); + } + + fsharp_line_comment_entity = '//' (escaped_newline | nonnewline)*; + fsharp_block_comment_entity = '(*' any* :>> '*)'; + fsharp_comment_entity = fsharp_line_comment_entity | fsharp_block_comment_entity; + + fsharp_string_entity = sq_str_with_escapes | dq_str_with_escapes; + + fsharp_number_entity = float | integer; + + fsharp_preproc_word = + 'define' | 'elif' | 'else' | 'endif' | 'error' | 'if' | 'ifdef' | + 'ifndef' | 'import' | 'include' | 'line' | 'pragma' | 'undef' | + 'using' | 'warning'; + # TODO: find some way of making preproc match the beginning of a line. + # Putting a 'when starts_line' conditional throws an assertion error. + fsharp_preproc_entity = + '#' space* (fsharp_block_comment_entity space*)? + fsharp_preproc_word (escaped_newline | nonnewline)*; + + fsharp_identifier_entity = (alpha | '_') (alnum | '_')*; + + fsharp_keyword_entity = + 'and' | 'and_eq' | 'asm' | 'auto' | 'bitand' | 'bitor' | 'bool' | + 'break' | 'case' | 'catch' | 'char' | 'class' | 'compl' | 'const' | + 'const_cast' | 'continue' | 'default' | 'delete' | 'do' | 'double' | + 'dynamic_cast' | 'else' | 'enum' | 'explicit' | 'export' | 'extern' | + 'false' | 'float' | 'for' | 'friend' | 'goto' | 'if' | 'inline' | 'int' | + 'long' | 'mutable' | 'namespace' | 'new' | 'not' | 'not_eq' | + 'operator' | 'or' | 'or_eq' | 'private' | 'protected' | 'public' | + 'register' | 'reinterpret_cast' | 'return' | 'short' | 'signed' | + 'sizeof' | 'static' | 'static_cast' | 'struct' | 'switch' | + 'template' | 'this' | 'throw' | 'true' | 'try' | 'typedef' | 'typeid' | + 'typename' | 'union' | 'unsigned' | 'using' | 'virtual' | 'void' | + 'volatile' | 'wchar_t' | 'while' | 'xor' | 'xor_eq'; + + fsharp_operator_entity = [+\-/*%<>!=^&|?~:;.,()\[\]{}]; + + fsharp_entity := |* + space+ ${ entity = FSHARP_SPACE; } => fsharp_ecallback; + fsharp_comment_entity ${ entity = FSHARP_COMMENT; } => fsharp_ecallback; + fsharp_string_entity ${ entity = FSHARP_STRING; } => fsharp_ecallback; + fsharp_number_entity ${ entity = FSHARP_NUMBER; } => fsharp_ecallback; + fsharp_preproc_entity ${ entity = FSHARP_PREPROC; } => fsharp_ecallback; + fsharp_identifier_entity ${ entity = FSHARP_IDENTIFIER; } => fsharp_ecallback; + fsharp_keyword_entity ${ entity = FSHARP_KEYWORD; } => fsharp_ecallback; + fsharp_operator_entity ${ entity = FSHARP_OPERATOR; } => fsharp_ecallback; + ^(space | digit) ${ entity = FSHARP_ANY; } => fsharp_ecallback; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with C/C++ code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_fsharp(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + %% write init; + cs = (count) ? fsharp_en_fsharp_line : fsharp_en_fsharp_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(FSHARP_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/test/detect_files/fs1.fs b/test/detect_files/fs1.fs new file mode 100644 index 0000000..acdf18d --- /dev/null +++ b/test/detect_files/fs1.fs @@ -0,0 +1,3 @@ +// a F# file + type FilterNode(provider, token, filter: FilterExpression, node_list) = + inherit TagNode(provider, token) diff --git a/test/expected_dir/fs1.fs b/test/expected_dir/fs1.fs new file mode 100644 index 0000000..2f632bb --- /dev/null +++ b/test/expected_dir/fs1.fs @@ -0,0 +1,51 @@ +fsharp comment (*************************************************************************** +fsharp comment * +fsharp comment * The Parser is free software: you can redistribute it and/or modify +fsharp comment * it under the terms of the GNU Lesser General Public License as published by +fsharp comment * the Free Software Foundation, either version 3 of the License, or +fsharp comment * (at your option) any later version. +fsharp comment * +fsharp comment ***************************************************************************) +fsharp blank +fsharp code namespace Tags +fsharp blank +fsharp code open System +fsharp code open System.Reflection; +fsharp code open System.Runtime.CompilerServices; +fsharp code open System.Runtime.InteropServices; +fsharp blank +fsharp code module internal Filter = +fsharp blank +fsharp code let FILTER_VARIABLE_NAME = "$filter" +fsharp blank +fsharp code type FilterNode(provider, token, filter: FilterExpression, node_list) = +fsharp code inherit TagNode(provider, token) +fsharp blank +fsharp code override this.walk manager walker = +fsharp code let reader = +fsharp code new NDjango.ASTWalker.Reader (manager, {walker with parent=None; nodes=node_list; context=walker.context}) +fsharp code match filter.ResolveForOutput manager +fsharp code {walker with context=walker.context.add(FILTER_VARIABLE_NAME, (reader.ReadToEnd():>obj))} +fsharp code with +fsharp code | Some w -> w +fsharp code | None -> walker +fsharp blank +fsharp comment /// Filters the contents of the block through variable filters. +fsharp comment /// +fsharp comment /// Filters can also be piped through each other, and they can have +fsharp comment /// arguments -- just like in variable syntax. +fsharp comment /// +fsharp comment /// Sample usage:: +fsharp comment /// +fsharp comment /// {% filter force_escape|lower %} +fsharp comment /// This text will be HTML-escaped, and will appear in lowercase. +fsharp comment /// {% endfilter %} +fsharp code type FilterTag() = +fsharp code interface ITag with +fsharp code member this.Perform token provider tokens = +fsharp code match token.Args with +fsharp code | filter::[] -> +fsharp code let filter_expr = new FilterExpression(provider, Block token, FILTER_VARIABLE_NAME + "|" + filter) +fsharp code let node_list, remaining = (provider :?> IParser).Parse (Some token) tokens ["endfilter"] +fsharp code (new FilterNode(provider, token, filter_expr, node_list) :> INodeImpl), remaining +fsharp code | _ -> raise (SyntaxError ("'filter' tag requires one argument")) diff --git a/test/src_dir/fs1.fs b/test/src_dir/fs1.fs new file mode 100644 index 0000000..433670d --- /dev/null +++ b/test/src_dir/fs1.fs @@ -0,0 +1,51 @@ +(*************************************************************************** + * + * The Parser is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + ***************************************************************************) + +namespace Tags + +open System +open System.Reflection; +open System.Runtime.CompilerServices; +open System.Runtime.InteropServices; + +module internal Filter = + + let FILTER_VARIABLE_NAME = "$filter" + + type FilterNode(provider, token, filter: FilterExpression, node_list) = + inherit TagNode(provider, token) + + override this.walk manager walker = + let reader = + new NDjango.ASTWalker.Reader (manager, {walker with parent=None; nodes=node_list; context=walker.context}) + match filter.ResolveForOutput manager + {walker with context=walker.context.add(FILTER_VARIABLE_NAME, (reader.ReadToEnd():>obj))} + with + | Some w -> w + | None -> walker + + /// Filters the contents of the block through variable filters. + /// + /// Filters can also be piped through each other, and they can have + /// arguments -- just like in variable syntax. + /// + /// Sample usage:: + /// + /// {% filter force_escape|lower %} + /// This text will be HTML-escaped, and will appear in lowercase. + /// {% endfilter %} + type FilterTag() = + interface ITag with + member this.Perform token provider tokens = + match token.Args with + | filter::[] -> + let filter_expr = new FilterExpression(provider, Block token, FILTER_VARIABLE_NAME + "|" + filter) + let node_list, remaining = (provider :?> IParser).Parse (Some token) tokens ["endfilter"] + (new FilterNode(provider, token, filter_expr, node_list) :> INodeImpl), remaining + | _ -> raise (SyntaxError ("'filter' tag requires one argument")) diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index 3aaf4d7..cd36b6d 100644 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -77,6 +77,7 @@ void test_detector_detect_polyglot() { ASSERT_DETECT(LANG_IDL_PVWAVE, "foo.pro"); ASSERT_DETECT(LANG_ASSEMBLER, "foo.z80"); ASSERT_DETECT(LANG_PHP, "php.inc"); + ASSERT_DETECT(LANG_FSHARP, "fs1.fs"); } void test_detector_upper_case_extensions() { diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index 66f174b..23291de 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -99,6 +99,7 @@ void test_parser_verify_entity(SourceFile *sf, const char *entity, #include "parsers/test_exheres.h" #include "parsers/test_factor.h" #include "parsers/test_fortran.h" +#include "parsers/test_fsharp.h" #include "parsers/test_glsl.h" #include "parsers/test_groovy.h" #include "parsers/test_haml.h" @@ -270,6 +271,7 @@ void all_parser_tests() { all_exheres_tests(); all_factor_tests(); all_fortran_tests(); + all_fsharp_tests(); all_glsl_tests(); all_groovy_tests(); all_haml_tests(); diff --git a/test/unit/parsers/test_fsharp.h b/test/unit/parsers/test_fsharp.h new file mode 100644 index 0000000..3289e92 --- /dev/null +++ b/test/unit/parsers/test_fsharp.h @@ -0,0 +1,23 @@ + +void test_fsharp_comments() { + test_parser_verify_parse( + test_parser_sourcefile("fsharp", " //comment"), + "fsharp", "", "//comment", 0 + ); +} + +void test_fsharp_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("fsharp", " //comment"), + "comment", "//comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("fsharp", " (*comment*)"), + "comment", "(*comment*)" + ); +} + +void all_fsharp_tests() { + test_fsharp_comments(); + test_fsharp_comment_entities(); +} From 07cd52d3dc7e726e17e0488f27662939d81216cd Mon Sep 17 00:00:00 2001 From: pshiryaev Date: Mon, 7 Sep 2009 18:46:46 +0400 Subject: [PATCH 235/387] written by --- src/parsers/fsharp.rl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/parsers/fsharp.rl b/src/parsers/fsharp.rl index 7d2ee3c..64c85b1 100644 --- a/src/parsers/fsharp.rl +++ b/src/parsers/fsharp.rl @@ -1,4 +1,5 @@ -// fsharp.rl written by Pavel Shiryaev. +// fsharp.rl written by Pavel Shiryaev. Hill30 http://www.hill30.com +// based on c.rl /************************* Required for every parser *************************/ #ifndef OHCOUNT_FSHARP_PARSER_H From 489e4c5311f07daac975c8e58628e735a1d9c5ba Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Wed, 9 Sep 2009 14:54:35 -0700 Subject: [PATCH 236/387] [CHANGE] remove bin/ohcount; it should be built by users with ./build --- bin/ohcount | Bin 2013308 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 bin/ohcount diff --git a/bin/ohcount b/bin/ohcount deleted file mode 100755 index 1359c797bd48cd348ed0404477b9770e5ae78308..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2013308 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

uLXZ-OZh|);hBFJCf**}$DLuMTTCCW-^nX0Fi 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%0AY!SdWgOT{k24q zztLrUl{g(pM4p2oj3u-zn1)IVo`8k*{iVF4lMgzA?`80fIz`aa_KqSJRs}&XNf7iL zWoh0wfQ18>IJQ=ubSue8x5bX9jH)v84&xiSGMEgU;l-p=k$1zqH&R`{C*frLm)BWZ zpU4mRF0+bD%X$qQJ!UE+GnAwg-VD%hu=ypdY^ah*j&S73rhT!n6c1XH5mP0Os)8l(Q7w;M&DnR=+%fn zGxv>=Q>F)GW*~(5SN-M7S~hv{^fNQUeTXG3+Ly;kT#n;lzWpvGWfk=UM~!KneGHFf z*$FF8-h9S+7hH7db^bGnjzOXE3&5KKJedlRq-$8`YTcMW)i! zRNc34vwzkh2-JsQ#VOL(ke(uSH2s5vz~0Trgsl#JE;?W4m)Y_&@&ybqCod~2H%sF; z6=#;@=O-2A7vUl<;LY%*0iRk_NFG{wl$_#uQ9!Hgxs7U{B(b-JauIH$ja*U zszL7T;mLDDp@I@jiXgg-bEYSV^apXJW_*u~^77^T4kMP0jZKXfLiV98Lq~=W<#~H@ zvCJ@jmuFp8a5W?NU3~Y-E>J)lIBBAc6G9(Hn@~y3QE7Q9qgZ7-DjQ?a8I00h(9kJx zr~;*g{tjDq5a7LlT@b*|EY@Xh)Og5pm?5FI3q3`cEMeR~k{64jp*k{{%{b9vROnPm`5LSvAu&p?7d2MPLeB=;MT+;65gIvtBW zGQ)O-Ms9!Ddc=ATZT*8-KKUK^`;6m&=;Oo1ErtIWpuXO{M3%Rft*dF~zmk7?Ds2c4Cg_aeU392whg^c5#+xnp^3+p*=5 zH(12`-h4TVSbA}|jEYvesKYr)B2`7Pje^J_F%i?bFi0|IAVjl#mlnq(Yk>BJq0zGk z%m~LE6_apz7TL^eRWMi9$Lg!+zNawjHG?%3$1#t!N^9uI{F-3ooXbjr>zNt3n;E!A zSby;%+BrXDzU|MPH5<&XUSKWy%?qQ4G5c;}$KtKz7+XXc}>4cMmC{N|4 zfC8P96YN%4h@xIeVb`t{KQes8U`T#MA+UaYNsJOpCH4 zx1n#}0Rsp2v+Y66efkI{{c!BsjT+5_bwhLW82>89jvF`LKk?YHrDbEI&H~k4KXKCJ z#)rn4CFz^5pgW z;$-yxJ7Ku`1e|?zl|#mbndyw7i9gUAsALUOXWr8am(fWk0LC)6J)TYcL@)y;#(1&U z9dW$QzW$`l{$)iWlxpN~8yZJc9F3AOL<_>h6o{H`Dlw>rk@lE?Y--ZrV|bo_v(lDwv%2^SX9;6w_nR7 z%s$Rrc>I#J>$aYG;l*+Fw4Bm#4v9386Xl6TcIiLkxrfg3q`o(<#PU6d%k{LLJhT`y zYDUj4$~i^WDtV?)_r}P0o<~YM`!^l`i{XU0SGEcw*^^Be9+7US6ct3_R34V$bfoLn ztd3@MG@ApTlTlDuT-Cd&-|z_-&6vAj(UMcvow5D=j+P9yd_#!Wbo8u)ymJibI(R^3bNt(3_?uiurU!K(K!Ty9TzW8lr4nE` zP?#G8A$p#$Tc(IM3xGD%t|~RPxyZIgTh`P*^ZWFX+cvpjc7vDzajfxmb>r)@`&lK) zsUv{N9O%xdo-r&G5@VlEhu-H9eTJ|*9?QerV3cD5yjQ&iM>lXFGmnX!{{BU_=&dfm zh5>v{aTu3a5JKu$+uUIH(K@OF?137ASn%P-+T*~goQS^kWT;wCXWD2?&x+ER7Jb&^ z>_ztR_G0ivmPJr24QAyj_Sz`aO2L-f8rFK<0p`d~`#ezQF2H8d#h{N|0shF9=)m3# z_QLDBo${W#0`FiH|||Fm?hB{@i2sxhkbirA}ArN2|;Xm6ZXzrgG-1+yyFsiRxOQx)rFx0#$sHDmht| zo~p{~RC$@Ia8!>nRi#vQ87OwDu1qzYu6m!Ln$A&u&s761RRb?mEjOwWH>r_#sL^}W zn0wW@`_%Y{)Wol<$xo=(RMncUT60xvzG^K|t);59w`%RHS_i7u5vp~xY8|IqC#u%T z^t3D4E^*ZLBOGc74ySC)y-sCqH*y{4gWB z?hG{IjJ`YHD@?J>Y@v66gJy~#N(;S#yb$W5C;f*=M>Ha5A5_#(F%-Foaf47KYzFrP zhok@pQ5JS1MvfdcYV?>f7!86Tn=tWnxJi>IPw|{stTJvIhO4xLQuACp>WUuj?yRG+ zZH#ea+}yC6H*fy@1-OMB+~>c&abvX}v2`GPwlo_znwzBX;Ka;MVzE*0DASNMAvJVs z`bzZ?;h4|{`gq-j&irhFY26&-$4#r`hOa@&*ZqXAtyCAssMU!(dI-4!lNNW^i!C2_@ ziQoiG!3N-Tco;$Vnh)2yNaMS1W^MIWG&-+FFZ6n(N?);_L{}7GYV@|h!AgEvS@N#+ zJ?p2|FF;HXtAL;IhNgn)YUTxtLHO!}MZo^p44A0L=-G_I-ne@zbAHe+%fKWccMGRJ;t5uE_F|E*ShQ6_3mc( z40pSGmiCvrm%2B)_qzAHkGU_n-*8`aUvl4e-*vy|zUThf{h9l|`*Zgb_s^(o27(#E ztYCJqORzLp9;^!X3|0s0gN?yH!KUEAU~_P2uq8MmI4(FbI3?H`(YTEN0veE+7~g{R z$u-C}XCjAOhwNl6Z{-TBjl7u}$+ks@OLe#o%~MG?5}KS7b-q|xko*mVCN3+ZT6Bvo zv?%cvIyC6Gl5RlWuUj&O)a%7cn#&wmcbY_8VhjvJ5_n|ti($;iDa;|qw*Z{QvC zOGZSFF*49?QDt6hUWx2u+mm)g-`8(1{usZ+!-q8};IT)oImA_*aEP)*$9eaon*ZHV zZ`jNOAF5=;=Q=9(O!BV}cYg2My)VMtDRY$fpA(hE9w$ddOJOQH{nv*s>Fi%0`lyco z`f&AQuikrB=BUK~+LXl}*YRJ+UWwmsY<~Q4@p3NjxcL0|6|a_WIBNgnm{2?-<6(_;EM(U&f|7{%3gxiKKjq^8TH2%m#Yg|5R!tB`h;O z(l^wMOkc!vH!a0ue~*BhI2G#6duRT)5Wv0BO-3&>CmTzWkX zh#6N**D~Fp7b)opVF}2N&g_7E&U67w6C{YNb&8qI2rvCcD^J9PXhx&0971`9)!u&8 zo7p`mZ(5g_qS#Y#^`Gj}^qr|Wqb znUWEM!O0OkbzK8(R9!4b=y@CFZsaz~vGF|Mr%rP%;YlA(iPND3w5m)ZwuWSSk4vVB zjFU#9qOoo2h7&a%E(l+MZo|tuqPJ#TTVtCeKzBIG|y z1Ir`wpN)ad$bQb$a-WNl`do#?=O$!5djj_a9tb=X_!_dF#{y3v?b#oA9$C-Jfo}!g z47`J^=ZDC8eirz7;Df-g0v{pm`D5Tufxia+&P-*Ro8jgo^(oRapB`>Ct4tb@`V2?n zGr^tY9_6;V?d}}+Sa+Gb0*TKy_e^((yVJeEy~w@Ry}`ZJ-Q(Wv-se8xKIDGQebn8D z%;#nIp!*IopPwM}`K9}7_qXmJ+&{V>yFg$D(}RUUztJN2Ofnqb(Y)CyOpDY$2F*xA49&ye|sxi^Kbp@V>h~s?;je ztJ%wGp#pC){#O!O*i&G&g${d$_hRc?a%%`>y|sV(?S zm(q7$Le4Jyl^~*C&Hf6!sVyt$cUafbyIx0lJ-EWxfu4R1c{gES<7U04{#N!k;-l-` z7FF{)N_KOtd+4F}fRcU(+Gc{Tez$cmT4(nYy9?hAE`y*F??tZv5Gdylg2?g!xev2_ zjqOqVBj8ov2aePu#J^7X^_cwV+$Xd)+f%gk1hWMD^yankwAOWtZ$Wau)=A6HbdvvU zC;9th^6%j)pVyev&ofW)B3iKDB=sD=9pvj*@GpbI@fsu6>%+x1+=w+RnY|1Iln zoffR)*ple{cNy=#!~Dm0Y3aY%e@9~&w=*a5ZRSM251x(8k0fg2hn<$Z*J;U*qDllO zSVr7-bbEh_|B3Z8#@(MY^8OSAogb6`OEe09Mff2j@kd~O{fhaS56J%=zjxZkKRPY>XQw6qiYk$R`D6Z3 zJEV>n1`3X{XUvKx;Hn%OxB(EtZudm&14G3G}?vH+`vBoX<>-|7( zHx^unk}IhZk@P5g6xuSQ!F3xGw(UBSct3PzjMmI}awRo6lJ2LqX!=2!^}|om2!w5f z)4?HZ19@pGxijrqc(Kwmn|(XJUsSz0Q8n8rIR@Vk+`?lC=i>W;E;o;GKE59oeirC( zAsRYj?Pn3QgZ-cfm*72Joqm)_-U%^zE4U*kfl+5H&z=Nc-AXJ(o`PSitQ{O2Vt~7vQgE zyGDoChWBFcNOG?yyn(%!e`C1(rbxY;b-i1{>0875+rsv7xY zL_KCdfqxY0{z<~8@Q*_0KTY@yUczVb&)EB!6@H%d3-&kgFW4{IFWKKD{jAPA5R><+ z{R(!VUL*V#{$*@`zE1cC{$=}3{L9#f`ZnP~yo7Jz55ifzW4}xKJN9?+Vms=4SdV&{ zGRgZvOx};|_uxZ*O!!m#XKX)V`>FlD{R{g8`fIQj?Xw13Ti z|A>-5+KH&PkL^TM*~j(->tovb#QwAW7q&mK{TX{!v#kHdis@FUk-yvju>WcQ3ue?- ze`D6Xot(eJ3;WcSPc@xt1=JeLRW3{Lw^|{LqNRvoG`3`wsy!KgWaq=EN5ln+sVsP1uCBI>8iTn3spRY(^Xw#6=8F0w^barx7r=ftvkM4Rp3k2 z9abr`{L;_MNa>Bf(PM1q<5HFC3np9@3U$8i)*e{*YPYJ;g{wza&~eOYP_ni%eoSak zUF`;}f;G^h*nM3Awp^_B*FI<>v|CM-4OV_X?Dwxz?ICK4Jrw(}!_Zi0riB(YQk_p9 zFj9?zPxURuj=*|syET&1i7LMTnxrPOXzYLeP&ABC;5R<`qPu{8S#-%^{Ju4brq zESJqv)9~$98zo}J>=?M>W7TYw4ChjFK2~XuQ;P@}uq{-_tH zAmM-{o@q;JJo^b+dwr7TeMFPp#N<87w}l7FhfWY4sL-CyckjpAnL!eMNA`t$wZi!b zV(T&RK7Oo_qs#4i@H^%90?i2>2M2T_G2x0#e34aUFNP~x0>`tQy@@T;e9&SzpOx@D zJ?)b<=MtM*1!uI{slc%WwcYj8V$On9Bg!kkbuHkTfU$HC^9)`;?B%^W?-e%6w{;W@$=;0!zt1dC#D z8y??baCr}EUgI6jJ$#q?hHv;GNSHr@_7&>hqwJ-{@wU+Q<84FJ|5nq=-Sks_1ZD=>?DP?hyf~a;`GtPI%7bmDL zqLza#9Y zt&!Y)@j?@uCo!74HVQiT18ba)J!6fvpXWaBXB!`(d&k=!a(_gJd@9uNWYD)K+kfKz zv}ww>oqJ?FqM11N5xs@++i1h$nSD0*-XW_0fL?;G3pY)NuWAnF4IP?%$$pk+lmcZW zp`+_b_$1FS1Z@?fhsvVzLMo4v@YuurqZT2Kw&z8rnOZsPAeoyAI?lh@*3c&f8iZ$iJFk9pp`Yza46 z{dv-20cc3LT+U@#NlLgC<1N;&nq%cEyb_5!)|l{lO3h(bni|iO&C=ocNSR!VU-DbS z@DWZ5*C-DkovXywQCA%v6)BUW{gOXKj-F;;r~kQyR7ae7LT@E}Lf`E430H9@6S z&!}3-*f`u?tt6ZQmvxsu%T1Ab^3;Bp@TvVQ{M7zJUH@+TPwj?C8xpC6rt!|UK76*h z_QU#YU(t_Gp5}@UPjh~!PxBsYk^KxU2kfT^r_=gpaZ?Uaf1FxwzoaoL*XS!V?Sf!R z%G@uO1L*tpCeqE})`qBBQsdM}y+F9$_w+b_y8Tne`Fm`cwHT)nOW&vI9NUFzEmmhi z(}eVlNIT5x$gX}zOsQMe* zCAQek+QRsF2CX}cwdX(w6|1a9%grLJvL4XoV#> z?(x^zKaLLXAnR6p3X-yKkUju?bUUe6kckaPqGcfo6N|rha^K!&eEP1nDdvt+;Xm9> zh+MxPGg&76>2f2D{C^wq?vuBd8TJlndN_#DN`;K+}R=$jV zc?Y~ZFex1I_L4O5=o~N4--fi-()ikkN_#DN`;K+JHlz0t@nJ6`l@~wqz04*i z@)kU;=m#9yTkw+G^{kl8jKzBkzU+?ZKXC+cnG5)I&VthX?B23Oww%agNtE>~m*8dp z#dwSHI+1?`sb(Vo9@Lh|4M(C=C$##0Qb|2?d;v9FG}oEw2-) zT?wfQWNV1Fm&snnoKO%nAhClwuluoK-Z z?E>0)xnUAsQ?!y7zv3%g&$4VMDK#sndo62~hqj1SvDxz$Eb{TYMcYp#TAr4%=+F6S z(LoTc^&`_c{xtfCiM0{^tMjfaTFa6D$lZa-7acOq=WDcWeQV^)K^KY|^cYHqR99|F zdY8P?T4OP6-1M2pu!25vtD+-F4Gqdb&M>$vu-&s(aSd)aKPi zpD{KrAn;jE7R&YdbF7V*AS=t#z+ahZvdlI&H9spW4dZQ;Bs8$JGP%6L89uyU7&$v;LA)rNBmm%uUL)@>gvU}~ad!&~BGt9MI$Q+zKcwX> z2K!zlD_#8e9&Qfw3pl+pW#uS4P1)dkDM8r;1~3>>NyzSVHNIC-7~D%f3jxA+6@RFM z<7w&7gWIKX(gdeVoY>+@6Wy6ZJ9%5AhTezcI^F4E@!#9w(j6O;OP0$`=JNz_f56C5 z<0nm?b==Agr=4~2b=Tj3VUc_8y?@`6Pd&T;`Hlx8SvFpHD)B~FIUaYnLTeGp7hGW( z{o&YE9iKl}usXbN()1l-6Ug)y)d|n_`Ez|u*(2|VD&UxDK7a^yeK_H!7+C z4^K(U$m)_;SW;RGV92DY)7$4SKV{1qJ1@WS=3DQ&_x=YT`r7^%UOe#1x1x^nqMS=h zPf?6>LvFxLPNEA;NlQ-wMI=>#nZo^FN*H)JH#bG{x=Ej?V}&}FosyDPoKlpMQq;Yq zw5+VOyrQgo_mm!0RX~YURaT}*UX9L^SfP%UrPTH6Raf88tF|_!5&XoazL>Q!dHr-| zuay1+v}Kz?0|yNnhE(sVswbLi}H^x4^ zKgS*q&P__s%FgRrR8!a3cTl8O;z)c?8Q+@;%~BcFOPD^+>)}i< zVtUl*)e}CwVrVG8hvX`RQsG~tIWDotSR)@cFM%aj-zC3WaZRs2{lJ=1JaTz8lq)v? zN(9w;AU7D%QZj;oqX`L+o*v4`$jws@IzJ$zDK{?=?23Ug&Jakpc)No^!RJVKGXUyH zOD@oNs>15#hKfq6?3z*xR7F`3O%`=`-$4e1DFM0b(Aen~kRJKoYe=4Xa$;{$Xj{=g z65S)SLcZv8;N!<58wnd@5b+O{s$;Es9qY#pmVR$|Pg%3t`I{nd zj`yCK6*>klU*5A=y!_8o>W`&|K3d-GI;Rn&{zgzRy>ok4AHTlHyWYfWp`!n-_eIok z4{&fc0r?tuKkej{@Ylg-B2R`L`fd($Apu?l#yb6(fS}){u(YDOZqV52?Z>S?Wj*N2 z=U=kxs>qWu5xxL9M&suj_q0qHQCt8!wNG{dCB3D zlI~KHt&^oW*`}hD5iiXv6FaZT<>3GJsO-_Br(IoJUT!dMYHBKKYa9Edru9kblbX>d zJ+n`FQ{*ba{}%jwm6hY>$S|b8Q$ADqTry^TLPXJwgr5=EgExzY;^*fD@NbV(}P>DHQqL9O}8`9 zViSEf!Lh2rq$KVFkH*33&FIyBaCTvFPdF@(enC={ZJgH)e|136&(&5 zAj&>j*_UZ(D>QEwDl|saPNgna4g>@?p_`R+V-&_!yGos@(vOM4xH?YdE>ii+eT=Ij zV6F;ONr5U|t;*J@iVdo=LG`FqRgS8z)G$|-s+Up?fP`#QP1{xf^VERz)!-{s^DZ^& z7B%`-HD-?*cc&VEpPG2Tn)FpQ+FDUJUBz~}qi!1QsGCPSKG@X^C**DogI&#FzcmW%Y9U}(JHudC3)%0C z0lVT)Is7Y!zvWbp+2d4>zt8DW={Wo&wpyo-eO+a}0|ppdE?X1Z09I7>KAoWNIRpbQ z4YXOROoC=t4XGS@ovVgb4!_=2EtMl~(2!TFba=T2zFMWj%iSX2uU6^sa<^E=CA{1% z(QyeccPr&Q681eue>|Tt5J7^lm%@vSlT~er(XRym3QNxb)fuNTuz>InI}N>AUapDA zo?$GkdO^d&s8(MP!uxA1EJ$19fWaCzY#6p00SMO)h|;hdJ!Z^UDBba4EG)pSCS!Ip z>@dCws@074&+fpzI@)uBdnNAJxd2`Xv6|pXgu)wS>l?f8~Jw)fN4M6001|N|D*fI#0omZ`LciME6lv zdyQwNb`mSMrfD4qL6kRIhbOTT${@;Li6+9e=o;*eXuCaw#(-!Eyn$Z8chPu~l_wvf zf%ZpjwOM!@k=hs9J<;6~yw0&&hvjH(xA{c$??vbSJZKJ~H*SjHXqwfYFQTFSL*_I- zMAKPjFnkT?AafVFto^K3{ZxNee~v-hbv|0E8`UOtuG*z;Q+w4D>P2-xy{uP%{z3gq zr8xyop;P2kJN=x2&LCEPPIG2B?al($e6DvkI2)bK&gr0mZ3hkP67ayTcCK-5VCCms z&fU%fto?l4dCGYjT(ECCuQ=~GKXyKHe&hU(m7gCwe{%l9`cE5icXA*rkR2!q)CTH7 z1se(m*inI2)_=CM_ERvwP6g@fLJ+<#jY0UjleL~t1r7w>W^LzB0>1&f>kq8x{5bFl zYdZfH_($MhOp1Vbj7%wo^_^L64l6vnxy2aHsBo*?8n+iKJbP<&uYRob9Ow?#2wx-J zv8?!S?+9&_ch;L;;wX0a!+Li=mvKqs9&eMTQ%<2`R--z<*Wp~ z&b^-1pf|d^-Fw`xunzPI_i6Vz_jUJ8_Xn&2{gwM+conD>1eF&vnrXpI5WsSS1;K8? z;$Q>3n_zy856%eA4$cWK2`&wu5?seh(2d%k6Fet)g7f~+g`wj^OGC>-hx)=qXV~}_w0yqA7V|hz;V*@E-Tp5l={9m3pX)tR39`r+L`p0Y z^~88#CSR_{)cL=IE#}=Lxx(ms)LDM~y{qN8`RI8iIyO<6cYF=K?-ummCG^gfsQ#hK zytceL@z1%leDAmvo?7(Grs$imKug>^j?p#htvOuo(oSlx>Lh8`otk)G3oG&rU)(z(Sl|M-rhuYawbkCOj4vE+m*`F!`kGB@!XoiKVz;l31Z)F4Rs0 zW+yd5x`x2n$xRV764Wwu{RB_t^JMV^nM;#R&*h8KlGa>86d2C(YRH7VsjH>bastsGU&VUl+qK1nC$N|BEGvKCVok50*}ShUC49`v z+`n;^L3Bd8pb=8YjBo{W!2_B79i#E_CbRDEIA(U2f@rdhS=+ObnO+1E$emzw+{gO= z{TdBJurA&}X8IN=7C!=e;uCIDDw5K!=ydmFnzRligx;VR^i_jECKv;Pz)YrR7qR+( zwc4!C!Jfj6SX8)IJ%UAr*VXsb`|1PrEA=NP@-nsDvKj)Asp zZ9kz~pg2&94TUP?r2|0B8xa_V%yc&P66RqkVS~1hur077a2d#Ww+42DizkS9PX(R} zd?WA@GSgQAuLa%>{1}@De-4O@G!ttFB}hig-AZJmf_>M=?H87b8k+}GkcPG+2c7FK zbQinJk%O+*whuPAn~;JE9^TpRd7$B4>RyQ)^hWnqWT1DrcWP9;y%AKr=Rn1K)qM+G zyzjc-*VuUPyB{DG{iFLg_a82^p26f`D(HA!f?YAQ*aL*TURXmIh82X#!CA;ej{zI+ zxZv@iyqzHAT^zg&$>{AM<2?i}-V4D4NJifYekb_j;Ln1;2>vqo ztKf&hKL`I341}^nxuMcfU8p|PJJcsMJTx*iE;KpR8frrxIy1B+v^=ynv_7;obbjcP z&}E?;LN|r(3EdxhDD-gXvCtEtr$Wz!UI@JudO7r3==IQdL*Ea*7y9ub<)`L*qc4%K zPj7<17i6W0Y^>77>mHL(bX`3pKJ=i7r|U2yyiaGXq~xNWtu?N_{4U}0oJhS~T`w=3 z&JXWJFH4T^8s2vc?+e5GB3&xD67v0ar)DYMvdZw{%GoM(SQ*||FgGH(RfM9K=;c?3 z%WJ~>+VEa*DeAzZ5X~sj@ewSSMlD~i*BE>Q2nT8ez5&d&^rQC>-$0#uOYkR#683?1 z7*4DiU#~IvM(TBzqoLgekFP}^Q%~toVuHpemJ|hpVm$LTW62W?zA1!9fxRbae3N48 zO^vEKo)W>MXxHd_GYLK1iK8P3d`D|kJ`ZhTKKZkl16mZG2bvE*u^7yXCAzO$3I^YD zV#iZwg~s3$)V-xTby6ffi~evmc_*_;C@6eu3B?x2T5u=UkSiE`rx9)hLqgE_)|2Pg z+Z3ao%?|g9ic9JXpOzLb0aZm7R zF5#%l^m-)0;ky{Wowc@C;&*8zzN-kYAtiWx=ID#5x1AX<@!K^j-*xP7&}b7k(9%u1 zHNoS%9>1M_|2F)sAn4rAwwrZMx3OyX7D~ilPrdCR@(KRlog67>6n8OB>>*c>`R*qa zG>Qj_-HSIz?V*mu1f_2~coh==3K$jJ!Oz>yYToUj-)-0E6ps@MD#hch_I;E*vDWi6 z;WLauPlHwQWK6yNQ8fk8!W{iv!rbShav!G^LA7|1@Fo7mH;KJ~-yVmqXR!6me|Uj9 z+nF_N1MBAvjf;1X{abo_o4v%|A@t(!M#aAq75^`=^}YwHhT!Y{kl1(eZI+;A{Fu-n zX8f43_C0dnXZtzZFYzCMobe&Yd_epcgujU7$LD^eN9f-&Rts|8ul44&@w(sIyAS#ka|U=n9L*sozE$?fjl=XtO*FBu|UjAmg=x}#!)>^h*rq`qtfsYqm5}Pl`9+l8DJ(vfs(t2*?b~*K>9aR6oxRW+b z8**KOyw_$40!TfG5C#RLUSojNfyrG!37aKyg?k*46^WG zD5!zt3MR;K!WQuGMiLu}H%ASmPOUu}Dr*d(*pM6p%{7WVLB*R$DE1^Lf*~j-W_U+^??MOSbu;WmwacRDln^P=jV$sE2{a}y-a}WeHCw7dw_bov<=XGgx7$0_auncvc7Ydwg~zR;jc((on7GLwON9b_dc7fQI+kd zV9k6$D0q24g=6^@;fHuZ()%^rM>_mXc>j_8Tb=$L;qNK+^8XMn|6`=y$GYAp;q;%v z`#*>Ge+lpZ8s7hRc>gzjlxUg!9VESfa)y85f2tW#xguNr6z*F>mfh*StiF@9OBjsG z4~5HWWVXU9Ssa4qh}{atZVB66WLcK-!aay6GV6 z72yj(BN6nxbjl>JG$yY?38r2pp`eI}HP|Y`p7=5}W~vDVMWhVe^jaO(!5P+~KwA&$ zT^Sr=BVPDK!M!V^O!E50pQf zoak8mC^cS9gF+pzCV+=GNv|s&r%=KrXS_N}C8D%jRU%5dRgJY;X-m-Yrn60BYXct- z)M@bXwm?D70vk_ODhoQ^One(Tvp~r6DPo_}U1QBxCtC|NV%`?(ICVVy^6_xZ$K#i% zGc3W(TaFjhyw{;=R-lKp65PC#HB#Ohjhc4?*m`Z0tN=GJ5ydJiqt|28@LKCMy=^4i z2)is67Vz-55Zi)pvrZ?rO>M`Yq0UlglG8ao z(fNpewweoi>)A*Q&PB2NJaxXh0BejpXzgq)8DFRpjolZiL}T+sYLtDEx>#LAiQNMUE*Yc2hm~TFf@M~Bkctkyl&C0Lh+pLGldmK%*C)HE< zebjkcJ&VnP=Lnx+dlpGdhI&DLgY6~tP4wAbLaXg1{L6gZuc}wDZtxoWZxMR~E12I# zZgY_B4Yt>5{|#bqskiZOq6hbm`VJecZ6~h5HoAkZ)nJFek1hC((Q)COJ<320gwnGt=rwrZfkNHEJvZA! zHUHc~+)ItnT=XdP8OIPCL7kD-C^+S2+i=gqJ5SPlw228a+(?j)j6Vx6vwf)AUe*)i{8(IaBQqC@r4|B9Q?9DY!t+L;h+t6 zy@?5y{aD+eHX0mzL32Eryj5&dZQ+WAb6&4`=BZ#W3eUV5y!tbV`SC5*4EqetBcH*_ zDH9V!$FnrQ+-{$(Ipo;XIhun$$C_#HBqrRn#AZ@=Cw#PU(zEP~G-iElO8DkWtfRqg zGd#4!FJ-%k^lV#r=Uwa#j-wyH8l-#CCB2Tl#Ab)_90k!)P#lGSHnG{Z;5pu=dFVT+ zw+CKXupCWH_6xvqyc=ryo-m@lpArmv;hzQ5Ug8UENqv?5!*I)j=_p8!er$m)NR9@_ zQ7qdou%87P%a2LUGW&USUSF`5+0yey$6wOe@`CJWV#{n3e+>jJgD?L^IJV3djoCLf z(ygFAn%FYiAV4m&-?6>}Cu_J{g97;@&FKoC`y)8r_c*)oxE_aVV$1BGk-x_Ng|!B3 z$bV@bHyRyMcu%usXX3gR{%^M1zXkz*B z1l^EbZ}f2r;PWa-8)Qc>Rsknr_&(vlVO~$@Z9jE0#yCxDq7t z_pQ~uE8%dxE{dG>6W)=(vV9WOqGkOO`NBtRzvRe2 zQrBWhE;?XFgqrIzyi=U5SL?JRQmx2cKiW?S-zn2( zxf1z-@yud{%i1`rSAtMTSM|^>t5iFP`?Wf358t_?Z7KCjKH?bh;>vYsSq(~%_?vWi zO!&BRYaW&SlHcj0t_mM{u|Co~`5z~I@^5$gSXq;@{uOwW^_jJ2H z%XN`@@;3Y<;oI>0@Z0cL>Lz*{1SipVmDc3Q*}fV++X?mq;s5lMzA5G{IV<5?a!IFe z$(;$`k`3XvwaJ@G*WhK;=@#ov16e&b2#Tg)XWne@fM(fAY$@oO!{IJ(L*gSS zFPB1p2qx=FyVe>7mw5;BAE7~SfTnPuG{oIvodRuojB=6x9HZ{iq0pv#kig$XxgcAK zyT>{W3iTUEY3{X!N_`NyyC7Uy&=-$Fu|8l=LT)a|n$JL|eudP2q~b%N5(HCoIQPr4 z9%d|f4L6jOr6Pxne zGDpX@;nnr_iEBq6`DOgeJMcew2PWvoO=!;3F~>)cjjrciRmZ&8oY<7#mUq1Dy*lxG zza+YLqPU^;zSvOosS|k%Imirns6%^8OCMxb{z$#0xn$v#J)h_f94@a;&m?}D5N<`! zw|%zIvSd!`NWH~O$rtIdfQcNjqc2B_n8*w57VRx4r_oS3tyozVFZ7UDo3X5Uth*I2 zdSsR*)?-d!FY@dSTBa>>?e)l>Eo(dS=Cj!QP9(p^UrPS9>N@RjAiSBh$YPPiM*LUF z+lQ?58TKL({RaD2wCwX$Vs9had>8Mxo*;&dL*yG@;){xQ*5S3?zr+{)f9$;rfK^lf z|G&;=1 z7=%1Rk87^y|N89xS#$QB&fxj-{r;ct_t!b|+3U5}{;bbgv(G+zuf6tO?_GTx`oEwr zTD^~NKMgrwJs$WHPeo4p2YE$Th@xmCxGzf7Z0 z<1hZ`7HLbmdRcU9(zoe|$Uz((-3d3>fX;ci>c};0)T&L#ZasQe)i?(H0rBQ~aE!iO zt#o7%YbPd(!fZVhW|L~yZjj>-@VrQWLQXK06Am{_%r&XLR3vdyRb$RonafDXN=?n= z?dr}JnY@&=#)Zua(uxCZ+a^_4o0S!9SGH3z(JOQ{3#pX+Pw35Mnw(H5)G#lm=I$&$ zHSPbT9~Y$tkG68Q6;=))oq)Jb^>c_Bg;l#kWOvSPeC8PV-R%A_~Q$;~Th z+N?vTKK6 zV@Z8c9_5NY;}`r%+-okkn9Ek<+*;0Je|r6#+(u2BwdmO8;6ptBh~Jlxn3#ZqU@#a+ zO-n=hGc6@0kcePl0P#;GGV9c>%kL{ED=P&UmhIc~gsnpE z?@DFGr!xM5NdoF(h@d4UiTqh&2AX39DXl})Hq&%0EbLlnYBx6xliHzU8tBuLEvZ30 z4HOkAbTZha+^xzdYQV;U&s1QNLXnBdO}WSHb&1`9l&9D}m8 z^P6_{i>2B@Zn<_|3`2?WjWg>;CPLLRcQ?Q{FFCQ>v3I_zL|ovDL8c=)Jv%4VsBwOA zSCLj7I%4GEW5!OHgzVm|v(LYL(RFc4N~Vl1ZNU{%cLbk|jh5~Dk0~ZdIlE>5xsk(e z+rS;4=lxAd-Nrde4ymN_yR+lm(otDFU-N7oY8v0?{zo>Fc<0BIv{9p~%U%!5&YnGX zP0Ie9pDmjMtvng2#4Haplf4!Cp8RZrNi2#jwg0@^ili8eoQ*{G2I40Bg#F#4IRViR zu9cbHFuzGrtJYmhh7Lb$)KSNbFP(hCsWaxBKkw4Z7u{HXN7Oxrs3jkRb`Qe`5D!jA z)i5m+(NcCLbvdxq$xN+VU(yDtIjQKQg>&;7hC+@UaDgKN?Bo?XnGI7#Em$-aTNbr! z*@nn%+aXBYwta{8DIGd?Lg*am(!4ne_uYH+?A*CUmoB}W&+C0qPN+}s5>(R;?o-mN zSxMi1hxF-l@WB292O*u-Os35T$5gv&wjQmAKtf_Y#FLYg^F)@>N%CsRKT*e-hCm}9$iIkrpP#`Lxpri>gpyjjayErzG1^+`Bk$dII@26-kBk`wHsMt3~9 zVO5R)0N4YpP5(fVYA&^P&ZgBC#>}v}@=Eat12;3KZM$~uI&|n@MAWXNWWa#v6G381 z%eKk}`Wp(tqBYCU!)@RBQ-c1K#6UHzV2R+}!rhHMdMx)RaZsyUKh%&mUZ*axpFf=b z``9*~o0reNLq;M;_b2YC*a7tWd-oXP;~tfx$LrXLQpWl9vr+TU@GsM>g4~~~RNraV zQ8}LCkdcKtaO2kPI(O^oEcXW!Nlay=tVf#}9wWRr$!jZ=3h>j*?a@egEOf5_aaoF`0alq}6*SH|1IMBIS z+k}ML4NxG}!>;ItdbLA6tvQZ>Y{9iMr0o_C)wK0fo`0_T)p=2XcAvc{*W~5+D_7vr z5l+%0FAvE`%JQew_opZM(^H(ItsH5C{#t=_lN3nzMUR#;Dw4yfzTBf}V%1_KKqsNV(P&(uES?8QzcHtH3=pOgZ+ix3+)tRsPvrAa?7YlIXcC7)_1z7uMOs?-v^*{?vUcRJZ|l~5Ti2G=G@xC( zL)&#UjoJ0~=~GbHtV>{c%i&4AMkOTFYuF%;jJ(@mcBgLaYE$=E5j|q?UFh#g5@S%o zZ`I0h?Cr{n9g}@I?Q8jkyH8t{r-0aT8SXtd&M(~a>(1~eW%{LC!u@Fn{I&UM8~gJ{ z3Epi)%XZiY42q@7u~-w~sFTzAfmWPe@%MjO+Y5R`E={M7hy zBs0X+Z9+2dY(&lier#^T(4UgkAe7&vX;E>zF5M3qIDGW@$tPB=9{hRwQUcv8v`pm- zOY?K)=1)!XrzJTckBF%2le0vQK^&?ZY#cwZq}Y!F*!m2MP-cn<9#v znd$tIJxG)0FgXH8T2u9Op-} z-!H}aZB+e0uK z)VX(1?i-Y+L$`PC36y&QWo(z+`*%pSyZ(l8Kh+4vVvW+VS2FU--rG0c8Cxay^NC`5 z?A?3Qxijx{?$A5SH_N#fPjpIU{L=-DZn}sOP4ji^(n3ZfxoYV$3Q0yF$!Me7xX0x7 zD&6$E88>u~qnm!e?*YHb_nSh$InvMF_~u@}uYuo}=l8W2$@E~rpAhgT2K>oG{3%2I zX(Ro$()}6f{>*fL?W6p4#`?4W=C6O8zrpeTa8rLn27&nejTro4`~_iu6XS0h_P3bn zFFMm-e4fAcTz|Vu{OvFGcfZEpV~M}#4gTIY`VYFre{i|K{~G_G6#t+!|DZblLD~L6 z4g7;b{y|0lL9P9R+WQCf@DJ+kA9S#PP(S~m{{DM7vuZOhU`p-?n8iH;=IS2K!v_+$ z(=8!zD0T)NTn0N7J0nml-51D6H`tNboIoa=31`CLo;L)-2i+2A81@Akg$PZH9L(-%X65tna8B$js(*o-0_M8(<$8fO71cWcfBehEN(Jw zd5%om%#&%!9Z8N)7j{X1@k<(6aulT@;=J}3H+LSPRf|2U^UM+1pVK0da|t=&rFX5M zfPHtN?7H0-Eu@w$rB%?1=lIBrHj=)0oDZje`s&z86wm+4R~MRI_JxRgPxpn0x@xE& zT;ja?Mqm9ruS4kI8ZdAWufh5{R9~p8$GrZsFF{(it~resw zEU8;cTqRp-=;l-{(M4K!*Y7X;N95z2Pj(|l*^*S{e-k;;mvEVK@>sTHWUcyzu?1Cs(%0>=lYqFZwsdf#WGTysI-lE7t-e$7>Z z#VFWZi+;^*DA?SM=J&mUHG#E(b&itFqk#>m*;JrsvpKLeur077@Oofppb|x!-GM!5 z+I)is_|JTCw5~ZrNDbCP3A}Ewey~9>2Zft_6mFUZTLfF73*J81DcCjGBiI|Qn|{Fo z!NI|yXoQbICH(N_^}!p0H=&MmOK?SSRd7vkZSdjXBaTMSlfkEgPX}KJz7l*j_-63!;CrZx ze~hyDw{(y5d@HnaL`l3sLeqriDCM+ulyW*d>fr|^l%N_u620)T3CEz6GZDS;6B15z z-e;j0ei0hs*CgDMaCgG$gnJV1P1xY5gFlOCT^5o0X z+00AY&Xa$VmYb-lESGZL`9A!PV&k8v{xdw~B)V(j-NzZ7CG)l(Hb<0PV&lpG;Qk*j zNnLGCCFdk(=|pF0Ybg2de?8gBKi!$0=uBs*XCL+jXEUDd6!s3s;s4v8;>K}fy3;5&-Le}>UFb!=c<`ifplt8t*1hItmVp^+k4=0 zbv11JU;Q<;j_u`k`^{x)KgX*jE!W#>%0Hk#U45&S?{et&Dp0sU!N zkMgW*_sMwCCkXsm72ALB>i7TuzvI6`Z&$7|$o2lJzEej-^bn3ke@4aE-IK_%^|w@! z-F<)TF-mgnvCJNO4jfbeE5}rObo#Tu3-=n?U$M3Q6)|Mn`oF02>|U+@y=!;wmFPcm zZF~RY&mTFu{3j|fyHADq?d$Y?*pJCRtew*WjkXKro}k|QU9AyqRoNEh>Q6hCNAD4k zqe{Fy8$F+r60!Q71=T;j+WEWm{>W`Wez^oLuRuc8RPG9p7k3QF{dEC4W9^GeKa{X} z)m4oppxkccOx%mJWXb&q{=ZNbnRw2N>%QEONEK!7PyG*6vMQpYBaa--B)fN8 z$bA>_)REhbRE4l4fu1$-ut>jhvD*nt2HRBSum>biX%EbAnB(l>bCQF^KP#k$V z1vIT5Kr6F<99`hXvorrwDgT7Mln?N7d;8qGTUepwILn>2pbq5V>hvU?jmk)w5#!ofW+*y%r9M$u5Y>cfC?bdk!i6ZsU5SF&wTuBSrw{2Kl+`w(i1sY{XIs!Y z+m7Dx8z_-|j4IgIq9K5eP6HIMM8m2#T2e>&C;CtI&qCvP4r)b9PzAaN)t#qN(%Fn! z&b$8i{U6ek^n?FrdXka@b?8589B2|~7AOjE7dDE=eF7zc!GR&D9v>MvmY$@^^dLXLKJuMh^#`3_OSO@hgGtfj0tg2j1m*ak~Papnm*$ z;M>42fd~&)P7S69Gw3C%M-NfMV549`u#g_2*1-<+4)qF_1p5bv1P`M}=;+|zf|G(% z=?6MJI4gK=aBlE|;Kjkqf>#6=YwyqU;BCP>f`3OF`M%&f`hFg#-{%>$kzb_e=O6U^ zyc4XX=jWr~?%-#^&x3n;vfMtND`&W{oy_y(xCK3-PC_>QK%$(Sk8W~v`hw&sawQ4< z5(Xp;P8dpG(5QqlXeLi^dVx;ksd2M-X54u^G47&-1@r`6n{YEa$tx4?q(5jq&x(7N z=frJK_=ls7{4P(6`#j;Rgzpo6L>W1fz`a-W0i`?7i7RmWep>RhxQ>Zk61yk%NbJco z;|3*;MjLrD+Q?_4jC@|=`H2e?uS#5!cthf{#9ITr(c}GQB7{I zuEqVXu6D5{NozZKqF?MTm9(ytSIdZovD^n1T`D@puAe9wM@!^5B}C2G%?oSV(DS*u zRZH`#s8JQwLWxOgSHQ8eiB1bOZCaJv%vsu8=UZr6gvxmlW$Dw<&n>Q^HtZqVauy*| z(K&YK+B<0nrX4-`opgEUD!(p{Uss*)rfGLgduZBI(_WhPc1jg7a{eG{CGBqGXbzB= z60EN??Wbv9&Tu5RKT{c7Z1V@|@runI*GmQ)M|dGqKaTWk7J3bDT{ux^m?AgxtVAu&qfdGY~JT^ zZ`zr>XF6jp=h8#qU>}(M;}pl zn$Go$=^TfqJ9@_tIU2}!I|@&t^Yma<{v%xN5Zx!6`xtYNp^JQM5q~wUcMyCwWgt4Qey*=TLxnfoG*|g`ed;-MoYf#LG-Y z3F>K7kY!$!qM}P;^F*X5V@Cyf7kW}3;4j+9pD`8fsP|AjmU&T4_AaTOzt>SS-iyBR#~kBj z?n~a&oj9)IR5XUvOWFm~W3-Q5<>T*Z9Y~8MLYs>gF7zv^$lp8feW)XUZ{+^CMDED? ziK|gOtAjg$gTC(>TqR0Fsm_>`3@C-STPldp_eSm}smsY4a7*+i@ zmLG{7!#z0Oyi(T4MCX2-iL?SI@}7jY@o}W0qcxGcbWUJ8mG?y2hbJ->B}kc`%=;wO zJf4Wou_$XzcQlUAVEM_|bab`6d1unPoXGt>)6Hz|@eu{%b5Pn6n?;**4pULtn#C2& zxlGUJJ&Si4CiehIdQlb4t0Gx;v9t7&YI&Dx$@!$0Q8v2t@+!XtRU}asIwh{C%DYlO z^(xQjE~;9(xQec>q6=s5V#nlcsVn(=y5~uZng{6|HcT zk=^NS-0xJ*9ZxH`<4Mxnncm^t0p;f3smoVY`TgDTyG!Tq)^xR|_h@>rrfW1^>y%oC z+VXwWN>r6+p|tz}(^;r2&q8fkrlPy-&WZN&EVPx^p|u>%e^i%0rs)PvA4hxnao>|{ z3meh)*@(ijJW*v6*QuZ3UBQ{gvrM1kUBNlWW@q|5x@MbES{C(Wxt{$J?-x;77Tx6v zmPy{L)$;zqlUe@3xylYlF?l=ZEN^h`@+R-?Tn&GV>D#=wJIcv2eTVl>=Ly)Ab^C=HGGhKCYH0YRaE*RsB<@qNeFt_Dc(;*k5j1I~vJtIkPOLOgj{k?=T%vN$%jNC3kS1 zM&6mcuH4Pgh4M8Y$!k8AcK3@meRt<>h+dq(icWGj-qVdJEFbLufumsbi2?3WvjpX; z{f~+z{!CwqzpuZ9i2eNi{iU2+_eW7Vs<3>B{}AGe`tneJ^hgvv!VK^Y_xJO;iVq{v zU@rBI@{jhP#a>g?AFPV9tD}s*GO1|5aw#;C_c+Q=@=x(U z$?t87|2PyQPCzr_ME_*o)6Eo?oP>Jvt-ez^XFnOQY5p0GhVl&V3Yo$C4F6L;(U+LX z8U1XY_dW}yiCNCs{SMUr&PCbyJkIk)^;i@q_W3S!w28}9_jn$f#TRpL$)zlr4_(Il zVm~JfyxP%6CHLMWKuO$TaMootaN98?s3m7p#pKJgU*ycGz4N3Pt8m-Rh@!34u|1eGm%g009Ktz_=+zFQ zTu0wvN3*u0PoDMSWjRxkU)N#IIm>X<(I-68Igb&w+9vh~m4 z9OVqoPrQ7(8R?TV2{}(W3$tpr?itJ|-?^N(ldvG;pPeI?*J!|-s^Mg}- zR%iAUpS1pKQks>vz0Yaa%LrYs&a6DIVg}<~GMGwRUE1j~=4A#g^adWPM=MT7xy_^< zUNzF3Hup?g-Gxr;+ob|pbZ*mj~V%}{;|@;=me3cn4x z8~re*@}9=FaU}Q3xmvT!&9P3a`C4a-k@m4@%}zp%crshiINGUVYn*S`efGyxTE8dx zo-P4>q+NEWj$@-G#e#|DFN&9Ff=Qg4@ zdoC^BxsdyA%6W;qXLP3@vQKi~$5+eu`urZhUCrT|syP3umjB0R-elk9206?r^pJBL zeAJm%1vhtbCK=$F9WrI8B`=xY!P%vuwQ79BO$yEv=oL>hnS5_ja)9Mz-EMv?A;HCYpx6SsX9wngaGYhP|5jHT7M=F~jwDKEQm; z8J&F_&T-vkqIhnX@WXLjtv3w-0P>zk@#2o#zIRiD;JKW#9o-=g7J{Z(jkt33OwXTXeLFKT!q z(|`5VnwZho$f~)HRTN$NN2s}f47%g;oVfAshTs$`G{-RKuG4pY?mB(Z=`Ee?@e+^H zD!&iZPjp(NFM5cp*1`~73w<3u*F`>gR;Bc(rlaaAZT}N#9VO9MdIW8Zqq$yticju6 zZse|Im*|`+{$_FJYN?STjhRdc|FWAvzxgTooeYb zGmdKO<;*=tkKIA^+!>CK2QwXNuJFCW(eXy#cINtG|F66TRsEx}RP%gQkpu9j*MPg0 zqwCtLLV9y-UNn`Dt?sdZPVDlU=54-B<3;|{|K@=J2i8E`HQ?%=xKr0*{~W{hJnypo zIbMz}qeZJ?#Linkn?^s)db;hc|CFip55#*L&dTLz{M&ECwYg@(^uJ=o=Iam(;L~9H2RW$LHB(K`NRCfo%dl(4`<$0 zb)DcSyG~|ao@X|lRQlb{Bt6&ZVPpKVxtRX6`Pe1!{^$1b^d$pneuOE!vO{zU@UnHY zAY=2~7vpSGYh~1Kl;5}nqzn`GVFqaxgm!`mNd%Kp z91)ZBKnD3K%(yQ8T7XzGK9aE1n1;1ciEP-+q@<joP&eiU5O{ygGL_qDW%8_v+QFx7=+J z=f%J3_TEU}O)^(mMFEf}$od1^?w1-!qVLrEVpYjjQT1|XlbN=RY!DCcj!a_nVd) z$cr)TR3}C5UUWa%{aVSCdB5noWoFf@pA%}{vTcVrb#tJDfN=-*Kd%X!-W$5{j~JNbR(%BID#cwSQxCeC9)&3tLS*E5$QE$EKli(H6&&T;vwdxj{--bGXQvWCDbMd$ z?WlUyw4-dO-$~_L)t95zBU^Baynd&gE|za37Hvk&5oF8yy?4!}Wr+!h`C zpn)g)jU$ge{`50u&OUd}WecvlX31}rmoXOZTkb)2_eIft$+0Z6TWA~I_e3=gWfaZ7 zm)oaWj8x~EL0|4v>dPHT_H)Kp^ZBpj_TkLl-A`JbRJl*vdzW@W)u+Y3zdLqK6tHe; zc*)l;I}M~8lSI2wUM{lFb@#kAl=NiFmgCv;xJah6tM>TCL;0PjW!9~q)1-CRzK0AL zbSMIjM^8R=_BnIPF1mQ}lBLU*$17#?nE&b4`-5uBmC<>4*+Qt;{TT0*Ofb z)XA<_w{~qOufCHfOY1jqFe5RC+akk>s0AnHB_b5jD8Ha_US48h)24;Znm29I#K~*n z*Cg}+qQ4lv1QASojS88@6e%D$Bx~5B=<nzBr4HF9OOWJgj@COM578FVZfHuRx!TF@k1*r-u*BZ*lk!iAk1 za#z07Ll-ay6%`#+6mXRf`Br?UZ*g(oVqe|1$Q<`N<%vl4(wllW97=C1N&DyLelPw5A0tL z>|YP;U;pFwukNnuf4Bwvdu>-){@X8S|C*LT118k8UC)7o1|K?P=&<2qCr>-)Tv{;m z7GJaU=HF<+*w(A7AP_yTvggG1j7#R*(8~OOw>@jugy=%Z+R!$wv>!NwlreAdTd*>` z@VCD~HauSc)fTMNe$A?z)38x~tImC-^*URUCG|>9>y_HOS8)y96M52p&C5^B=Uh6iwwz6KD$OJ_-+3-a10>iQI+JjIzCnjA zFV9E&wXkV!v;6$j{Oax3|CKFR*>q&fi}Nz3Lq~(ETkk$KfB!VlDgQsxKX73GO8wiWM!Jpl~#_oEvs%JzP^c0a}82aWZk<>_sw3Hx|)VHZK7$hrtLNDs_8+R4$*XsrV}(hUejrso~`M{nqIBxGEHyQ zbe*P;YxCvG%eJ$m8KmvEzxv{rXw{StLX$yPtf!< zP0!PGfu@T!U8-rhrmHnwr|DywKCS7?n!c`SrKTTi`njgxY8ufrZL$0R)zvhtX%kIb zYT7~5-kNT%aLbkG{6I}dXuAKF?dIJ3UwWB8TFTs;JtaGoI^mdsnKFL8Ter-jP=e`L zG@(()KN{k{*N?-8d-RAzIDYVoxzKVH>+hTq#vD!BZ#-A|NiX^v#|zTA!+3ft>BLc7 z?I&$L!I)D?kK-{9Ge|Eyfvf+d#~x+OS)>h*;CMp1X-xFn_+xv~KjB3uz8nlv<)FYZ z!TtLa@&4kX9KVgb_w`QYtlG{8lw^!iVpXoYG>Q3S&6D0?$xU;57i?)am2pT}>L;U- zB)2ZpY^1G>dk$%eKb$TJ=vu){z+KIKuJ1) zsf>h*Lr#X?x@!ZQCiA=>#tjaq{Nt7GhlA^loQY13Hie^-itJ@HX$e1VB zPxKpvW;^-~w(Pl#aS|5Q2Ae0NqFk2oP8T^W3J#KYi8J=eT`J?4T#|83E?uE%ByuHs z4Q`%{XmUwLHMz8;%I{iq93=00vlN{lcWHEbqvqVi9b(bkNaW^fbCJmMn0c>nByvlf zrR8z*R>aARM!NMkmqz_ux()A@|5l0E2!HMT?SH5)GD>X!&t2uo`@4tt_xzvBxhr}& z*pDvYcySRnAG;h|f?bcvab!7mtJ+FU?<5tIE$C3ro5Cum`b+u`-rDLb?H~ zz&2r9uqEWbNV*Ms2a|H|Yx)uCr`Xq+l=~Kwct2<=$H55Zznb$TtQIEAYm?T)a zbDZO36Sz6n66=65VOyYl} z>8GThVc%m?&yCbY>?im-%Ku6#{{Cy+xCx~5Se`&3imZ+%E5PCrsvUyJY&8>IO|No9Q=Mk?!f zwB{eB={Qo^9tKiItdx227hkbS%-16gvP|rF=H>f3kyO^_sicxGF~m+|Ug~ousm#yT z`8lK#w~SQQ%RJI->f1_fKJ&}rD@hk)*I`-s-AF2*b2F)IS1U**{z}q*EMH}fdHKB6 zq!Q;L(nqjoF!@}GCDu{xdGf{oMN)}#4rRn%WqvO6uaSzqjfvlTr1H5RYPy?LOzI}K zNAvfRN<8^a#lF>ii7EC2^J2eX@_qT2xci($QYkl%SZQz;CZCtBX^2!lCs*h5HEl*J z^=nDm8tbI_-AKg_(s_w3)>r2TXnLro!%4-)==@ksrJX(wmiBik>2Yc&lFIfnja1gJ zeO=^?bpNZTQy3TN#*}+#E~29-n-(D_KC}U+p=A~Od2On48dXuOPfhb}_=HsAhZrZ; zh8Et5j4{iE3K@a+KA$COpVFf>gfU+uS@H-iIrDFSN=={szdzp|=d~Y^zA3wHNP0Tk ziyUXpCH1rYU##_gEw$2!$xB9;+#c(8MYpKz6PI4^7mn_Z_F{nu()x^pM$N$Dr@kGkRQB> z{UbIQix=l|@|R#QVei!7vzz>Hu=dN?uVV4yj39q3wgkJq2A})M--ZQm&N1DwcyVTv zzYN=o?W@73{qh`Bf=$EbWAWnLLH;^yH$izD`xIuJ!0|x_fh1J#TH;oYw&rF{B4-I zn{y>BUYxVYFT>ViPu1Y_2Kjri{M9+8KNc^}Wb$WYtFdi0_K&%{<>8*1>WB!4fKzlQ${ix=l)^5eG?@ zk=Pt;Weq;BkiQGde1PK<7B9{S^2cEdv9&e$yhHwOEVM4i6l3w?976u#*feZm4L*;P zzXJud1YPX2Bz=OK;>SiCsX$e)9)#&*`=)9_)|3pNg$gT;%p zjQnzJ3-)>qKA)2R4c2Tu^}*uBnMD3nYzcO24L%Q(zXAIM`>6(>29K~$!Ny{zVDUcd zQu5bw&H5VBRWVn`d^>mzy6evi$QKBw3`>067uJngkzdkGaZoQ?XOAGcfU&zPETU8(+SYc$mD9eMGVT(oZFM^GUtmzw{Tx`byth zY@W2)V)LYrEH-a>96#yPiuJob&icPMj-T|Gc+1xG{YpQE*H6~bM#{#1KhKf(GWHI( zTNpp-D~&BH{i(5e(nl4W_gmk?zBqBEe<}9mjT!Iz|E~B;0+w3x_kMz&ldAskE zzQWi%>Hm$*lRn7UyqW|sBq9lkkw}ugclk|-?>u8((7EQ4bZ|ZA`o+;Z>NwYeuK0T$r?39aFB6@<{cC>7G;%C{VT|9o zrZo4225z7H;X!BrwIMg%=~JI^djqE*zx<6_&b6fv#$-Fk>(|fsJAI2&7N(nXiE~+c z!0BuM?BfjQ8r#?c_u5M0Ka8_4te=a;~9G`LKa=EhRD`%ekgBb$l)7y4v6w^_;%-n+Dc#`t+ZhRmbV$-!Piz zg|OXi{4CALZ|R4+^_*)?7uHI2uA|JLzOt|F@Nl|wt+8@8dTAVYYESYx*D~@?O*L{{ z^-oVS@|*SFm+f3*x;>oawEdcL;Z&}t9JV~wxmNLOod#w#^P{)cbFOu~dr$+Xtzk|} zajq?N?UU$S%Newyo^x$s?sr+vHM57eaCZow^Ugw_bL}kSnM5P|_EYQDa;|xtbW4(R zO>gq_MCY2!OQX`AYhSb8&vx31gSz>g_ECqo{m$_?FD==~@$-k_sm`^t>vyLcX*1k- zXp(acY|~pjLxts?5`E4!jO;h7bvaktP+$1(ex(+nnLF^r!bZJ&CotT%kZT3KPwbY8 zH1B`+C;y@N|1a!+WFI8gx#eZA-}ipnJ%5w^k(iuo$;)03E@8R6}2NU{88HPVl$YRb3AF6iJhnZa?Ei|{q6P2`8sc} zr(dD|a-Je~jm}H^OY9crCBEzj#q4r>{c)xG%dtvq74uR*Io}g|K$lCKQS5P@m$tvy z(>iaj2fm>5_Il_`Ixpu~V%v3I_NQX6>AbYX#NO62tiw1>rN>%8oj#ccVu#1hM8xx|;_yjXMV4@=vwhtA8r z0AjZMG+3-emrHw1tiR4nTTSdxotJY_v5`72`**Q1IxqWqv7>cf&fUaL(s_IRe45V7 z{$K12otN``v2%1@jt63w>b$+qy+G&X_#n1O=jAvdcDv5o`x4gZy!07}J*4w;{1CJ2 zL)u|ZTTGYB@kGonx7X31)aBC76MKPqS^xGr_RG3l+InLD(0O}Z`vaYqHoMrzI&bgS z`AX;IJXI|4jJtivaY-zddHFo&9FzaQt}d7JU$J7H&%#%%qs~h^SFEefOJ9fB!OY9= zPtNnj2J3P;zZ4s-^Kx7h8>{njUL-b^d8v;a=fqCa<#IkRcB#(GaZl_r=H>J3b^NP! zIa$?Sf9N3bXPo}SkAEhs@~UKv+gD9`ey&Nzf|wCI@H(&t4y=I#Yv8~dIIso|tbqe- z;J_L7*6J^8{g3qcTNeKl@foiE!q&fw$KSH}FUMz^`U_kC z_W8%d@A1CB9|x{~4cW)nC~9%LBly zzh&`n#^cGpP=Ddy^B;jvC(>9796*8fqDzh&|7#L7KR{e`Xn zXC8mc;@_w%zfbiSw*FTF!Xubi7XQ`Vj9H=n!r~+AzXu>J{+7l6qwdB$t^UH|BmSoX z!s2gP{15L*8TA(yAMxLVS%1so--o9M{i^=L*1xaE-?I3hk59w<-1RSP{m=3ETNeKx z@Ht5Rg{}X!fba+=mc{={cIZ>oUs!yk{)c+vTNeM<@wrOPpY?x-GiuKWcp8diU>tynd9j^11TASeCl&#=klKvab^sANgNS^Y~j9|D$;j zbszN?K0eN8J?trKS;}UWupMeyVf$GeMyl#&S^T@BA;bh%693;_J+T#LtzqU9UkTREX(4* z5TB0fFKqpXr?@QfEsOt~LwWYM`U{VVQ@4hm&$29Kzrp`REh}t4Yof>BviKiC(YF@saKG6Mxj- zviOUJ=qmLWw*LM=)ZeoBPaeZ>O8teczg>q?AIsuD7oTTr{XPBzJ^!y|@fVHKZR#&< zW$|w@-k79y?zSpy{q6rK z{+7jGv|6*&U)cKh1%$=lviOUpYk~R;i;sL?f5)u9W$_oS*G}p$Z2gZ+j`~{`f6;|9n7L{Dm*XN7|ni1-a%b z<+3KZX1Q`{vs|;*a`RmCxb=azDp$hqT5geRK2tVra?Ov*r5$rk`h)IgP3oL$Lds=u zk#Yqrb&GfG=!wr1mdWc-IQH1__Q}RvO1|v7ge8vrzgd8={J)lE{d{%`zen{K79a6H z%CqmXEdKq@GG?v%3tNA?jY)jV;y)grN7P@~`cLFDgvH;o_&Mv~l`+EE>i+{aY92eAI*!mCg_&fZNG5Kr{^2+eA_{aNRn&4xr*4}(Y~%Fr5dB=s5=X|JZPz%$?|RC9-$XO z2>#dEaK9(hpj3cXuzpQiNW}dPgJZ$Te?TKSq;>b9*-Wo@En5XPm58F5| zc>XWT5=X}GP1ZQV(>!I*^stSy)f30E#F6oM=V~0`OFU(-@UV@u!V|}`#F252*JvE! z+dO60c-Y37-ah($S(Z35-ttk6Bm9h~>{bukI4wFx<5-qBGT!u6jU)WFr);H%ZJbp- zqH!!s92sA^OXCPz|6@Gczh&{4@u6R;zwqz*%lOP+)L;1b{AC<$%6fM@6mA6D-+ns} z+c>p~qyLv>si%yKJy_!iAMPnT(Ze>*qn_{Gvc!?`ywf#~@Hw8c7kJplDffKumL-mi z>%3Is2;bl-d#8tOoUxwYmt~0~<9pX>9N~?gvTu6W#yNB#50}#Yo@I&iD&vbk(>TKW zyk#GWu5%lwx2HaqC60`9PQhRH8^SrBvMoGp<2-a^v_6(4j*MsRpmBtIddeQ`VH@WO z&+o#r#F25qhiDw(5uUO~c-Y2S=lQ-YOB@;Jd#uJ0p6V%knul#1yDuFjbrzL634Q{k@4C$Y8>HJp0f9Q*v5I^vprjuI5IBzF^wbqyr=AT58F6f zJaH^b92vj9Q{xDK<|+G~hix3YPnQ47vc!>b*m6=X+mCPtY=7@L9=375Z5#c)Tb4L7 zF1kSD2zT+69pGUbXKJ%(9Lo|%#)*&7IKn4*%AV!nsyLqQXR5Nqk@4R1G>-5hPuZm& zwsG$25v`A9i6i5>Z_zly_jt-a>|q-x#q+zcEOBH!d4M)=G2BizbU zwxfq_oKnwz%(C-;F}}Zt#*wl913YC%dDzDJVQ2LJvMh0Ay#82?BYcvl>}(I)I4v4S z<5-qBqFZpW#t~lZDSLy5ZJc(V|I4z(5nY3FjU#-wr|d%>wsFoF9^F4%mN=rnutDPp zZ}ybk=3yJh9{Wa+VOipcF2w5^N7(uwQ$u@0^e=X+zwqz*i@wEo>MtDF5Z$iQJ#6Ew z?;KtKmZhGe&ybD3Y*)gKJ!PAF*v7f8XEcswi6goktu>BtZ%^659=35_^z3gfOB~U+ z7_D)HCwj`B>|q<{c+d7=S>lL}#7vDNJkL{hk%w)Z*F5#HEOA8F;wFtFe7C3U!ydMA zc6j1gmN=pdvQgs*zvwBu!^1X?{f&$u!?MH?9g(**j_@a*vgYyVHelm)KR5b)S(Z4W zuab?wvp<3JJ!M;a*v7HHeW{OSi6goxoivVciKpzL9=34~_k3TLC64I0jM6y5<2+?g z@UV^Z#r@I$%d*4~{gzWTj&PZ$>{TANao+XR$Fjr`os*k2j__Jf*(W`0! z_vS^7Bm9=9?1vt;+I8+c;>?|q6Vj%A4>dNk?y%l9rE_LObv zVOyUgJ#j2c9MREfqj7|Lc*^$mu#NLi&vDJN#5s6VmKm&ZghzYI9^+vf=U`79%MwTQ zX-YMY@Ts1%b3AP0< z9juczj_@o`+4DVY<5YUKAIlO)^s_F}IKqoPWtV!`#wl+ZJ$_l1IHHTTT;mAe?e72TG8FV3(DJo^BD*?xq3#3{?^R#jh+W%*wcOVNALvchCJedbF%{+7l6MtsJp zzp(YEo3ARq@X7cz=h|aAx-91_uY_+};j@(o!}FAf!PhE}gjXq#f$viu z3s)$QgP&I}gQGnC8Vh062bTa@R+ z4=XQ(Ur}BJ?^Ip_f3Ca~-lx0_PI=a?PdS{cyb^A!yb2zuyc!;>ycV9WybhkPydJ(z zc>{cxas|9zc@w-cj;&!#61J zfge!b3%{uR4ZKTvAMD%ge(uk3p0at4{grYMK3q8&o}io#pRSw*pRb$^FHz2c?^e!* zA63qWUsi4kzpGpXf34gaPJQ03TYI>Xa%Z@+a(8%;a&LH?atS#k1!M&7A;iHwOz_XO6!dEMw0^g)O1HManCj5Z%Y`8*s4*arm z8T^*=Joq!^`S5qj3*n?KZao*lVdW)o3+1J7PvvFsAmws+obpQe4CPhu1Yf2+I+4s3Pnxfu>CZ-qN4Z-e_P?|_d`egmGYyc0f0xe~rc zc^7=E@^1KHyt-@x0H_rYH({|sln>ej(L&u>9F2)9*E zhI=Zf!^4%c;7Q8a@Ttl<@Lc6w_%h{u_(tWX@IA^!@Z-v@;g^-$!|yA1hQC$r4ySB) z>)ad8RW5?)PGWba4dGN`~^Wh7X7s6L4FM^jVFMz4uZNFN-T+Tlu7J-`-UMHxycxbtc`N*g z@;3N+uvoep0zNyiK_T{!qC;{G;+nrbq+bHjb2P*G@$0+ZGrz(E~ zpQXGHzC!tD_zq>W1^rv)AiPOA8Q!Lx4u7be1@BYNh66j@dgj2{%DHf3<$Soka#Q#a zR{uOW|Y1X@;10sc?W!k@*D7c<(=@2%9ZfF%Ddo=%Ddq=l=r}U zmG{C)m2Ta>fg36BgS#pJ3?HU!wzA(-4#IPlli?eb)8Pk{v*4GNv*C}GbKtL)bK%7I z-8$sMb(NdKMao6+!OE@S;mYmdiOQYf>B`;VOO$)Vwsa1@;G>iaw&YA@)Y<&<*D$E%BR5Vm1n@)lxM=9E6;}0KXgBL4%|Sw z3@%ch2X|7Q5BFDI2p^@q2%e<81U^G~DLhws8GMy;Iee?~O86n=Rq!_D)$lImweT;> z>)@PSZk^Y|EtEIFy_GBAp~{=!QsvF?Eak260_AP+3gsQ}gUWBfTaH5v~nqYobnWSw(?Z?3guJa<;pYQ2bE{S&nnM` zKUAIr`*%~fpfP1|NVyX3qMZLyjv1v~3ZJBWA$+lNIb5z>2|ucwzm4C%aw+_+^@rV9q|+)BCp6^?y2AD*O~|0=(Cwlc3U^U{7ap$sA$**&`3Ki8l<$YHSAG`0Px&o)i}invYZl6-@IK{oxXvE84$s5w zl;43zDE|wdqMZLa`xfQ1;H#7`hwoHg4sTH20B={`1piaH5;mW^pL^vSoC7M~3U^X| z2p*F|@aM{v@UO~k-{p7xFZ~|j z7RrO+UdpBLaOHA%qVj9-Y~>H(#mal(70Tv4o+GZ@6W*#k3f`q$2LGUZ2b}elTc5RX z3*}1qAm!ZmX;&zBf@dfXfiF`ogKt*O|A0Cum%=Y9&xb!%z6DPD+Wp*z;9TWOxRrA0 zhtxs293E+X;8NwTyEu+pe|Vnthp)ByA9Jj<`S26UmGG;|`Jd39S2nw8qbireN#D5j ztbiLSn@{=ODVM;5l*{1JHvgaOib0lvgl8*11>d0jB7C26CH$mvmvG3usyqVzNVyFDR{1VC=?AwC z55ghkO1PD>KR09!R&EH7R_+X+pj--{rEKy-X1;O>yi9pE{DAUec&qYV@J{7Q_+QGs z8-+~Tk8a(Lg_|j#1NT;50w1A#6Fg110=`7~g~lOstMaGtiAA=5;;6fRLdA1+m14$o4qfafclrXjOjxujXhtWz#)9x~5a{}%l3%K1h7@5<$^ zLMGv7w+^LU*d~?ByM|0><;rd$Gt~O@44LuDB?Cj|bn8DPWG+)ShlR{-%4MV2PHg@d zwiBCwWXOD=`~>{H@>V$g7q>od!Htynz#WzU1rJm1FN9|(-w0o#yb4~XTmj#s zoH#aQo>FcGzpmUL-m82#oc61(A2?6B3~p!nSn8vk|2Ni;az$y#oTgkdiT#ptIefEn z;HGh~`7m#<-4RW5rtWR9{v8$xEL zvf0Qsqg?V_$ShH=gl|{Q-yAXzDVM^Vl%IunSbunz^?5#IzE-Z-!akfkmE_#VY-Jy= zTmrXJu7JB)pO->rka8J(w9S8+-a%1N=P~HT0QQih0s$2;ltDOHz$V^v0623%v5`2sDGK9#kHOuPUx0@wZ-XZ&zY5P(HveEdR6ZRpSH1v#Sa}ir zl5#m*sr)wlt@1Z;deE&;t=B?qcP{6`{gjL0Ba}$p}epLBt z_+{mC_(SEr@K4IWz;zPbI;6fHGA)(!;XcZx@Da+_!qb&+g%>EVftM>+z-yF0ho4dY z1%6vO;|-1}%Gq#$apv+HtPkfXm%y!+*TMajH^Ij$?|@HNHgAT^JmrJn8hLyA6$;x%$vz1HWE0ynu?^J#Yeo}cG z{JL@_{7>bEZ-)?obL-F<&QTr?cTye)k5oPxo}yd^pQ*eCUZ7k7uTXv!UZ=bZeqQ-g z_+4eQGi1I}z7S4LaqDvpT%f!X?yg(`4^d8fhu@KMbNDRf0q`Q_BjMG`C%{iCm%*c)W5YJWILHyCHL}@=*AG<+1R~%4P5;%J;$kH21SM z!;O{SgAZ2T15Z@`0X|1L|2_UktGp84r@R`jlkR?Q1zfCrNoB|k zR=ysdqPz+&v;Oe)$|dj9?o}>>UsS#m-lM!8u2swZtmolo%9U_uW_{pmlq)}CzocC8MaVp+T=r$iY*Q}TOWWJ}{EPjha{0F*lbqq!t^7OM zFqXgP7^hsiFJul=&i{cnr}g=fHjK^xi8hS&hi|q%@LJ`K@H5Jl@LS6HKeLZgF8hUc zLZ*H%aGtXHm35_D0uQwL5%y8arSR#>74SmqW5Q;YatZvHavA)Ba=tHY-c>GzzfvxT z0|?T{KGW|HoBGQ6a7*QKxR-KiLfDM5`S9_|mGHUNCoyamC|4wf&2r_ElEQ8$}k95z{X^m}X_HU-N0ZNsLMaydLixe}geecFZ1 znaU@@3zW;?70MOxL&_x`!scb`1Ak(D;E1y67&dk4YJK1$<@`=zQ=(i3A8UQ!*~+Ff z>qNN(zDfByc#ZOX@YBj$;T_5!z@I4ZhJRGf?-DlY*=~JuyM|2@+6h8^1xzrD2m) z->uI^xIlRe+)H@}e7N#k@X5+M;d#ntBI`%FC%j(y5O}-tF!&4QQaGuB`?=+C6Xi{C ziSmnZsq$;^Eagi066JzP{O`)$;d_-w!cQtsf?riW0sct24E|nu;N-BWmE+cDJlsTi zCfrTA93G^cKP7CAQ7(n2D=&aARlXHoq5KGZzj7s9pqoh4YS?_NTyY}5cV%;O z*d&MCx|PCV<;qjTrr7dq)|+zvIbk!#`kxy%Q?1W=tV3mUdDvX0Tz+NP+^k%3P1vkc zuDCXAUbOj3!{!~Ee`DC}QBJ!lY)sg#TRxnv+!b!7JO=KrJPsbJTn3M~KFh-94CNEy z`O0(Qo0ZGqdzABUW*sV*!v9dd3jSPqC7jgIt=l7Tj&dbjq+GTrJ`hv9RfBeKv&62<4K;!{#{a1JAYjPlU~t%K1<7yHFkmKcajr{EG5P z@W;wC;9rzahqD{Gbt{KkDc7k8oBqlL@Ob6+@L9?w@a4+q!Yh=Qz>g~51HY!c0scmL z3!Ku}{oG18tlaXcuxYP65FV&J1wLB&EO?sox$s5GytnzC39py^+ zOXbq1!zP%o>j7@4ydCbMycZs&Tx%2CvvLVMOZimzD&@1`JC!eiHz+TJw<})>|5Ldf zrsKwGzkLUXmHp4q4pGj4hbia7la)*1Im*|?xN)2+InP#SDYML1{Q%!_%53w%o zZW0C|%eF3Ap|yh$Ldb3iWYKIi#7=RD6jr{(n;z0dbNzvn!^?>Y0E-_*?c z1pCYF;or#};FIJ$c(ObLzDT|pULao!KP)%FFUl?OM{<|v@%~5N7v5`svxdXqBjkKI zU!Dk$m#4y$)_dgLPbPj<|!=#|{O8t(z*rq{X#tL^yLaUN|Q{?69d z;Op#xW^FBRcMbNIo8Q6pEH|y|8jO&O-ox7Lm=C)KHFDz@Seu;xpRU0ja_|+dD?5H8 z-qXtM{@XQJE9b!fk$b?u%A??24>D^jfDe)z;or$;e~s&0J_nvGUkaZuH^JA+dEa1d zauK{tz8Zc_z7^geKM4OKx4`WWHtPw#?HcSO7r{r!&G2#Zf#2ahiJT8ll3U=Ja^8>l z+A24~O?C{t)YgAO-|YCGagEtA@W18!U-7zhh|VLtr`#Ci1c%6Zt#X2aaszz2{6~1Y zycE7heg(cqeiMF54z|e&-j+LWn-hF59|71J0A@!TsbV@HqJqxKeI`FOxU5$qDX|cWIjwJSq2t z-4AHGzshHsHCgO|xS!!OFs@H=w* zozN5c5V&m*vz}paS9t<_xO^5oL~ev9$ftD332Njz_zL+t_*S_Yen8Iem=ioJH^S@W zrSNz1Yw#|IoArDNA0X#-$_e_)7s8|DTi}UuGdx}X9KK5a7QRi++c_tASRT6z&X-&T ze<;s|e~_Eu9ebMf6zz&@Rc?Zhl3U=Dodl>)A6W*iCMN50zWsd^x{sPB2z(%*hE#>=?Mgj>*jluCrs{Kg-SV z6LQ{OIl&9^CGa}=R`@GB9{yGS9Nzf|v(9hf{pGy9bAmqdfPHYC%csF-$@TC#aueJr z=jY`FH^`0f-SXq`-{m*qf65!-PvyLQagE8%`{SJUHfzf}0OwS0JTNCXLdG{-!7#Z9 zKHZK#6z5lNJ_?_MwtjR@ut0A79jTorQBM7sCZ|16(d&2hWo4fal8hz_-cG@PqQ@XXgaZ%eTPmnkKvt;Hfswi@wHNJu0jvxqMDpwxE)iQ6PzZu)Zz2gj;YTH zE|ME(<^=O>{qmgPJ~^0!&r`YS%ADX|a`W7rV7;v`#M`t zA#w|Ry8Ja|Qk{81t$j`x>8Dj{eI{@N0Gq{FR*dB)+cYo8uP2`^fX*f%0OwP+kVlmY;-gmYdOL z+*@7)50<}%PnLg#C(C(H;eD4p;AwonCZ7f0F3*M^k(=NZa{e>8#^gr$bNO+&)nK!> zx8SbwX88Z)ycPJ~N}dj%AYToiE#CoG$xGoz`7!tgxdpz{j(HZZQSyuMDmw;lk%Q-O zJ;;r4t088c&2Sfa1KeHS=6QTgl=py7mh<6CxdEOd&w&@o^WneCx58`XCiok<8Qy8A zSwoMNcpZ=jz$4_*aG6{LpD*76&zB#EACdnBzbStPe=mOzcN%7nmG=T(ljX*ja)P7f z;AOl&xAj+Yf>OEp)tum5Id3)IpIg6?6WnFTzmM;E<=_Kc8@B!-zF)BZ1U(;a*3k4# zPO!V&ycyr$$t^$U1jkzkxxr-XZF7V3tlQ)USIHgQB5Ow88-7Uc0Y4-6f&VG@h5s!V z!9U5%;hjgAwY>x%D8CIKBM0qrgVAz6Tq0ippC?}f|3O{|-z_)8OXZK?=jBcC+j5)j zbA!+2PVg3aSGdDSv$lMAANh}PANd}5guDzsQ*ME$%AI$}4bGPjgRhr|!HeZn;iu$s z_%*o^ZjoEyO>*9jxk0<*&Dx6KJ>|>c?s5}6P;P-wlJj=L`IU>{*>*g9y&VrTk(EE^ z(9{7vv~~CeIj>`G@PS+e|76F*?N2a|ZGpSW`JHlu!{kOdUv7rS%Adj$Ug%}D;+Ozyx8&Mj-PkD*6|mPw>a)FE`DBnJ3hp5KgUBIpW?XKagF2i9AD*lzT-bT ze%Nude!ef8%)DQ{v~? z(eXZxyE{JC@rjO$9oIO%#PM9mH#xr3@q><^aQuSfe>wiQUf7!49dpg$eNUkM&Ny{9Gs9Fyvgxx&DZg_9KYxI1IM2@ z{@n4Gj=y&NgX3Qux1SInH_ve&$N7#&I3DfzRLA9xFLK-pPp_2!!+&nh`vQz9HRWIt zJSp&VlTRwfeW+0HhR4#Jq8mPj;e*CopvXPoKVi%_8c*Bt`#9sRIsR`L)8;fYKW)d? zI^(T5{@{sw1UVW{+ws$#@zxxF3&!-)c-oHN)fsQi@eg3kV2!8k_(9HiYmWaf#+;_{ zv>o3Ephx3>)*OF8DeeoQ@ifP4n(O%^#&kU0To1GzZ`V8;1#6Cf z6=M$7c-oF1=ge=-@%v7~{R}mpw&PEA##?iI1I83-JZ;BMaK>A6{A!GusqwTOkDr_f zJsJgTj{h8EZq#`Cx5l@gjQcxjJpEha_r{plG@iEOk95{!&Gn4Om@hS+w&NE#T40FC{JKpw?&)1schm_;Ka2ikB@qcjUx90e_FlMC2({{Z5oaOx19KQi$iZ!0L z;|DqOTXXzj6}Z={#?yBE1pv+YtvUX_DY!p?#?u`0zdnCIz?fGwp0?xd=Pc*9=KQ^; z;@)~1PuubKn&)_Hj-P@tyPs+LPyg2VJ29re#?!wwejUb?XgvK}k6>qj-L;x&F5><_e9c?Rfh+#qrizU*8wuvG(ix5;*zwy=N726Er_<=Rd*e zr*+o+o1FQ7&6xi@%z5nDrk}K(|0ZXCYd+u3)%g0W@w6RZ2+(}K)*N3~gM0pHJk2ru ze0D5XgqDl-|Vc%n&WT9m{}T6+wreBiUjWb?Z_V+W&cpq( zG@j-dj-Q1OJKmb(r_ILuAC0H&c>Hy0G~Sxymz|G$2WdQQ$8Xst9#5~s82dfK2aZ2; z{H5bfj(>E_i`UN6)^SJ2yE)#=@&1mv&aBVJ12Lu)`}kjfIQjX$v=R5UL!IyEY5RO{ z!+4tgw`PCFUxa&wX*_MmS3BdaIsR#kc}(N!-x}ZRV!WT!c-oFX+?n5+^A};v7LBLv z_(9HiYmUDiWA-jG&zH92?Q7;}6s)uQIS7xn{X88`_H#4loUi%m$KXq`7XD|C^>>-a zvgXK{k_2Y64_Qqrn?2Fejc?H}9 z?tuE$`{8|}9))#T%51i`oRS@5s&lW;rC&H0%(w3p1UBm2vI4L?NY>vJ!e zuf6?bzOD|G`I?D;It%CI>mmM%H#A@C@U3}hzK)@_q4^qBF7q5+NNn0MddQHie|~o zD!NWy3*RfRgCCQbRrIRNtfKd2W)*FcnN_qS*2r}-t0+fiR#7i`GdxJ%0-quW&*6Ui za%;FjZU8{m3*HhhKL2sg=>!Vk-H;FsjN@F((h@J4wa+^UUP!+f~Cyb#_? zZi0Kti{Rtr#qjC!{cxrH0DOtO6kaGVga0fqho6+2;Z^bqxJ6zGe@a1wR_(r)iyjb1?{)e0kzar&TV;2!ck_!xOUJX&4| zpCLEFHS!|(3VAX72l;;ZUiks|QF$r+io6W|OkNIuD>uX2w>Rrt0q-uagnP)V;NkLW z_+)tvTp_Q8XUgl~YvmUB9{FSVZ}NKhC3yq*vYJIGn^}LfqTlqO1xgl zt>Kg9c5s#49==%a1TU03!w<-Nz%R?W@CG>#{#EV<@6o}m=V16yxjQ^e?g^L3ec)=j zAAFJAAHGJ;hnwUfFrt~mYjp(tj64edmpm5!L@t20$P?f$9nE9Ug!h$;;NEg6JWwu& z$H|rOWVr^elk4Hj)>{s%sS`6d&%?R?(#x- zsN4h>$&27hc`%W_Yc<0{&cH3I8Imf;;YP*1Q_t zPhJBbEw6>g$m`&VatnN({4so^ydGXGZ-5_{H^Q&Wo8XV-&G5Fnm^EyHyUD=|_*{@% z!^g?(;L&n>xLEE4&yYLA7s-3TH^{m0Epi^bMD7MZB_9mGCU=KFl6%76%6;JNcQtG7 z2k#~KhkMHT@L+ieJV71-SIVQ{i{-KKjdB6}XL$nLET0Llm5bmnlUW90_;czHH_mfQ$WkuQZWl;^;Il;^^?%h$mV$@Ad9%k$w^H^bM;E8u(NmGGnTD)?o2HTVUIXJ-o5T8AxE=lygzH%c<5vYkx4{1=e+&eDxexp&xgUJL+#h~Y&WB%@hrpl6Bj6w9 zQSdH%nRSkZ50MMte0c(VntUdFj$8y^C6~gt$>s3lawWV*u7SUj>)|$go8vaXyU4TQ zZgL~sQ@#`)EYE=_$aCRI@^$dJ@;rEsJRiPIUI;Ifo8YJ9Meu5QG5nT%Km4iu0Q{}I z6mEqdg5Wi|4Bk~<4(}s3!$-&~;NkL0xIkV7PnK81_3|3{3VAKOP+kWwkz3%W<&WWi z%Io0`@&>qdo>}KcI7i+DA0cmsPms63C33I|uX}Q9_y)Nh{1>@B{Jh)={z&c&|0wSP zx82vQAs6l{=fMZb-QfQ6!SHywJ6tUHgs01W;7jCw@B+C%{IHx4^Y2V~j)uVR$Rpql z@+f%w{mhuL@WFBc+)thWkCxAb&z6heS#l}-N4XqcB3Htz^paCr_qL7odwm9K+m$n)SUJL8x6G`ffikm- z#>vbonk?tSwQ?SOiOj5`Yh`8?-6k`u=pmU|MNi7iDq1Zwt7x6vAO1?thg%Te9V#=csK3mtqA@bFiq4SFgr~_x@GO~GMRR3l72Pf~tLPz_Sw%0%%qn_Y zW>(Sn@@#mwgR$n;CadT$xdru+GP8=xWM&mzATz7zCYf19OJ!yiy&^NKXoJkGqU{ec z$7+HPl$ljDz}AsZbegThGh}8J{ZVFC(K0(8e$9@D-Wo8wPl$ljjEHkTUmdvc8>ttpX-6u1v=vkRrMep13c$2(IW>!)A?m92< zfikm-2FuJUnkX}?s6l2{(bY1uitdz|RrG|+tfJL2vx+{GnN{?Q%&el$hnY1ntEh*} ztfJvEvx(Q6nOQ~6GP8=_lbKcYjm)f~Ha*O7nN_s6%&elmGP8ijI+)Rdkxn ztfDHJSw*vDW)=NjW>(Q1GP8;vl9^SsLS|OcKV@bWeI_%jXp79OqE0={+L%?;O=eb6 zZ<$#|LuFKh)yu4n zSw*|Z%qluaJ_bHUW>(P{nOQ}}GP8=N%gid8D>JL;E}2t-itfI^9czC`Y58rF+pW(R+ za1tfCWSW)+MHLS|Oc&oZ-$b~w_knOQ|$Wo8w1xAmR(#Qjpt7-khskeO99NoH2j z1v0aWZkCx(PWo8vM%FHUdNoH2jBQmp! z-jJD9v`J=G(e6i?V==3!m&~l9;WD#|Cd$kzI$vg1(H~@H75!CaR?!PGvx+{HnN{?w z%&elEe&)D6;G<+_6`dqAt7w|ctfILxvx@#AGpp!XnOQ||$jmDGRAyGu4>Gfgwm;e& zmsv$QGP8;flbKaCKxS6ac$ry6lVxTVohLJ^=qfqb3mG(WKKy{ptfJ>-W)-!_%qrR_ zx4_%|&a91DMf=FiDmq$bR?%3QSw$5xvx+X3nN_qvW>(SPWM&n;CNryOgUqa=ZH_U= zWmZv+%&elmGP8;bWM&oB%gideT4q+!LYY}b56R3bS}8ND=p8%$AUt=OSw-9RH)~*4 z(VjB1ih9|4U))z;W>!(59rHWfyIy8i(dBkLvWjkznN{?t%&ej}Y`p;2iLIZ4j4+v5 zMLQmA*2Ao#JegTVN65@78YVNV=yaJ`Mbl(v6=zMbF60Dtbd^R?&KySw%m~%qr@5oLL*QiuRY8RdkfhtfJ#( zW)&67%qp5GGppztnOQ}*%FHTyNM=^iN|{+jAIQuq+9ETnsKa2h9%dEoBQvY$NSRqh zC&GplI(A!a?yD$0|YRrEWV zSw*MF%qpsonN@VI%&em8WM&oJEitR;Wfikm- zj+L2JG)`t#QH9K`qDy3E72PH?tLPz_Sw+vt%qn_IW>(QxGP8=d8D`eNtfJjzW)*dp znN^f8GplHV%&eknnOQ}b%gid8FEgv?FEX==R>;gMdQWCn(T_5-igp@q*2Ao#ePm`8 z^_7`bbfV0xqGFj@MKfh)6(P`GP8<)k(pK0d4yRHvx>UQ z%qki#GpndnW>!&y%&ej-Wo8xKCNrz(5t&& zTA5izi)3aM{X=F}(c3b!ioTYaRn&fzITo{u4wRWyG*D(%(U~%{iW+2Q70t8b;rnD} z6+J66tLOunSw+E#=2*-s+E->)(a|!qiblxHDmqhUR#A=2tfGr#W);n|W8iyaW)(dq zGpp!TnOQ|2%gieJ!H)SaUMEMJwK1zG*ZMoWhq3-1U*lwE6_v=$Dyp|*e#CniTmK2~ zVeEMLK|2OsAv3G!Ety$GU&_oX+GdPd53`E8%FS>unOQ|6WM&neZtK6|HA-ey(d9C; zikj>g{6^z)nOQ}z%FHTyPtI$FY!tZ&ZZlT>fp?dgRrG%{vx<(jW8g6|vx>@W9X?lP zR?+Y6m^R3dkeOBVkj$*2=WQK+UuIU(4|WW^!%1ds&G4Rb(~ig|l9^RBNM=^iI9u<4 zwaLsXYOrJQ58_wJ%qnWK^%qrSpoLO7Zp!(P9RtsmnN`#zGpp#YGP8=Fk(pKWFPT|I>t$vY{UkH1s6&BS53`E$ zWM&ohm6=s^g3PR(P-r8qhw|k70S#iI>(M#h>Rzh zSw#zFW)(dsGppz+nOQ|^WM&opTV_^Kt24~nm{pV`Gpne(%&emRGP83Um+uYEGJiVl;RRn%W* zR?%oXW_j0OqRgzKS#}J3gRMV_Tnw36MUTkLDtcLFR?#OivxAc+K9`wQ)UMDRmsv%7$;>M1Av3FJ zh|H{_(`9BAO_P~bbg|5=qCd&ZD!NZ*R?#yuvx?r9nN{>(nOQ~K7Mb-ht7s3o2|iqA zR?$eASw&?svx*vIW))p6Gpp!MnOQ|o$jmBQEiRfEr!>pnnGP8MHUS?L&t|ev-%qr?7GplHr%&ejUnOQ}X zWo8wfD>JL;Dw$bD3uR^%Es>d3^beU?MQdbc6|I+ZG?I$y<=xCW) zMdM^<6-|_xRa7f8tLO@uSw#zFW)&@wnN{?(%&ek+%FHVIx6G`fpv(QDcFfCo-)P6cSINvOS|~HC=sr8(QLGP8t$vY-61op=x;K!idMMb*?Xqe2bqElpM6_v}(DmqtYR?*cmvx=HzW)&^9W8jsx z{uBCU$N!9L%#MM7mYG%5xx%cu1wKq>R?)FCvx>&c4RDprtfDJrW)G8YMHUXp+pVqDGlnMK{UJD*BtutfJRtW)*!YGplI3N^>m!aP>Yi zvx<(9nN@VU%&emGWM&oJC^M_*PMKLn%VcI1y(}}U=zW=4Mc>HGDr!4T=NIlOGpneV z%&el}GP8=#l9^RhB{Qq&VwqV*^JQigJt#A)XqC*YqW5HG6@4W$t7y9_vmRy@<;ct` z>LD|$Xt2zzq6spyiYjGh6(QxGP8=dImfJr zSw)@YqCIghdRvDF%FHS%keO9fDl@BSrX2&%wPWy$28-+%_(_>rMX$=tDtcFDR?$Y8 zSw-8{s#ox?GP8;fkeO9XH6RkYo7vmRy@b&-n-bAp3qW)&SPGpp!inOQ~EGP8;r zWo8v!FEgv?9+_E1f0vn6v|46X(I+yqihh)tRn%dISsSy84wQ@FW925eKyHC2$;>J` zPi9up4KlNe?zdy$l`^x6-jSJA^qI`8qRle1ingC=*2Ao#-DPGK9V9cW=qQ<4MZ;uf z6`dwCt7xjstfKQ}W))o}-wZF1nN@VZ%&elPWM&num6=uasmxyv`c`IE(e@2y&CDv= zOJ-J451Cm-gJfnE70Apgnj|x;XtvC(qU&X572Pc}tLSesvx;7jnN{?j%&emCWM&n0 znq}6;tfGBoW)=04nN>7QW>(P|c1$huiDYIKU1Z19=LCO{nN_sd)-TTq{vk7~=uMef zMPJCwD%xV}3$eCy&Dxk%bfCGP8=Vmzh;`x6G`fWiqph zR>{mNYLS^$^o`7{q8-jN>tR+=p3JPGzB03lhRe(&Nk~|R#C3ZtfF2rvx!(X%&elTWo8xKA~UP# zA(>f4FUZU)`bcJ0(XTSIigr2QtcO`e2g=MU8YnZXXoAeFqAHnLMVHIWD!Nr>R?#Ce zvx-*B%qsd^W>!(_3(RquRkWwftfF2rvx-iTnN?ISGppzdnOQ}*$jmBwKxS6aN|{+j zEi$u;zLl9()c!)P0p4F`R?*Qivx>&c%qpt17iW>!(1%&em8WM&opRc2PvD>Ac+Hpt8>>Tr=c7PE>Dmzh;G zR%TXFrOd3Nt7T>t-7hn%Xtm6&qVHs8743SlnV(rj`^wBJ>LW9&Xt>O*qElsN6;;U0 zDmqVQR?%E}z|;7CO=ecnBQmp!UXYnpv{q(T(dRO=ihhxqRn+AYvrc9e^^loWG(cun z(I}Z&MTIi6ifUzM6ZhNU&8?%bK z$jmA_L}pe|zRawm(`059RmjXLYLuB(v`}VN(K4A?MX$-X!W(2}6}7$0tbtiY`^wBJ z8YnZX=uDYeMYCjP6K6`}m$$W>(SXw*Dc$U${a&{{%gknN@VC%&elpGP8=# zwnkRbdDh4(`n@%>if)yeRrHX|tfJ>+W)=NQW>(SXGP8<)mYG%5agJFVvx*LonN{>V znOQ|+WM&mjl$ljDQ)X7t?`38c-77Pz=y91@MJr`y6}=-ftLRIaSw+9d%qr@1rCA%Z ziuRM4Rn%K%R?!HVSw&~c%qpspnN@V5%&em8Wo8xKB{QpNxy-DhH)UoOeIhffXp_vW zqIOrAwK1zGS7uhxVKTFd@?~ZfjhC5KR3 zD*9GtR#C^R&DxsaJegTVJ!EDT4U(BvR3I~}s8nWF(F~bcMRR0k72PB=t7wVLtfHsw zc;plP(~gHfv32GX**d)AT(eGQ740W8tLPXxKn~Ffaz68k)+@Q&B0hj5NugiN9ywhj-LnN@U#%&em6c0BWm?09&A z%&ek^Wo8wvl9^TXq0FqJA7y40?Q*SI53`C6k(pIAL}pge*)p?=8tnMJbAxMa9lp!f zkwf$knOQ~aWM&opWXHoh{~pKPE(kj10=XW(LhcD)FSmmi$aCOD@}Q9 zt8y+pP~M2~!{wf+7sx~4VmoFq&aXTH^>gJ)c#hl%|3RJyFP0a>kIT#9XXTIK*X7Od zyK)~K>kIiz_&a$7{Hxpmce(+6Xp4K*j?WEtrE%`&qQ1A>3?D4d!E@{-Z$bT7c^y1L z&Kr^&jFXGtv*dbsiaZCNB`<{M$Pd8tv;55VWj z_rn*__*`3o$6in4vF}U`f;%)O7h~?$n6((QOzsXpE9b-il#Aex!DhT$J&mA2Ehsebz1;MfMiUQoPTFyBceV5NT73WSq?yMlVOupo7B@Evl1&&>zr ze(*Ci9^3Z-+^1gkBGlK)qu@{E+3=4V|31dInQzumjx}_oF;6kpun&#r+l28wtZ{yi zkyoHTlE(TMA|UoCHjZ<2HII=NWx2|p?ifuENrz-wtdU*4ns3z_$~Z@0kI=N^Y_ z8~KY$WQ53T_6>s5A3UNO%dHfXQ zBFJ54;{M_Cni)YbLuQuK)pq=3++#|93pYkvA^!*U4`pV-{30J#f!{G-XpYN_l`(Rc zO8g$T%&d@`b-|Bmr*-|^- zW{%6;sGc%2m`2LXdn%Hd<#e9R9Hl?W`{GzjWade&l$mw)p3EGjEiyBkIyaf)GXLuU znb}_b3FJi1R1>~e>he-_+Z{-`%zyX7B_34$x+ z3*md^YmW_rHS)jUujK(4)A3F-=YfX>!9nu*m~)VP0FG5FZ$W*5+#BnELVmCZ?oTJ* ze^e0sBJYaz@3RQ=<29!nUUT-NTLnQ&1764FZhywH&?YF9C+4;fYUB>jwh1nf-}J$^cOn@CGsmLwGXP~(z)$}3*=spwh!jYe_G!@SSU~1b*JEdx%{l1 zg2&{hwL1mR%3pliAy_THbyLUSBl*#nItJg#H~!o)*!CXtyl(E%DcD*5wXjpLk9_j= zoq|Kl6%@ZyvTwFh+iU<}Sfm@-_GF5=@d$TeC}0D;I9JYjB~w*N*Li ztK|<1ItTORjpEG+T3gAUyCuj%NyYRX^i>28(w?mzrZ6jCcyVrr^=n-$#OTmrHvm&+;7jL5*pLH9V#Ib*MkD`UE`o9U5y}au8m7v`f}QZ% z$6n3Dm>e4O_rqiNQ@s-PBUN9B`Y|-->3%To>!&e`F=m{`^ud@@R9}hrX{8#^?4g+& zGYVs7%RS*njbDy=Zjjf)x5*peC31l8Hft?o0=aTMH% z#`{=xB%_p>La54#$pMR;%QxVtl^x8q|R4|06G3F#{hn@zH>fS@<{?ALrp?Ha^bB2Oo0*{^Y&18}V@wJ}$<`CHS}$ zAD7_+FU7$X_?Ux_EAhd{T!lZc#>ZTIT!W8m@sSsl&Z;aetgD|sv2bEVRcS@lpM!!~7SX@_FS-~Y_ z>?o_Muc)7eU8Tj*!9f2QDA=h<%!ofUWn74+s;euTHnFm-HkvRh_|ryZJ9%8-qNmwI zB+Jo(rq@@OR98)kj$^m|!`P}lO0ubB_>ir;ZR-og7hvN@T8W-$TC3d0`f0`0I z2~bsN&$>3E2Uix?)m4=w>E#5R+%W`U=y|6tUd9e@nTU|Q8^?2tSPCC zONqnAJEDU+B^=Uz!ny1M8Yg8l(euoIJfU^HV~uv1Mbo`F|P_vOl| zcoREy&F@yK3a8kkq{{YKC3WTX(<B+*)F0jEq)crwU8yadDT; zqLK}cj}oe+dfGHh5}=uhJ$2{c3E_1+wWD-vJKXb;m@H%Unm2R3;iJu`Q|jgCDs=`D10%rpJd^Ne;&slyce^kJEnVT1oATua?xV_cR27!$wO1R_gG-{< zkW$dQHdxSg5fYQ2VxFo~h^Cr_w{Fo|!VQ1Auw*AR8<;YLCiRPU;(xkGe4P|D_pWoE%{My3&Mw&laj^?lBds^F>GPC8+Z)$da zZDD>R&7Uks^EZ^2)s{tH#mcnlA3;TX2)l`6h&o7mhdsuAVW=UTu@jmOrbh*?F~v znT<4evTWzCojx&|J+wD>SkcVJRfXZ7W>&9cXDly{-^hgaW(+Hu(b${OD|s{GMK9dx z9NrEN|1>M|O7Y|Crj}JkCkEf@hMS3XnPRjwZStsw_5i6J@nIUGi>Kl#=Um7(C(Yr_^nC&CCApHuZd2hWP! z&CyDt$7fFLe3kTOwu385D+_C8%*0V;dWDs;BY0-XY$rnhCjec&5( zd(_b0@xqFZWQ@1ae1w_ZE7@l=rLHEL5cKCm!A?iI=a7$6!JP`F=nQCx(@$G*)?}v9 z()1)%!ynNbGW$r>>>DwsWZ!@}rTFr2is_}*cnyjVtd7M6_pOybW9sQ^&WyS(RaWqM znDyz2Z#+x{`^D0`G>8xvaVNOqIQiX9)VrW$|m=o~HF zP8}_*I!80xX3Eg<(Neo?@9N8<@83x87%XV|kX42J!%XTF>{QcgShTASH@xZ0e!Jdq zKc0U)rS_YWKPmeZJ|JVX*`cRuXN^a1WumCu5WhE=M*B-<#jZHC`+^vb$I{#v3R{c* zCfF%>$K+GujPa|M9U1xA?$RxJPuSg|C+?N13bASb(jse5`k+(n=U6;^ir-~-N9v$c_^OQ& zQ}mha4c4CMpe4>*=jw37e|BNX9>Q#3iV&vn#yq0-nisk1l6vRel(rI6ha;l7%@*eg zWoJ*6?ZRvD_oT(q)vYaWe$_O;-Kr{-%>1cxG(Wy`wx&h7vo^go_-)QgJvpS@~m|75XZPkv~eeg3I6x}|8wS@q@B(O;F-m@R)+Q?v7G z3o{#O?qu1{AN?gwt-sbqA z@3rac-IVO4_B*`zYSDiG3wczGE*`hyADT~=e`}#N+9T*MBg`va^k{?Vici$-w>pWk zz2Xz)jOSoRq!(@Knad2_4INuB4#|yZXm^!RQbDJ$r9?H(1C`a>8E3T}pFRqOKEx9f#_(zG#_CRp~ z$BH&|xM&-fQoJ)dDE{8EzHD;z-5&l8%WV6Hv{ie=Xd81{>v(pPhl_2lR1~I{)K9O) z-;#R&KAWm1kM2JzUPYpgL)w3+O-;%5OpLxt)SVN386*AUpPcJUm7S_lA z4ncZTv7o6!;yaM&-yxiWooYr!-E_RS@OtCbyve;iI*MPbDx6{ak+CB>>O}JoG1)W{dVP8iU@%FBH)j|K-jpN3R`zEx8cPiUFqK&PXtOWVqbuWzT@549POb6ylP_B#Jqo3S_QS~>o<(Vk`6 zznoaH=QlJ?1OL>L-BL7T#k6Qb(4P+lI~|GH@P{Ug3wEjo=lg-s-eh4#vl&+vhJTv* zyizn{{8p9U*820IV5cK78~)H_aUq(jt}^;tlLp$Kj1@auXiUdHHJ@9GW}H@8S5jU! zE&5W0dNZz zLx36k@RNI!>&vtEO)Z<1y`!$CxTGw#3&Xc|D17axsw>QzuMR)Wh`;#T$};e<$y?ot zABDtUByHu%@#iE%*_A^<}n&$!1QftqwnXwmzb)dQxF{ z2tE`)q~{z6Tgek;OHN~K$+ppM$7chT#7RKK?>!3XmZO;JG-{~^N3%u!iz@!J$?6t{ zW;Y2tyxv4VUFggi)slVkcR1bhci5i!)wpv}J<-3Y?sqXNr+XRgN_8~alj^IxC%S5* zqB(Tb@P`mmg8eOS$GeYhv9_2G`J*4rI!>%&^Q^-ejXFy7;hYiCMZN_NSsJFW8SwqIT`ZkjD8I%ms%`)oDcL%S!{NV_A|O=pL_`l6pG_b$MaAzc3h9=jnCd2KsYaSw z)I)40+80&)CzsVU49)HrcDSu7aT-;UY?BIclT=WPv=ud|B+;G{zd86`-y9}(PI3^2$u@jZTL*seiTl4>J3<*3_(1=1rY_`n)0j zsf>U9!aZhOO`XQXF83rRc15Q!QFl&YyeE13;ysCz7w^b8b@9&hiHrB8Pg}e%d2W(> zvb&UdUgC#t<*dX5ymNxT6LXG&t>ihdC8zhcWP5J6<6fhZ=rJmOZ&6716vb38QA_pE z)S?R>n~7FN75~X)wGKnGTZSEOtN252`UReNQm2?`Tyjs`zvLdZFFn^E>g@1( z>(o;%cJ?JZ?d(c6+}~yU?o|Eur*>pEEaPN256nC#&VKjQ=y!7BquAf&@&BUDt;VOr ztwvY0`4==kJUR^;=br)g0%S4=e^qs4kaW_z{IYi;ow(M`?;C|hr?2ry+t#=ecQvdfni|&po`$7#OT%)iqhU4GP+N`q85R=lbZW^b zoz={6cy=$tU0y5on>)_D_IG)b*QxpUp=3kd(YB>-EpDo+iMFchH&(@TYqcZQT-8(U zjq6c^RZ6tjtEQWg)n+{;yV2U|wz|~$qE?#xlBPm@rK+HoYAb4HY2r&+ssDuxuMo*M z(50y_Vx_4sVPVBK%1&wDK-=xOIjE%HK;w71vfe=Bx44`)(EMdAXC7=NK6yDHaiv8i z+Y&n@ZVD>?)y2nnR~8HD)}WZYqBt;lHN~?s3(uyhfT|l5`qr3du$~Ri}|o)i%;8#f>z@L?cbnZ=|WE z8)@pPMw)V}kx@CiMolGgjk?8D1G27B^MLGY)a>(Gt6vRurdB1{T(|6W*Dc%jy0y5! zswNt&s^4K1(=FDHRF73pH94+FT~;a4X0MuVMpmQsknB!tr`u}%j%+-+3W-L$)ws`Y zRc&@lQI}Qpo2;VOW7SeERz2Bam6HvQ%eKF&`0e$IsRm>;R}aYSt@e4Xb$<=mncpoZ z+nn0xG&{A=wmh{XZoIoI(SCQAe-hk1=~LnEO`Q;TXX>;hc19=1ttU=Vde>GOnRU9{ z2WOu&cSP2y<1bRD56J3PPF%Drecqy7iPIL?%Uc4 z)4t^SVmbSC#e1@w_diY+ANoJf6$iMdD*Vm#_%PvS;^f4&_^iY=osPH=orkdGpMbFB zbv~@5S{_!Dy$*}XCflOzZn*8Y)hQ*OXhtK$!I>Ql_js){zj*J=X$r~qIaQ~DPSv*1 zDaB1R#Y7uT(Ql-wrCVw0sb-pTs-00eYN)9sTIv>44ajP%c|dk!%|5ra;ZMHD^M;#= zw#K!%sc}s$jSEpj!;;_5u;eu}tfX2QR+Ehki^(?HqHSWh?YGb=C7x(T`@+GQ%?tOq ztqX6H5YHHHCR!KQ;?~7AwJt71tqV(j>%x-Py0DUJU06-FE-WTn=gero6>&<5CzjEw zaBya;!aaVg%ncvhNlhiyFsJPH%qd50b81fKOf}g&Q%&^G6f;_AcBH##>gh&Cb$c1w z`(5}~qF+rnBeTh7?ydCM?DSiW+hVv=V>8ucTXQ>XYf*b`!RakZ$;P6T=qf51Ek!lm zPZZP5G{v}+*iN=FDkYw1W&<&JE8W8$uXX(GH)qE1H|YGoqmKW9#A#hL&bBTp#I0i~ z(K?p=*0GXq9jmFB$vtXe zvK%$i+2Oa-+2J+Ssi#`&>`OM-*_CXwv&+9OQ#&$SlhJtRftl@h_PZy6|19WSui<8* z@o_C~d0bPo<3iNtu;e#5EP1UBE2*Z2)nq%vVzQC8Xg}4%ZNH^XDQ>1IrvF|ntYf|mZ6yH7;348nOf8@Y$n)Z@&Ftz;W*$!Vf3*%sRExPho7+J}nY zJQUKcLowAj)KYCTwWw*>OtdVj_)jjYT^O3(EbMSw#eabh?_d;98I=-E^XqZv{JPrb z7o#3VWxtV8+3RLhO|>-Ilk97>BiUSchwX4w^V^Y|G;n9OKyB_WJTOZz>$(=te zq}m==-KNLYsO53VX?R#nwmU2)njO|MS{>HYjSkD{HrsOCmVbn>l+ot6?zcIvJ8h1OUYo;my3JuZ)#k98+2(LhR-3~eS#5TX zV837Dt<9WrMiaKu=I}vVZF9KSZ8L8Q7EjKtM02B3+}Eh2mPXrAH(Bu;$%@xQ7EZ$R^O@~Lf1G06A*X0ByYTL6;bWsNnNfb9 zOwH?*DW!U4%E@k-YO-JMthQrrE%_WXx@LxF_RZ|_I>+BNcP8a#vTsq%X5N92;hCK@yWCdtK6UY& z+)A`DD#cBVN@`)W9W{^@zkRHD&0`_eIu?_SV=dV>)ojza>9;Jd_)jjQT^yR(Ebeey z72mkd{aq)wnrK~WSKPwXF10dMk6P;P@muTe@mlQeNVVGCnQXbcFWLIUK6?t>vVSVl zd*V~#?Mwfikh?qc6uASkPt_FX>W)WGNnYitU0J6}k4l{?)iX}jl*DI&dzh`9D%@=` z`Lnt1qqcskrldYg+{fWGrcc$B#Al8B0JFTTQ-w$UuTzD4LuUPKn>)96s>1s;I>!mO zlb=a((K#`3(VmjH5}%B)miUYbYyJrcOX=2!3 zvl|-j@>?0+ozk5)ETozlSKV&L)u^3u$?0cUOg1zuCOR6{GFlqe(>)E#>89Fp+|{s> zY^zgDH6XLG;RCkP*>IoRTHTm4o>_%NYu#$xTDPj!x}~VKD*CNe(QB=0sn)8VY^}=4 z*2ZPqT2=hkdc{-&GFqz#WVTlOyw>vWq|UtDOtv+uIZcgfwxv-aZYWEMcCzF*la+KU zSxq&P#Z((rjGD;pL<{3m;)!OpkAt(D$30%_aEDW8LTn`)XG>1sY{|CGZpU3iCDAlg z{GOqZZW)THj-i%nn5jkm!e*jfQN@39S|SAq-zxqqs5>9GQ|*e1Zo{Ht)Uv4J zG>x@n+gM99j-`y&v7BxmtLgTs8aI%IWDDb3@=0g5k;AvrNbd4l$y>lWlX5fJ$f)M@ zF{;@%MuoVGEG3%AlHWsC(k)~))j<|h4OB7eAGZ_ji%W?on$tBGl9dYt4dTr{`t4&>ZVa4{yPHDf#x7%@N zP)Wbd#to3O-dy9B$Ih?Mg*PpBCgSak6IWO`B&<0-iN@KsM1{CBEcsVfIF)x@g_U%R z_|W7v6%I{aQMMTMijVZKCg-4uCz{nXK0do|+~c(_{23u<%J^r7;`;-d`wu6(7mu{< ziz{*e!djw%Va@MgSW34rET?)HR#Q#1)u@YMA<;&smVDA#jSPopcQV}Nw$j`%IiA&Q zC$2-M7+;7^QLS_;Q7cW&Z>6butu&=nD@{4sN>fd?GOF5Enu6a-x0Za;8Lc$KGh1nP z`K=7^4((1G7E;ZOt8O>rYShlS7It=bW?3P?rK;`w$&-7 z8j#u8@Bv%tY`D*BZFDDWXY#0)Y_Pw>>9N1Vw%M=7osQ~>W=D0u-%&Z;@@QA8>(QQ6 zKRmJ=tz zmhoqNtJ&zL<>^yk$EVJK-H|#0&W@=6wuV1(RQs+VI;<&YG$yP0cCPH++r5d_`!`MZ zj^yu3pNfqA-YLo0AD^0xo$e{}cc)I3zuR-oKx!WGpln> zZPxDp(fI6B?N73`Q|^!QPCf2j?;I3c$rEf#&N;Ou+iJTVpE*<#Ckqw-{GgCNB`BuO z0&1zon_ARsY$nV4;P7Ko?y%8BNs_r+aI?^8R|JEFdN zyZi=wySz?&dr~d;_9lDp?M$A8mZ` ztC^nQOwG+?lcSo`;izWY8x`W-vXp2nOMX{bNw<{MR6kivH8Y;kepw5%A|SAq+o~}3BAzbXOf)O5#odZ)YFAu{`W2S^hJ_`sV__xLvap)$Sy)Uq z%@%Ff!fn58PATz3Ga45T&g@*c$7>z_s@s_mTgk@RlG8U^vTd{5ao12uGz}HMXDFmw zhGME?sHGZaYEi$inP^v3@t<5)voJKfSJ>gTiuonZblglfE2=r&ifXo9Q6cUZONoZD zi$PX%r+R$7Sk z<&yHk^0MO6vf7}qvbuWe^qL+=^y+;?P&l)?wiLe?RL{*`0d8?~9V)$0 z(dgd&`W@|z#%4c%bnkwBP_d(rKB}iX`sluRuse6}qmRVFHM&pFBl|j|v3aCFx=+tu zn9h#w)w_>7x>xVs$vfd#2y9|LcYLp- z`1A%1E*v#z^l)IvAgdEC#>cXyQ%{hN8&qI5YGlFbCk~omH^+>T1|Mf};-C|TT8|xT zHGagPan44;iKC)D<0BOg8b8)fJvb_B_mIK%Awy2X)38iO1QlJ5O!Y$@VeM2{>_3!Kgv@%$zv1V9>BJqwT5W=GZagqs_4eL+zqY zoDe;O(Iahf^n^jRlS_ia@Xr}R;h5u&x7QPRyq^4+!SS;nGq@mrUSr0M99|ebfE&)@ z#||1lc#v(=SezxzHg<$Pb7P(6jU5?XVPj7#7%|3P3*&}Pu!|k%3?Fy$arV^M^E=-5 zgom|#8$Wo&&=c)x7(aMq+_~{1;*&W3#6hD*6$~0>KR3poWEVRgmrTLX;r84VMAvKF z*i+)8opPLewPVYCYMwFz7lb&{eo9V=dx|p?uG20$K2sCMkFw{ou&}1KdU93qv@*m| zO)D=fYbYz3j_@k`f?AAw<5wYQER4{?OF3RFn9~%O7y=jVud1r9$6o?tkW`2W&dQ0! zB~$q#+M5XqGTQBi@RF9pVzR3*xQmlO~l#5wq@c?XeNrR#zWBqaa$3snr)( zRHCK~!tgnklrw7#Mc!1Nf0R}6|Cj-P@E6aVLnEHBrUI#DwPlmb8frK?{J>MK!M{sJ zE3`p=X8tJcLz6qZ)h6;GR3F?l)~9UduBnwZ=!uB*W3 zqW3Va(<@9eH@Qkw%M;rbXodH%imK$y(-I?abtNinq`56<{M_s1O)s?M2S zHXY|Be9$cZIisSs8Vkbv0sK$*2aLzt+t@`Fd-JupFsY&ep{4OECQSK-9+rL3|hC`?=d)jJbt26&E0Rjy);5xhm=aSlP z0dJY7)9j1u#oJ;}JNU)jM!uPHwJLtl{g$`4`a7XTQxUpFT*mr$Xt8_jIA5B7fbMY` zINUCFdpPh@J+wqG2=|Vw&0_ZleActZ*FH+W3%GxKwq)9@KLyJc=8ddYa3T%IJl#@A z%vWpp!n2whT~b}DM>6iWce^FObc23C z2fJ=?$v>~bkT*LRu-WkZ2!5~O1V(E;;Q&LLe}>(qc}}39-GDWAAiC*q;$D4hd~z!9LYM>0j6}S?{K@w zVkc{SmZjH?_hg{6v3vdCOWXH%8+5?)x!c77uCoSE(c%6cgC5FqHiwgMu8oYiE_YYA z(5j-X7PhM2_%%U3JR8$^Hf`xoaMHaA zVKDQH#lcyn>HMJ;PhKu|!HCyUZiC*$1;A;GtSrq;SDdQz<))?R!vL0o@#H;pGAo8J zEzQi=m73&>N=t=TMOTdudAwP86{%*vgwzyXKl(adJbLnXYmiuPzg|>Nybg@(`~@*n zyk>MUrh2S0TwbY+4Z}M%Z#!RBnN_Z(VjADKVQIXIvIJa0={j6L>8j5xwQl3mJM+Tn zlAgdBewyM*X_kWavh_=A#oNg27AAI>56wl;6kH#2J@E;3TaS71RkUiLM}0kUxyDg6 z&c9#cv#OT5TwmK(?e+0Vvwm@hw83xoKFJcDII2#!xbO#OyG8!q*p{CQ@MwY4$lPg9V01VT0~& zZs1yYHm4`OEE^8h(kozGxq%sZ@FUKb)o<<~?_mpj5uW=#w+{f^>)AhuUBw0Gi^ zL7uRL6GVV>vAxBXzqq|S?1L|yRxaT8h|exB_UkqLlwKU@XmIgqcXfzG;c)>s;bwgU zzwEGlzdx*RU~@5a-h^8z{C2sc(KsB2hFt?wID!wWyg9eKtIYxT9@wfGTo%Kr+!a(B zR=6m>P)6Ysj4?t#(G1X&mY3j(OWXuluI_lbQDL*Zg&qYK_(#jb7HW65fk8c3mf9V? zg29^o5sW+$k}7gr_R0q(s}M*zQFQE3q{9EwCO9be73A@U&8nSmVO}P58EII z`AlvSS;GZ39@~e`JwZy@a^GhG>PoLW6r zyHf)9P_H+4H?yO={q6|vVqV{^)A7H+^!jm95Ux+pT z4{pC+?N?WC@w5SBQ$gjn=wH7jd$k{J%KzEDS=~{fo3$G#@|*Mj?SU!W8D-#X|95xB zf4@Aweew)1{U{M1UPg+Pw59%@fD-@=s{8@F7s8sT-|WPyX4$ zT27pB1t+M?TJ9#JibsZ{2M;8~-dFJ%yWMt=y9REE-VMhd0(-jMfaagEH2M@158%Q) zr6HVTfx#(wtb`n3;ku1f!7viszP(=W$j1`ysY6%`Ss_1NPi{2Sgl@Q^ZnW-hFyOWL z^q!2cFdav~;6LiPa9xMO-pC4h=(@YX2-%zMmW;44eK}jAwhT%f0*hl_@d}@wP_e@9@8_R%+ZxCQQ^UR{4=t}*Ew2Ny@n{hlJi!gL&El944}MX!)DXa36fEEIs( z+~ED-02dck_H5Kv^wbTNpIZqYtHB3tVC!gU(Ijb6R3BK}HwXyd)P{wNhlrkr(J8 zYwi$7A?3jydenuSgVD=XFC3%{>oEhE+@D4;@eg{?(n^;BO^XqExfnn0i#qYFd)6z{iS{(Zwt(!Rvr1~nB5mM$% zW32cG9cbw$7+{6RZL|uwYBo6Iyq)16%tlKy!N6J`cc#$~yr{>=9QeT*$O4bga9&)o z%s5~R|H%Ri({YEP(_dXd4_gmz_^b>VaKSFL<_d5&hLuX0v5920go z9218BXvBq=LZii+moIPFk2*s)cupKzzJWgwlYMdB%rp)+qrX@vub36bqT#=0#Z|NU zNc3_R)-g&<4*cH*hj-ckU5HP^+Vq4F`Cu|yX`GuM7-BmL?jS?oyg&z8v+cog*BSmH zBQD(pgX6cC)Dv+Lblgusio1#?-3y1%aU7ij=_q~h)WLZe@1jw9 z^3!!Mv5wh;dm6--Y+3W{a5n%3cgYDBrsI%5{6`%Zrl%qNm_W~z_AGL5Kn8Tdk+^Eo z{qUv%4(n1VT)GMFA$+{L;WBPqr<(`(2Q9R;EVz&IE=mj6@je0$?NSz8x=9CtF$WI^ zlanRDQ_rO7x|Yv=`La_lLSd)C2gSzMifr>Jl*UnE8YrY&s4&90*uhzR(k`xG)Dwml zU|677WaK${uQzat0>^M1h8`GbLcP;gzKp>Q>YLP0{&>IUwM^8>guT7zD~ zIy_Ggy+JP~ES_9Yl%T3=WJ^OdU1z?Q#Ddgh8x9ZE3j?@DDP`aT_sjrom>m`p)CCQ- z)Ijj)XxvTU8Ced356jNA)g@t><7JBlN@5P0OjAHbZV<0q}4g;sx6k zQmKnyI$5ov1V!o&AH!n3<#B&3aKE>LU^UkZ1g#COVn&PTf@1TlE{zzJ6gcP-KPsC! zJU7lQ+hi?^ujaHINu@GGv+c)IiCTrImB>(8+X@XuQulMpI#P%q`23s$2hucfJ8G0)oOBq$0^5`@E)R)ROq<&Ux7LX2xvfK0QmfVi< zh^n(+WEzZYuO3d-%EvA!oF>6&Xi4VaB3duuETyL>(Y9N&rjBB+35%(A!12uT)IQ;J zKe30t(rn&an#uc1GsPa$jG@moTj({-rv0WFa?fez2}oM`*y~zeZHJW}1n@3PI3a>r zHGHJU={0k>1xCN`lCaD$y-E59&UDHFaO#tUpjl9JbdfMFSSTE+v0#+Q;YiYeoPh13 z6$zR}4a`G48d*{)v}h7rQ=7T0ar7ozd>SFL_?*h|S=0EEg7~~9@vCg{d0v!Y=7Fb7 zS~QKX^QeG6o<9q6b%J8mf%kJ6sIm(1U{xtWL@h#-5KLC365XKH;2|z8MN$cqXi|oz zHgj3y5}IuB!>E{*617}bv}lP*gK~LtnUp&=*3xlkU0Ny(!eyAzP>ROvu($Cnwp?&B zX|XtNr{&Rlsw62=0n#2|-lQlk$7U~w$ zdWuboY%#BI=CtIfNz#Zoz^D;vJw+r%BJz5Qn4}aDYDC6RygJj8wb`B zoj^s~G|ob$@~Rfl3|&+jxEuIFfU_Qy@` zCn9>98I=?ds$;*2>J)yoRHCK-vL?CZC#%4bb5hG+3n#-=f$Hpo!&?8KBnm;7c8khp z9#Xu4K>!pf#Rp$JLDy1gJ(Wj_l*H@66LWC%Bx!AMny54*uI6|+6O$VeZLmoWJqR&W zY(a4eJXHzX#BpWQq>`e+!cNFECun*i79>3Z3sT!sv{~l}juDU-EW})hr&ckypEN}k zE7-8e1F&%FiT44NI;|({qzHFj-*67zs3d72Jj+%Zk`pB+&BEozWIHq!uV`4Frz@fb zhIzLd7C(s_j~O&4S3=VCT$-gT;at#Ac-?@vCN!R7LU@=&kt>0yw$V{jUY=t5W&q?3y2>~itULu4M&q|=BP+87i{C`q*m)ri4rcHtJ59e zd|XRX4hmasXH@1EPWMcU8z|@CR12I40*AohhgLi3E4rTe6nGV7&n z5j`+{K14c$%-k!X$-`oE3WL)cbC3iym#uL#+T$a(@%ji!-WA+W3o<_pY6&UM(#dF* zlE+W1OikyCsj4Mf8Vb~PDNmDFoUcn2%abgj)bun8OD=6-uu|pSum)>S?9X_^b5YEF_o<77Aw$Yb;#P!BEj? zv<~5LDeSV32rB25BX6kCxms2O5w?sd2 zFffT!fehYKoiYz!RGmEhUDd!E9?}a1L8>;CN}+vJ(q_@Lw+1Ms5kSf8LFmXqY@|VJ zfGwKwGbPt%LHe#MH)rZIc9R`hr$BOWHekE8*5*E4$819}$|dXhVOk{fzbhv>;NLQjSf zdNoA!q;>Q`&gj|Dzp|^7`zDS(iZr2zCwW6~NLAn}1=cDlW=%U`Pzqd7GFK2fQV<(W z&>BeAj3FcoK2vh#M*S6B$6XZ+5fwh7?9nh)P?_YYOcGRB=jK4o&4kPUVbG)y_~Y4Wt?x&0x^p zXHS&pE?DFNm=SP|Kc=qMgdUzl55XZ-fvXf)tE8AU?Sw%oa6!pjLFh<9Y&1b@AXzhp zkSzF2$(0*H1J^MxFho@F9%G)~0w=u7ib({AB!VE4lmS{6Jj)CRrUKM&tuGsxWy3;> zLeY@A<7zrqVt_;5TMZX|_@4Yw;e;Yh6bN2PFFh&GAs}PG)pIJkZgGssmU~<-F7>@^ z>ZnuH+8=Y~+B2Kgnj;0xy)|cI+Z5DMlcmtZzMMV#(y(1T>qM)#LuwNk6APt4ss6vW07w8oG%>+p~)C{4+g8=(W&F)}bjRQTi>zfU0$3t|CREzYl61Y?zr zW-w%^!I0Pny&(>^N;;S-@N81TeY7sQWTVi)Dvh;I~-8@ z(NaDUQ%|5_7T5NIHxdqdI4vv0fmGRf(V_G-lN5=%I22HF@4`H(XQ9y1fLMDJI@aFg z(Ts`3&$StG0oP$y!KjH1%_$4)e7E!z@WnHm~Gi&Ei6Ina%=;*FZ~6}12sH4_%GBNjtrEP8|Nx=|LXU`}d> zF#;`F#-zmEEMj6TT0<;)B`k6U?6UF|CF4zE12BLq z8HQ}dme9s&z#)E=E9Pbku$xVhH-m$Zrh-43aw9}bZ;EJb4HAv5S&GpbC+ek%x@iLB zsJUY1aic|#QPbf>>RuqK6Afpk-fm_p&1QOQHMEQy4K2eqL&Ic~p>e9k&^FazVyo?i z^0>L&GKP0gV`0{N+X@|GQ_;+HFNTt(aa{9OaZQ@T1#1VAas!Z*$dl5LlUiAmSRt#Z zbSa&&2B}nZ0Fs=C1j&-n@x=QOlZA>er~zP56=9GZB8vqhiy0(q9VP1xCd&<{$p(~_ zf;5T^zz8d67=vY7L`zS;dt6Eutgbm!*955x29%_XlcWTbl!lVj3X;T%QALGF>5MQ) zrJ@6TDmFkx z&O=mW$*A~+4>2e!4OoyPvmhI`papWQR(Pxyek=|UvY}ICy@NDeyP>`bBlpCtb{Ip* z9D9N@8#8KnMMew_$p%@qNLV$)t3qH4QUwcAp$f_XDX5(%h#e-2P7=};qe-QrLxA8s zK@Thm9Zs1G5orcp9;5afBmtfIDLNAz9ZCfqN*Nt09UZC-9f}Q|N3do1-xsH+%cp=bxLQXL2{TZ_Hi-NhXBcv z(7~%sLO@7Wa4H3EDk(NiJ2g-WG*B`#5IQmt8!^xtFxHG0BnvK6a^(hn4qpT_W(9_b zir(bn;V4;Px#qN76I?DBFOo7ak`gge8ZuHVGZHH_6_pyLGqxa=iVnb$^N<`_GCF)) zO$>?Y2G7Ju&qTv#O5lfD1&CT9h|&Nd%AFyq9ipgC5rvA;wOZ*RNOYediKc`S-qaIf zLaJg^DL_<75o+22f>Q8-lHq~S(Sg{&f!46GX3!v6keQMzH^K$3V_0B_sPGOvy}`&s znpB`=-N|KL@MX~$nw&wJoM@Wbkea1(HA96P4NBOwjJe1IFazM0X-M6y89lv^DaI$E zVRtn`ch!))6o8Xhag$hJlQuw2dIwE%$E>nLCZ!?{VgoS5OBp8Mk}aXt7f^-RDpkBm z4}g=dh?D4$RW6uS&Y)H8sMXS7tD)gmL&2Nn0fZ4^%`}Fr){2?lyp>BJX@J@FjM?>o z*~NsJ zq?R_CsAQ0+B!(z7d?;3Os8whlO?kPJYcrsPu0ud*h-~<6XC9B!g-;NjP!P4-(JR*| zuTf&J%!#!`ilxSid!L^T#RCjTCMZ|B)bnuvMHj(_tbezOcjhKIYg5Lp`{HVDj6Rt2_6a! z9f}nkY89Jk3JsGPnJc++16=4jgoTEP%3oX;=Q>5Tplc>a*i3@5>4r2~GTLZKh@+vQ zj>d{S+A8{D(=Zi;U4CP}tFCKS!XCW;Q@rg|58w|l>4Z4w)R0b0p0L@Tz07GG2v z;$pI5H7!6jO_7@5Kv60`>MKp+*E(l#J6&>M2=P^9ABy{jD)({X< z6`V?en@WmJ(@qVP0u7YR41|sh#6}FX28=c11<8WTlw7$HEN~sO0z*cHcR^!3OgCI6 zMqnlyGE)LH)G9XA3OJMo=uqzPQ0@3cb$}>Tgs#;}4>6+q1V}U`l=uqR5EPRYq-lYp zX^PPVr-)L4h*D;VN=JxlBZy)HD5CMhbiwCRsptqEI*-|*C86Ut+=iGeRD3}V0E4Os zgX9odEErkLAX)1uS#K~|Za7UgpsW<6QEUK4SUJNOEZZX5UFed#+8;%5mLdp7Ng2Ui z>4Ur60pWGT^%Q;Ay56q!J5rR9hSY0(O*7)92`A#UT*BySVf) zav?1+F+as(f|Efh_bdvP`V}c15oWD@id<`tQqfpp&fJ?qp{1fDXqbP@4J`>BJtGuC z`ZGg5C!60tTlSW1QA@v+`te~;k)@g8m0;=lN^;vg38i{3YClsm4pg~h6=@s z3bl$#G)0BUjLMZ^8yK4aPN@GT>xNq?4r~Pu9vl z8EYd{qqauUbF&Og6Cei-l`;=oEP14+lW!}8!bGVJ7Uj@ZQPyUPnzxXsrEx^f?IL1t z5;3&a5WO{o>(&M$75qur72neYPN~OR_CB>v^rvyrY1WINELPrE* zBLrFl#G3UqNS0n^O0L`p7PyXCfgz%z&t7;qN)}kIIW5-&mkY*=qzsItM2wV%jMU1E z#0pJCrAFzDEl8!J190R#BuAEn4u-lzKuA?^Dg|yTDKW0x<_gw!CT3`M7HF9P<`Qg=*Qw^qXLUZerM~_Z4sJ!~i z%R70Ay-EVZ&HcsZZP=QVUmu^mJkg4;^|eYC`_b{k^XD%mx4s$3t%M+z|aY1iBu_!;Cp6S-}i#^=(^7-@Eze(wD<=qr!eSBn!4poyE;y{^b${>n1Lq^T8@)oq8%rs&mKNLd8%7-`sC>kx;I{5(R4Wr za{5ZQ=NjjRnI8Ij>FQ69&rgqa7nD!ThkPgJ$B&*r)5Avo{yXhPPr>8G^Rwu|a~{0x z7w0ERU!Ghyn_FlufayhNQ9^XO=Ja?^^oN9ak$=Y-{0Ln_~xsBe)IL$ zv-zj(ZiQznEPREhB>V0Bi9MVM!HtRKb_Egevx54CLaGdY zJ9WL@%-}5h!`=E0T^4Xc75!YO!O(M1@_x5Gy524yEN4d_7rUd2?e%KC+aLXT4gbEs zdj8XICy#!4`0cC1oA1Bctxmpw|HT(yoIgGK^8DuZ%cG+uyx#ll$49RpY-jWB<#Kzs zfvwpt=bQDXEF89n1)ShTpT%m0zFEA2vyl&X)fIm&vmc#Ewo*tP#*G#_3mt@eyQYmF zShzXj##20LJZSG`dIKjJ??;9K2#ST1k%`|R7}OIx$}M%ZR#bV_i4_}mAjce*IyYiE?A3SAuK$fk!t3qZ`PE^D@mBDv;lCSj z_4vb^N55e}I7z>RUzpwccCmvUm-iF+Er2&(&gOR;Uf%BRHeiIq=hepr zeBEUUx%Y=Hn(sEd#m6-siti4$caZ&X1CRE?!G{M`;D^e0Ke$9+&anpbPgjRaSlh$z zneLlrg!wYkuqSPr_-me|NHBIhLa~q{v)3{ Nef`gWel?rT{ulGNYsvrs From 460f1fd5bfd5f7536392743d6e0670b7ea4d5a09 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Thu, 10 Sep 2009 11:29:05 -0700 Subject: [PATCH 237/387] [FIX] unknown compiler flags are preceeded with -D to pass on to the source code --- build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build b/build index 51d4611..ad71874 100755 --- a/build +++ b/build @@ -18,7 +18,7 @@ then # You shouldn't have to change the following. CFLAGS=-O3 - CFLAGS="$CFLAGS TMP_FILES_ARE_DT_UNKNOWN" # workaround bug on centos/SF servers + CFLAGS="$CFLAGS -DTMP_FILES_ARE_DT_UNKNOWN" # workaround bug on centos/SF servers WARN="-Wall -Wno-pointer-to-int-cast -Wno-parentheses" SHARED=-shared SHARED_NAME=libohcount.so From 6568b9ed8701dedc4f7972b2c583cf90c93f32e7 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Fri, 11 Sep 2009 15:14:41 -0700 Subject: [PATCH 238/387] OH-13: Refine Jaspersoft gestalt definitions Expand definitions to include any use of Jasper brand names in code. I had to "enhance" the KeywordRule class. Previously, this rule required a specific language as a parameter. You can now use the rule with a +nil+ language, and it will match any language. --- ruby/gestalt.rb | 1 + ruby/gestalt/jasper_definitions.rb | 62 ++++++++++++ ruby/gestalt/java_definitions.rb | 15 --- ruby/gestalt/rules/keyword_rule.rb | 13 ++- ruby/gestalt/rules/logical_rule.rb | 4 + test/unit/ruby/gestalt/definitions_test.rb | 83 --------------- test/unit/ruby/gestalt/gestalt_test.rb | 1 + test/unit/ruby/gestalt/jasper_definitions_test.rb | 117 ++++++++++++++++++++++ test/unit/ruby/gestalt/keyword_rule_test.rb | 28 +++++- 9 files changed, 220 insertions(+), 104 deletions(-) create mode 100644 ruby/gestalt/jasper_definitions.rb create mode 100644 test/unit/ruby/gestalt/jasper_definitions_test.rb diff --git a/ruby/gestalt.rb b/ruby/gestalt.rb index d437ace..31f0457 100644 --- a/ruby/gestalt.rb +++ b/ruby/gestalt.rb @@ -12,6 +12,7 @@ require "gestalt/definitions" require "gestalt/dot_net_definitions" require "gestalt/java_definitions" +require "gestalt/jasper_definitions" require "gestalt/gestalt_engine" require "gestalt/gestalt_facts" diff --git a/ruby/gestalt/jasper_definitions.rb b/ruby/gestalt/jasper_definitions.rb new file mode 100644 index 0000000..70609f2 --- /dev/null +++ b/ruby/gestalt/jasper_definitions.rb @@ -0,0 +1,62 @@ +module Ohcount + module Gestalt + + define_platform 'jaspersoft' do + _or do + gestalt(:platform, 'jaspersoft_keyword') + gestalt(:platform, 'jasper_reports') + gestalt(:platform, 'jasper_server') + gestalt(:platform, 'jasper_ireport') + gestalt(:platform, 'jasper_intelligence') + end + end + + define_platform 'jaspersoft_keyword' do + keywords /jaspersoft/i + end + + define_platform 'jasper_reports' do + _or do + gestalt(:platform, 'jasper_reports_keyword') + gestalt(:platform, 'jasper_reports_java') + end + end + + define_platform 'jasper_reports_keyword' do + keywords /jasper[ _-]?reports?/i + end + + define_platform 'jasper_reports_java' do + _or do + maven_dependency /jasperreports/ + java_keywords '\bnet\.sf\.jasperreports\b' + end + end + + define_platform 'jasper_server' do + _or do + gestalt(:platform, 'jasper_server_keyword') + gestalt(:platform, 'jasper_server_java') + end + end + + define_platform 'jasper_server_keyword' do + keywords /jasper[ _-]?server/i + end + + define_platform 'jasper_server_java' do + java_keywords '\bcom\.jaspersoft\.jasperserver\b' + end + + define_platform 'jasper_intelligence' do + java_keywords '\bcom\.jaspersoft\.ji' + end + + define_platform 'jasper_ireport' do + _and do + keywords /jasper/i + keywords /ireport/i + end + end + end +end diff --git a/ruby/gestalt/java_definitions.rb b/ruby/gestalt/java_definitions.rb index 3696f50..508d14f 100644 --- a/ruby/gestalt/java_definitions.rb +++ b/ruby/gestalt/java_definitions.rb @@ -268,20 +268,5 @@ module Gestalt end end - ############################ Jasper ################################ - - define_platform 'jasper_jr' do - maven_dependency /jasperreports/ - java_keywords '\bnet\.sf\.jasperreports\b' - end - - define_platform 'jasper_jsce' do - java_keywords '\bcom\.jaspersoft\.jasperserver\b' - end - - define_platform 'jasper_ji' do - java_keywords '\bcom\.jaspersoft\.ji' - end - end end diff --git a/ruby/gestalt/rules/keyword_rule.rb b/ruby/gestalt/rules/keyword_rule.rb index eab56cd..ef0fb7d 100644 --- a/ruby/gestalt/rules/keyword_rule.rb +++ b/ruby/gestalt/rules/keyword_rule.rb @@ -20,10 +20,15 @@ def initialize(language, *args) end def process_source_file(source_file) - return unless source_file.language_breakdown(language) - - code = source_file.language_breakdown(language).code - @count += code.scan(regexp).size + if language + return unless source_file.language_breakdown(language) + @count += source_file.language_breakdown(language).code.scan(regexp).size + else + # All languages + source_file.language_breakdowns.each do |lb| + @count += lb.code.to_s.scan(regexp).size + end + end end def regexp diff --git a/ruby/gestalt/rules/logical_rule.rb b/ruby/gestalt/rules/logical_rule.rb index 33f6dae..d62b838 100644 --- a/ruby/gestalt/rules/logical_rule.rb +++ b/ruby/gestalt/rules/logical_rule.rb @@ -65,6 +65,10 @@ def filenames(*args) new_rule FilenameRule, *args end + def keywords(*args) + new_rule KeywordRule, *([nil] << args) + end + def c_keywords(*args) new_rule CKeywordRule, *args end diff --git a/test/unit/ruby/gestalt/definitions_test.rb b/test/unit/ruby/gestalt/definitions_test.rb index 47f40f9..568b357 100644 --- a/test/unit/ruby/gestalt/definitions_test.rb +++ b/test/unit/ruby/gestalt/definitions_test.rb @@ -463,89 +463,6 @@ def test_native_code assert_equal expected_gestalts.sort, c.gestalts.sort end - def test_jasper_jr - make = SourceFile.new("foo.java", :contents => <<-INLINE_JAVA - public class Employee implements Serializable { - private net.sf.jasperreports.report myReport; - } - INLINE_JAVA - ) - expected_gestalts = [ - Base.new(:platform, 'jasper_jr'), - Base.new(:platform, 'Java'), - ] - assert_equal expected_gestalts.sort, make.gestalts.sort - end - - def test_jasper_jr_pom - make = SourceFile.new("pom.xml", :contents => <<-INLINE_POM - - dzrealms - HelloWorld - 1.0 - - - jgoodies - plastic - 1.2.0 - - - log4j - log4j - 1.2.8 - - - jasperreports - jasperreports - 2.0.5 - - - - src/main/java - src/test/java - - - **/*Test.java - - - - - INLINE_POM - ) - expected_gestalts = [ - Base.new(:platform, 'jasper_jr'), - ] - assert_equal expected_gestalts.sort, make.gestalts.sort - end - - def test_jasper_jsce - make = SourceFile.new("foo.java", :contents => <<-INLINE_JAVA - public class Employee implements Serializable { - private com.jaspersoft.jasperserver; - } - INLINE_JAVA - ) - expected_gestalts = [ - Base.new(:platform, 'Java'), - Base.new(:platform, 'jasper_jsce') - ] - assert_equal expected_gestalts.sort, make.gestalts.sort - end - - def test_jasper_ji - make = SourceFile.new("foo.java", :contents => <<-INLINE_JAVA - public class Employee implements Serializable { - private com.jaspersoft.ji; - } - INLINE_JAVA - ) - expected_gestalts = [ - Base.new(:platform, 'Java'), - Base.new(:platform, 'jasper_ji') - ] - assert_equal expected_gestalts.sort, make.gestalts.sort - end - def test_flash as = SourceFile.new("sample.as", :contents => 'greet.text = "Hello, world";') expected_gestalts = [ Base.new(:platform, "flash") ] diff --git a/test/unit/ruby/gestalt/gestalt_test.rb b/test/unit/ruby/gestalt/gestalt_test.rb index dbf7ce0..ee4f066 100644 --- a/test/unit/ruby/gestalt/gestalt_test.rb +++ b/test/unit/ruby/gestalt/gestalt_test.rb @@ -7,3 +7,4 @@ require File.dirname(__FILE__) + '/definitions_test' require File.dirname(__FILE__) + '/java_definitions_test' require File.dirname(__FILE__) + '/dot_net_definitions_test' +require File.dirname(__FILE__) + '/jasper_definitions_test' diff --git a/test/unit/ruby/gestalt/jasper_definitions_test.rb b/test/unit/ruby/gestalt/jasper_definitions_test.rb new file mode 100644 index 0000000..8bc5315 --- /dev/null +++ b/test/unit/ruby/gestalt/jasper_definitions_test.rb @@ -0,0 +1,117 @@ +require 'test/unit' +require File.dirname(__FILE__) + '/../test_helper.rb' + +include Ohcount +include Ohcount::Gestalt + +class DefinitionsTest < Ohcount::Test + + def test_jasper_reports_java + java = SourceFile.new("foo.java", :contents => <<-INLINE_JAVA + public class Employee implements Serializable { + private net.sf.jasperreports.report myReport; + } + INLINE_JAVA + ) + assert platform_names(java.gestalts).include?('jaspersoft') + assert platform_names(java.gestalts).include?('jasper_reports') + assert platform_names(java.gestalts).include?('jasper_reports_java') + end + + def test_jasper_reports_via_maven + java = SourceFile.new("pom.xml", :contents => <<-INLINE_POM + + dzrealms + HelloWorld + 1.0 + + + jasperreports + jasperreports + 2.0.5 + + + + INLINE_POM + ) + assert platform_names(java.gestalts).include?('jaspersoft') + assert platform_names(java.gestalts).include?('jasper_reports') + assert platform_names(java.gestalts).include?('jasper_reports_java') + end + + def test_jasper_server_java + java = SourceFile.new("foo.java", :contents => <<-INLINE_JAVA + public class Employee implements Serializable { + private com.jaspersoft.jasperserver; + } + INLINE_JAVA + ) + assert platform_names(java.gestalts).include?('jaspersoft') + assert platform_names(java.gestalts).include?('jasper_server') + assert platform_names(java.gestalts).include?('jasper_server_java') + end + + def test_jasper_intelligence + java = SourceFile.new("foo.java", :contents => <<-INLINE_JAVA + public class Employee implements Serializable { + private com.jaspersoft.ji; + } + INLINE_JAVA + ) + assert platform_names(java.gestalts).include?('jaspersoft') + assert platform_names(java.gestalts).include?('jasper_intelligence') + end + + def test_jasper_server + expected = ['Scripting', 'Ruby', 'jaspersoft', 'jasper_server', 'jasper_server_keyword'] + + rb = SourceFile.new('jasper.rb', :contents => 'def jasper_server; nil ; end') + assert_platforms(expected, rb.gestalts) + + rb = SourceFile.new('jasper.rb', :contents => 'def jasperserver; nil ; end') + assert_platforms(expected, rb.gestalts) + + rb = SourceFile.new('jasper.rb', :contents => 'js = JasperServer.new()') + assert_platforms(expected, rb.gestalts) + + rb = SourceFile.new('jasper.rb', :contents => 'jasper-server') + assert_platforms(expected, rb.gestalts) + end + + def test_jasper_reports + expected = ['Scripting', 'Ruby', 'jaspersoft', 'jasper_reports', 'jasper_reports_keyword'] + + rb = SourceFile.new('jasper.rb', :contents => 'def jasper_reports; nil ; end') + assert_platforms(expected, rb.gestalts) + + rb = SourceFile.new('jasper.rb', :contents => 'def jasperreports; nil ; end') + assert_platforms(expected, rb.gestalts) + + rb = SourceFile.new('jasper.rb', :contents => 'def JasperReport; nil ; end') + assert_platforms(expected, rb.gestalts) + + rb = SourceFile.new('jasper.rb', :contents => 'jasper-report') + assert_platforms(expected, rb.gestalts) + end + + def test_jasper_ireport + rb = SourceFile.new('jasper.rb', :contents => 'ireport = nil') + assert !platform_names(rb.gestalts).include?('jasper_ireport') + + rb = SourceFile.new('jasper.rb', :contents => 'jasper = nil') + assert !platform_names(rb.gestalts).include?('jasper_ireport') + + rb = SourceFile.new('jasper.rb', :contents => 'jasper_ireport = nil') + assert platform_names(rb.gestalts).include?('jasper_ireport') + end + + protected + + def assert_platforms(expected_names, actual) + assert_equal(expected_names.sort, platform_names(actual).sort) + end + + def platform_names(gestalts) + gestalts.map { |g| g.type == :platform && g.name }.compact + end +end diff --git a/test/unit/ruby/gestalt/keyword_rule_test.rb b/test/unit/ruby/gestalt/keyword_rule_test.rb index 4fa1045..dc5098e 100644 --- a/test/unit/ruby/gestalt/keyword_rule_test.rb +++ b/test/unit/ruby/gestalt/keyword_rule_test.rb @@ -4,7 +4,7 @@ class KeywordRuleTest < Test::Unit::TestCase include Ohcount::Gestalt - def test_process_file + def test_process_file_in_same_language r = KeywordRule.new('c', 'WIN32') s = Ohcount::SourceFile.new('header.c', :contents => <<-C_CODE // a comment @@ -13,8 +13,32 @@ def test_process_file #endif C_CODE ) - assert r.process_source_file(s) + r.process_source_file(s) assert_equal 1, r.count end + + def test_process_file_in_other_language + r = KeywordRule.new('java', 'WIN32') + s = Ohcount::SourceFile.new('header.c', :contents => <<-C_CODE + // a comment + #ifdef WIN32 + ..some code.. + #endif + C_CODE + ) + r.process_source_file(s) + assert_equal 0, r.count + end + + def test_process_file_with_any_language + r = KeywordRule.new(nil, 'A', 'B') + s = Ohcount::SourceFile.new('mixed.rhtml', :contents => <<-RHTML + <% some ruby containing A -%> +
B
+ RHTML + ) + r.process_source_file(s) + assert_equal 2, r.count + end end From 67e904ace5077dd664227ff1de7a1268004ad762 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Fri, 11 Sep 2009 15:45:33 -0700 Subject: [PATCH 239/387] [CHANGE] Downcase all platform names --- ruby/gestalt/definitions.rb | 106 ++++++++--------- ruby/gestalt/dot_net_definitions.rb | 52 ++++----- ruby/gestalt/java_definitions.rb | 126 ++++++++++----------- test/unit/ruby/gestalt/definitions_test.rb | 108 +++++++++--------- test/unit/ruby/gestalt/dot_net_definitions_test.rb | 26 ++--- test/unit/ruby/gestalt/jasper_definitions_test.rb | 4 +- test/unit/ruby/gestalt/java_definitions_test.rb | 38 +++---- test/unit/ruby/source_file_list_test.rb | 4 +- 8 files changed, 232 insertions(+), 232 deletions(-) diff --git a/ruby/gestalt/definitions.rb b/ruby/gestalt/definitions.rb index 9c41480..548d745 100644 --- a/ruby/gestalt/definitions.rb +++ b/ruby/gestalt/definitions.rb @@ -13,7 +13,7 @@ module Gestalt # # ##################################################################### - define_platform 'POSIX' do + define_platform 'posix' do # gnu_lib && generic c_headers 'pthread.h', 'xstrtol.h', 'xreadlink.h', 'fatal-signal.h', 'diacrit.h', 'syslog.h', 'sys/stat.h' @@ -21,35 +21,35 @@ module Gestalt language :autoconf end - define_platform 'Win32' do + define_platform 'win32' do c_headers 'windows.h' c_keywords 'WM_PAINT', 'ReleaseDC', 'WndProc', :min => 2 end - define_platform 'VisualBasic' do + define_platform 'visualbasic' do language :visualbasic, :min_percent => 5 end - define_platform 'Ruby' do + define_platform 'ruby' do language :ruby, :min_percent => 15 end - define_platform 'Rails' do + define_platform 'rails' do _and do - gestalt(:platform, 'Ruby') + gestalt(:platform, 'ruby') ruby_keywords("RAILS_ROOT") end end - define_platform 'Java' do + define_platform 'java' do language :java, :min_percent => 15 end - define_platform 'Javascript' do + define_platform 'javascript' do language :javascript, :min_percent => 20 end - define_platform 'JQuery' do + define_platform 'jquery' do filenames 'jquery-\d.\d.\d.min.js$' end @@ -79,7 +79,7 @@ module Gestalt _or do language :actionscript, :min_percent => 1 _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') java_import /^(flash)\..+/ end end @@ -89,17 +89,17 @@ module Gestalt _or do language :mxml, :min_percent => 1 _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') java_import /^(mx)\..+/ end end end - define_platform 'XWindows' do + define_platform 'xwindows' do c_headers 'Xlib.h', 'X11\/xpm.h', 'X11/Xlib.h' end - define_platform 'Mac' do + define_platform 'mac' do # apple events c_keywords 'AppleEvent', 'AEBuildAppleEvent' @@ -107,31 +107,31 @@ module Gestalt filenames '\.plist' end - define_platform 'PHP' do + define_platform 'php' do language :php, :min_percent => 15 end - define_platform 'WxWidgets' do + define_platform 'wxwidgets' do c_headers 'wx/window.h' end - define_platform 'ZendFramework' do + define_platform 'zendframework' do _and do - gestalt(:platform, 'PHP') + gestalt(:platform, 'php') php_keywords('Zend_Controller_Action') end end - define_platform 'Symfony' do + define_platform 'symfony' do _and do - gestalt(:platform, 'PHP') + gestalt(:platform, 'php') php_keywords('sfCore', 'sfConfig') end end - define_platform 'Pear' do + define_platform 'pear' do _and do - gestalt(:platform, 'PHP') + gestalt(:platform, 'php') _or do filenames('\bpackage\.xml(\.tpl)?$') xml_keywords('pear\.php\.net/dtd/package\-2\.0') @@ -139,59 +139,59 @@ module Gestalt end end - define_platform 'Moodle' do + define_platform 'moodle' do _and do - gestalt(:platform, 'PHP') + gestalt(:platform, 'php') php_keywords("moodle") end end - define_platform 'SQL' do + define_platform 'sql' do language :sql end - define_platform 'MySQL' do + define_platform 'mysql' do php_keywords('mysql_connect') end - define_platform 'PostgreSQL' do + define_platform 'postgresql' do php_keywords('pg_connect') end - define_platform 'Python' do + define_platform 'python' do language :python, :min_percent => 15 end - define_platform 'Perl' do + define_platform 'perl' do language :perl, :min_percent => 20 end - define_platform 'Scripting' do - gestalt(:platform, 'Javascript') - gestalt(:platform, 'Perl') - gestalt(:platform, 'PHP') - gestalt(:platform, 'Python') - gestalt(:platform, 'Ruby') + define_platform 'scripting' do + gestalt(:platform, 'javascript') + gestalt(:platform, 'perl') + gestalt(:platform, 'php') + gestalt(:platform, 'python') + gestalt(:platform, 'ruby') end - define_platform 'CakePHP' do + define_platform 'cakephp' do _and do - gestalt(:platform, 'PHP') + gestalt(:platform, 'php') php_keywords('CAKE_CORE_INCLUDE_PATH') end end - define_platform 'KDE' do + define_platform 'kde' do c_headers 'KDEInit.h', 'kdeversion.h' end - define_platform 'GTK' do + define_platform 'gtk' do c_keywords 'gtk_init', 'gtk_main', 'gtk_window_new', 'GtkWidget' end - define_platform 'Drupal' do + define_platform 'drupal' do _and do - gestalt(:platform, 'PHP') + gestalt(:platform, 'php') _or do php_keywords('drupal_set_message') php_keywords('drupal_render') @@ -200,26 +200,26 @@ module Gestalt end end - define_platform 'MSDos' do + define_platform 'msdos' do c_keywords '__MSDOS__', 'MSDOS', :min => 2 end - define_platform 'EclipsePlatform' do + define_platform 'eclipseplatform' do java_import /org\.eclipse\./ end ############################### Tools ############################### - define_tool 'VisualStudio' do + define_tool 'visualstudio' do filenames '\.(sln|vcproj|vsproj|csproj|vbproj|vbp)$' end - define_tool 'Eclipse' do + define_tool 'eclipse' do filenames '\.(project|classpath)$' end - define_tool 'NetBeans' do + define_tool 'netbeans' do filenames '\bnbplatform\b' filenames '\.nbm$' end @@ -250,13 +250,13 @@ module Gestalt make_keywords 'SSE3_ATOM' end - define_platform 'xL_flag' do + define_platform 'xl_flag' do make_keywords '\bxL\b', '\/QxL\b' end define_platform 'atom' do gestalt(:platform, 'sse3_atom_flag') - gestalt(:platform, 'xL_flag') + gestalt(:platform, 'xl_flag') end ########################## COMPILER ################################ @@ -278,7 +278,7 @@ module Gestalt ruby_keywords "Clutter::Actor", "Clutter::Stage", "Clutter::Shader", "Clutter::Cairo" end - define_platform 'moblin' do + define_platform 'moblin_misc' do c_keywords '\"org\.moblin\.', 'MOBLIN_NETBOOK_SYSTEM_TRAY_H', 'org_Moblin_', '\"org\.Moblin\.', "url=\"http://moblin.org\">http://moblin.org" make_keywords "org\.moblin\.", "moblin-netbook" filenames 'moblin-netbook-system-tray.h$' @@ -291,9 +291,9 @@ module Gestalt filenames 'nbtk\/nbtk.h' end - define_platform 'moblin_all' do + define_platform 'moblin' do gestalt(:platform, 'clutter') - gestalt(:platform, 'moblin') + gestalt(:platform, 'moblin_misc') gestalt(:platform, 'nbtk') end @@ -305,7 +305,7 @@ module Gestalt ############################ iPhone ################################# - define_platform 'iPhone' do + define_platform 'iphone' do objective_c_keywords '\bUIApplicationMain', '\bUIWindow', '\bUIView', '\bUIResponder' end @@ -323,13 +323,13 @@ module Gestalt gestalt(:platform, 'hildon') end - define_platform 'MID_combined' do + define_platform 'mid_combined' do gestalt(:platform, 'clutter') gestalt(:platform, 'nbtk') gestalt(:platform, 'moblin') gestalt(:platform, 'maemo') gestalt(:platform, 'android') - gestalt(:platform, 'iPhone') + gestalt(:platform, 'iphone') end diff --git a/ruby/gestalt/dot_net_definitions.rb b/ruby/gestalt/dot_net_definitions.rb index c792e8c..abb6701 100644 --- a/ruby/gestalt/dot_net_definitions.rb +++ b/ruby/gestalt/dot_net_definitions.rb @@ -1,32 +1,32 @@ module Ohcount module Gestalt - define_platform 'Dot_NET' do + define_platform 'dot_net' do language :csharp, :min_percent => 10 end - define_platform 'ASP_NET' do + define_platform 'asp_net' do filenames('\.(aspx|ascx|ashx|asax|axd)$') end - define_platform 'NUnit' do + define_platform 'nunit' do _and do - gestalt(:platform, 'Dot_NET') + gestalt(:platform, 'dot_net') csharp_using /^NUnit\b/ end end - define_platform 'NHibernate' do + define_platform 'nhibernate' do _and do - gestalt(:platform, 'Dot_NET') + gestalt(:platform, 'dot_net') csharp_using /^NHibernate\b/ end end # BizTalk - define_platform 'Dot_NET_BizTalk' do + define_platform 'dot_net_biztalk' do _and do - gestalt(:platform, 'Dot_NET') + gestalt(:platform, 'dot_net') _or do csharp_using /^Microsoft\.Solutions\b/ csharp_using /^Microsoft\.BizTalk\b/ @@ -35,48 +35,48 @@ module Gestalt end # Connected Services Framework - define_platform 'Dot_NET_Csf' do + define_platform 'dot_net_csf' do _and do - gestalt(:platform, 'Dot_NET') + gestalt(:platform, 'dot_net') csharp_using /^Microsoft\.Csf\b/ end end # Microsoft Content Management Server - define_platform 'Dot_NET_CMS' do + define_platform 'dot_net_cms' do _and do - gestalt(:platform, 'Dot_NET') + gestalt(:platform, 'dot_net') csharp_using /^Microsoft\.ContentManagement\b/ end end # Exchange - define_platform 'Dot_NET_Exchange' do + define_platform 'dot_net_exchange' do _and do - gestalt(:platform, 'Dot_NET') + gestalt(:platform, 'dot_net') csharp_using /^Microsoft\.Exchange\b/ end end # Microsoft Operations Manager (Mom) - define_platform 'Dot_NET_Mom' do + define_platform 'dot_net_mom' do _and do - gestalt(:platform, 'Dot_NET') + gestalt(:platform, 'dot_net') csharp_using /^Microsoft\.EnterpriseManagement\.Mom\b/ end end # A general category of software. # Not a particular technology, but it "smells" like middle-tier/enterprise software. - define_platform 'Dot_NET_Enterprise' do + define_platform 'dot_net_enterprise' do _and do - gestalt(:platform, 'Dot_NET') + gestalt(:platform, 'dot_net') _or do - gestalt(:platform, 'Dot_NET_BizTalk') - gestalt(:platform, 'Dot_NET_Exchange') - gestalt(:platform, 'Dot_NET_Cms') - gestalt(:platform, 'Dot_NET_Csf') - gestalt(:platform, 'Dot_NET_Mom') + gestalt(:platform, 'dot_net_biztalk') + gestalt(:platform, 'dot_net_exchange') + gestalt(:platform, 'dot_net_cms') + gestalt(:platform, 'dot_net_csf') + gestalt(:platform, 'dot_net_mom') csharp_using /^System\.Runtime\.Remoting\b/ csharp_using /^System\.DirectoryServices\b/ csharp_using /^System\.ServiceModel\b/ @@ -86,7 +86,7 @@ module Gestalt end end - define_platform 'WPF' do + define_platform 'wpf' do filenames '\.xaml$' end @@ -97,8 +97,8 @@ module Gestalt csproj_import /\bSilverlight\b/ _and do # A combination of ASP.NET with xaml is assumed to mean Silverlight - gestalt(:platform, 'ASP_NET') - gestalt(:platform, 'WPF') + gestalt(:platform, 'asp_net') + gestalt(:platform, 'wpf') end end end diff --git a/ruby/gestalt/java_definitions.rb b/ruby/gestalt/java_definitions.rb index 508d14f..2c31103 100644 --- a/ruby/gestalt/java_definitions.rb +++ b/ruby/gestalt/java_definitions.rb @@ -2,7 +2,7 @@ module Ohcount module Gestalt define_java_jar do - find_filenames /([^\\^\/]*\.(jar|JAR))/, :name_from_match => 1 + find_filenames /([^\\^\/]*\.jar)/i, :name_from_match => 1 end define_java_import do @@ -11,9 +11,9 @@ module Gestalt # Java Application Servers - define_platform 'GlassFish' do + define_platform 'glassfish' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') _or do find_filenames /\b(sun\-web|sun\-ejb\-jar|sun\-application(\-client))\.xml\b/ maven_dependency /^org.glassfish\b/ @@ -21,9 +21,9 @@ module Gestalt end end - define_platform 'JBoss' do + define_platform 'jboss' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') _or do find_filenames /\bjboss(\-app|cmp\-jdbc|\-web|\-build|\-client)\.xml\b/ maven_dependency /^org.jboss\b/ @@ -31,9 +31,9 @@ module Gestalt end end - define_platform 'WebLogic' do + define_platform 'weblogic' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') _or do find_filenames /\bweblogic(\-ejb\-jar|\-ra|\-application|\-cmp\-rdbms\jar)\.xml\b/ maven_plugin /^org\.codehaus\.mojo\b/, /^weblogic\-maven\-plugin\b/ @@ -41,23 +41,23 @@ module Gestalt end end - define_platform 'Jonas' do + define_platform 'jonas' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') find_filenames /\bjonas\-ejb\-jar\.xml\b/ end end - define_platform 'WebSphere' do + define_platform 'websphere' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') find_filenames /\bibm\-(application|web|webservices|webservicesclient)\-.+\.xmi$/ end end - define_platform 'Tomcat' do + define_platform 'tomcat' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') _or do java_import /^org\.apache\.tomcat\b/ maven_dependency /^org\.apache\.tomcat\b/ @@ -65,20 +65,20 @@ module Gestalt end end - define_platform 'AppServer' do + define_platform 'appserver' do _or do - gestalt(:platform, 'GlassFish') - gestalt(:platform, 'JBoss') - gestalt(:platform, 'WebLogic') - gestalt(:platform, 'Tomcat') - gestalt(:platform, 'Jonas') - gestalt(:platform, 'WebSphere') + gestalt(:platform, 'glassfish') + gestalt(:platform, 'jboss') + gestalt(:platform, 'weblogic') + gestalt(:platform, 'tomcat') + gestalt(:platform, 'jonas') + gestalt(:platform, 'websphere') end end - define_platform 'EJB2' do + define_platform 'ejb2' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') _or do find_filenames /(.+\-)ejb\-jar\.xml\b/ java_keywords 'EJBHome', 'EJBRemote', 'SessionBean' @@ -90,9 +90,9 @@ module Gestalt # The gestalt engine iterates over definitions in the order they are defined. # # First, look for the subset of new features that definitely indicate EJB 3.1 - define_platform 'EJB3.1' do + define_platform 'ejb3.1' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') _or do java_keywords '@Schedule', '@Singleton', '@Asynchronous' java_keywords /@EJB\(.*\bmappedName\s*=\s*"java:(global|app|module)\/.+".*\)/ @@ -101,27 +101,27 @@ module Gestalt end end # Next, look for the basic attributes that can mean either EJB 3.0 or 3.1 - define_platform 'EJB3+' do + define_platform 'ejb3+' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') _or do - gestalt(:platform, 'EJB3.1') + gestalt(:platform, 'ejb3.1') java_keywords '@EJB', '@Stateless', '@Statefull', '@Entity', '@Remote', '@Local', '@BusinessMethod' java_import /^javax\.persistence\b/ end end end # Finally, if we found EJB3+ and not EJB 3.1, then you must be using EJB 3.0 only. - define_platform 'EJB3.0' do + define_platform 'ejb3.0' do _and do - gestalt(:platform, 'EJB3+') - _not { gestalt(:platform, 'EJB3.1') } + gestalt(:platform, 'ejb3+') + _not { gestalt(:platform, 'ejb3.1') } end end - define_platform 'Servlet' do + define_platform 'servlet' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') _or do java_import /^javax\.servlet\b/ maven_dependency /^javax\.servlet\b/ @@ -129,9 +129,9 @@ module Gestalt end end - define_platform 'Struts' do + define_platform 'struts' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') _or do filenames('\bstruts(\-config)?\.xml$', '\bstruts\.jar$') java_import /^org\.apache\.struts\b/ @@ -140,9 +140,9 @@ module Gestalt end end - define_platform 'SpringFramework' do + define_platform 'springframework' do _and do - gestalt(:platform,'Java') + gestalt(:platform,'java') _or do filenames('spring\.jar$') java_import /^org\.springframework\b/ @@ -151,9 +151,9 @@ module Gestalt end end - define_platform 'JSF' do + define_platform 'jsf' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') _or do java_import /^javax\.faces\b/ maven_dependency /^javax\.faces\b/ @@ -161,18 +161,18 @@ module Gestalt end end - define_platform 'GoogleWebToolkit' do + define_platform 'googlewebtoolkit' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') java_import /^com\.google\.gwt\b/ end end # Java Persistence Frameworks - define_platform 'Hibernate' do + define_platform 'hibernate' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') _or do filenames '\bhibernate\d\.jar$' java_import /^org\.hibernate\b/ @@ -181,53 +181,53 @@ module Gestalt end end - define_platform 'JPA' do + define_platform 'jpa' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') java_import /^javax\.persistence\b/ end end - define_platform 'TopLink' do + define_platform 'toplink' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') java_import /^oracle\.toplink\b/ end end - define_platform 'Castor' do + define_platform 'castor' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') java_import /^org\.exolab\.castor\b/ end end define_platform 'db4o' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') java_import /^com\.db4o\b/ end end # Java Enterprise Service Buses - define_platform 'OpenESB' do + define_platform 'openesb' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') java_import /^org\.openesb\b/ end end - define_platform 'MuleESB' do + define_platform 'muleesb' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') java_import /^org\.mule\b/ end end - define_platform 'ServiceMIX' do + define_platform 'servicemix' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') _or do java_import /^org\.apache\.servicemix\b/ maven_dependency /^org.apache.servicemix\b/ @@ -235,25 +235,25 @@ module Gestalt end end - define_platform 'JBossESB' do + define_platform 'jbossesb' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') java_import /^org\.jboss\.soa\.esb\b/ end end - define_platform 'OpenESB' do + define_platform 'openesb' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') java_import /^org\.openesb\b/ end end # Other Java Technologies - define_platform 'OpenSSO' do + define_platform 'opensso' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') _or do filenames '\bopensso\.war$' java_import /^com\.sun\.identity\.(authentication|agents)\b/ @@ -261,9 +261,9 @@ module Gestalt end end - define_platform 'Maven' do + define_platform 'maven' do _and do - gestalt(:platform, 'Java') + gestalt(:platform, 'java') find_filenames /\bpom\.xml$/ end end diff --git a/test/unit/ruby/gestalt/definitions_test.rb b/test/unit/ruby/gestalt/definitions_test.rb index 568b357..7d8de42 100644 --- a/test/unit/ruby/gestalt/definitions_test.rb +++ b/test/unit/ruby/gestalt/definitions_test.rb @@ -8,30 +8,30 @@ class DefinitionsTest < Ohcount::Test def test_zend_framework assert_gestalts 'zend_framework', [ - Base.new(:platform,'PHP'), - Base.new(:platform,'ZendFramework'), - Base.new(:platform,'Scripting') + Base.new(:platform,'php'), + Base.new(:platform,'zendframework'), + Base.new(:platform,'scripting') ] end def test_php assert_gestalts 'php', [ - Base.new(:platform,'PHP'), - Base.new(:platform,'Scripting') + Base.new(:platform,'php'), + Base.new(:platform,'scripting') ] end def test_wx_widgets assert_gestalts 'wx_widgets', [ - Base.new(:platform,'WxWidgets'), + Base.new(:platform,'wxwidgets'), Base.new(:platform, 'native_code') ] end def test_eclipse_platform assert_gestalts 'eclipse_platform', [ - Base.new(:platform,'Java'), - Base.new(:platform,'EclipsePlatform'), + Base.new(:platform,'java'), + Base.new(:platform,'eclipseplatform'), Base.new(:java_import,"java.text.SimpleDateFormat"), Base.new(:java_import,"java.util.Map"), Base.new(:java_import,"org.eclipse.core") @@ -46,27 +46,27 @@ def test_win32_not_enough def test_win32_enough assert_gestalts 'win32_enough', [ - Base.new(:platform, 'Win32'), + Base.new(:platform, 'win32'), Base.new(:platform, 'native_code') ] end def test_wpf assert_gestalts 'wpf', [ - Base.new(:platform, 'WPF') + Base.new(:platform, 'wpf') ] end def test_asp_net assert_gestalts 'asp_net', [ - Base.new(:platform, 'ASP_NET') + Base.new(:platform, 'asp_net') ] end def test_ruby_just_enough assert_gestalts 'ruby_just_enough', [ - Base.new(:platform, 'Ruby'), - Base.new(:platform, 'Scripting'), + Base.new(:platform, 'ruby'), + Base.new(:platform, 'scripting'), Base.new(:platform, 'native_code'), ] end @@ -79,38 +79,38 @@ def test_ruby_not_enough def test_cakephp assert_gestalts 'cakephp', [ - Base.new(:platform, 'PHP'), - Base.new(:platform, 'CakePHP'), - Base.new(:platform, 'Scripting'), + Base.new(:platform, 'php'), + Base.new(:platform, 'cakephp'), + Base.new(:platform, 'scripting'), ] end def test_symfony - assert_platform('symfony', :PHP, :Symfony, :Scripting) + assert_platform('symfony', :php, :symfony, :scripting) end def test_pear - assert_platform('pear', :PHP, :Pear, :Scripting) + assert_platform('pear', :php, :pear, :scripting) end def test_moodle - assert_platform('moodle', :PHP, :Moodle, :Scripting) + assert_platform('moodle', :php, :moodle, :scripting) end def test_spring_framework assert_gestalts 'spring_framework', [ - Base.new(:platform, 'Java'), - Base.new(:platform, 'SpringFramework'), + Base.new(:platform, 'java'), + Base.new(:platform, 'springframework'), Base.new(:java_jar, 'spring.jar'), ] end def test_rails - assert_platform('rails', :Ruby, :Rails, :Scripting) + assert_platform('rails', :ruby, :rails, :scripting) end def test_jquery - assert_platform('jquery', :Javascript, :JQuery, :Scripting) + assert_platform('jquery', :javascript, :jquery, :scripting) end def test_dojo @@ -126,51 +126,51 @@ def test_yui end def test_python - assert_platform('python', :Python, :Scripting) + assert_platform('python', :python, :scripting) end def test_mac - assert_platform('mac', :Mac, :native_code) + assert_platform('mac', :mac, :native_code) end def test_plist - assert_platform('plist', :Mac) + assert_platform('plist', :mac) end def test_posix - assert_platform('posix', :POSIX, :native_code) + assert_platform('posix', :posix, :native_code) end def test_x_windows - assert_platform('xwindows', :XWindows, :native_code) + assert_platform('xwindows', :xwindows, :native_code) end def test_kde - assert_platform('kde', :KDE, :native_code) + assert_platform('kde', :kde, :native_code) end def test_msdos - assert_platform('msdos', :MSDos, :native_code) + assert_platform('msdos', :msdos, :native_code) end def test_gtk - assert_platform('gtk', :GTK, :native_code) + assert_platform('gtk', :gtk, :native_code) end def test_drupal - assert_platform('drupal', :PHP, :Drupal, :Scripting) + assert_platform('drupal', :php, :drupal, :scripting) end def test_vs_1 - assert_tool('vs_1', :VisualStudio) + assert_tool('vs_1', :visualstudio) end def test_eclipse - assert_tool('eclipse', :Eclipse) + assert_tool('eclipse', :eclipse) end def test_netbeans - assert_tool('netbeans', :NetBeans) + assert_tool('netbeans', :netbeans) end def test_java_imports_from_java_file @@ -185,7 +185,7 @@ def test_java_imports_from_java_file expected_gestalts = [ Base.new(:java_import, 'com.foo', 2), Base.new(:java_import, 'net.ohloh'), - Base.new(:platform, 'Java'), + Base.new(:platform, 'java'), ] assert_equal expected_gestalts.sort, java.gestalts.sort @@ -247,8 +247,8 @@ def test_moblin_clutter ) expected_gestalts = [ Base.new(:platform, 'clutter'), - Base.new(:platform, 'moblin_all'), - Base.new(:platform, 'MID_combined'), + Base.new(:platform, 'moblin'), + Base.new(:platform, 'mid_combined'), Base.new(:platform, 'native_code') ] @@ -261,9 +261,9 @@ def test_moblin_by_filename INLINE_PERL ) expected_gestalts = [ + Base.new(:platform, 'moblin_misc'), Base.new(:platform, 'moblin'), - Base.new(:platform, 'moblin_all'), - Base.new(:platform, 'MID_combined'), + Base.new(:platform, 'mid_combined'), Base.new(:platform, 'native_code') ] @@ -276,9 +276,9 @@ def test_moblin_by_keyword INLINE_PERL ) expected_gestalts = [ + Base.new(:platform, 'moblin_misc'), Base.new(:platform, 'moblin'), - Base.new(:platform, 'moblin_all'), - Base.new(:platform, 'MID_combined'), + Base.new(:platform, 'mid_combined'), Base.new(:platform, 'native_code') ] @@ -292,8 +292,8 @@ def test_nbtk ) expected_gestalts = [ Base.new(:platform, 'nbtk'), - Base.new(:platform, 'MID_combined'), - Base.new(:platform, 'moblin_all'), + Base.new(:platform, 'mid_combined'), + Base.new(:platform, 'moblin'), Base.new(:platform, 'native_code') ] @@ -310,9 +310,9 @@ def test_android expected_gestalts = [ Base.new(:java_import, 'android.app.Activity'), - Base.new(:platform, 'Java'), + Base.new(:platform, 'java'), Base.new(:platform, 'android'), - Base.new(:platform, 'MID_combined') + Base.new(:platform, 'mid_combined') ] assert_equal expected_gestalts.sort, java.gestalts.sort @@ -334,8 +334,8 @@ def test_iphone ) expected_gestalts = [ - Base.new(:platform, 'iPhone'), - Base.new(:platform, 'MID_combined') + Base.new(:platform, 'iphone'), + Base.new(:platform, 'mid_combined') ] assert_equal expected_gestalts.sort, objective_c.gestalts.sort @@ -350,7 +350,7 @@ def test_hildon Base.new(:platform, 'hildon'), Base.new(:platform, 'maemo'), Base.new(:platform, 'native_code'), - Base.new(:platform, 'MID_combined') + Base.new(:platform, 'mid_combined') ] assert_equal expected_gestalts.sort, c.gestalts.sort @@ -362,7 +362,7 @@ def test_atom_linux INLINE_MAKEFILE ) expected_gestalts = [ - Base.new(:platform, 'xL_flag'), + Base.new(:platform, 'xl_flag'), Base.new(:platform, 'atom') ] assert_equal expected_gestalts.sort, make.gestalts.sort @@ -374,7 +374,7 @@ def test_atom_windows INLINE_MAKEFILE ) expected_gestalts = [ - Base.new(:platform, 'xL_flag'), + Base.new(:platform, 'xl_flag'), Base.new(:platform, 'atom') ] assert_equal expected_gestalts.sort, make.gestalts.sort @@ -419,8 +419,8 @@ def test_opensso INLINE_JAVA ) expected_gestalts = [ - Base.new(:platform, 'Java'), - Base.new(:platform, 'OpenSSO'), + Base.new(:platform, 'java'), + Base.new(:platform, 'opensso'), Base.new(:java_import, 'com.sun.identity') ] @@ -435,7 +435,7 @@ def test_windows_ce ) expected_gestalts = [ Base.new(:platform, 'windows_ce_incomplete'), - Base.new(:platform, 'Dot_NET'), + Base.new(:platform, 'dot_net'), ] assert_equal expected_gestalts.sort, csharp.gestalts.sort diff --git a/test/unit/ruby/gestalt/dot_net_definitions_test.rb b/test/unit/ruby/gestalt/dot_net_definitions_test.rb index bac0dff..ac1e630 100644 --- a/test/unit/ruby/gestalt/dot_net_definitions_test.rb +++ b/test/unit/ruby/gestalt/dot_net_definitions_test.rb @@ -11,8 +11,8 @@ def test_nunit CONTENTS ) assert_equal [ - Gestalt::Base.new(:platform, 'Dot_NET'), - Gestalt::Base.new(:platform, 'NUnit') + Gestalt::Base.new(:platform, 'dot_net'), + Gestalt::Base.new(:platform, 'nunit') ], sf.gestalts.sort end @@ -22,8 +22,8 @@ def test_nhibernate CONTENTS ) assert_equal [ - Gestalt::Base.new(:platform, 'Dot_NET'), - Gestalt::Base.new(:platform, 'NHibernate') + Gestalt::Base.new(:platform, 'dot_net'), + Gestalt::Base.new(:platform, 'nhibernate') ], sf.gestalts.sort end @@ -33,8 +33,8 @@ def test_remoting_implies_enterprise CONTENTS ) assert_equal [ - Gestalt::Base.new(:platform, 'Dot_NET'), - Gestalt::Base.new(:platform, 'Dot_NET_Enterprise') + Gestalt::Base.new(:platform, 'dot_net'), + Gestalt::Base.new(:platform, 'dot_net_enterprise') ], sf.gestalts.sort end @@ -44,9 +44,9 @@ def test_biztalk_implies_enterprise CONTENTS ) assert_equal [ - Gestalt::Base.new(:platform, 'Dot_NET'), - Gestalt::Base.new(:platform, 'Dot_NET_BizTalk'), - Gestalt::Base.new(:platform, 'Dot_NET_Enterprise') + Gestalt::Base.new(:platform, 'dot_net'), + Gestalt::Base.new(:platform, 'dot_net_biztalk'), + Gestalt::Base.new(:platform, 'dot_net_enterprise') ], sf.gestalts.sort end @@ -56,8 +56,8 @@ def test_linq_implies_enterprise CONTENTS ) assert_equal [ - Gestalt::Base.new(:platform, 'Dot_NET'), - Gestalt::Base.new(:platform, 'Dot_NET_Enterprise') + Gestalt::Base.new(:platform, 'dot_net'), + Gestalt::Base.new(:platform, 'dot_net_enterprise') ], sf.gestalts.sort end @@ -69,7 +69,7 @@ def test_silverlight_via_asp_keyword CONTENTS ) assert_equal [ - Gestalt::Base.new(:platform, 'ASP_NET'), + Gestalt::Base.new(:platform, 'asp_net'), Gestalt::Base.new(:platform, 'silverlight') ], sf.gestalts.sort end @@ -83,7 +83,7 @@ def test_silverlight_via_csproj_import ) assert_equal([ Gestalt::Base.new(:platform, 'silverlight'), - Gestalt::Base.new(:tool, 'VisualStudio') + Gestalt::Base.new(:tool, 'visualstudio') ], sf.gestalts.sort) end end diff --git a/test/unit/ruby/gestalt/jasper_definitions_test.rb b/test/unit/ruby/gestalt/jasper_definitions_test.rb index 8bc5315..8eef510 100644 --- a/test/unit/ruby/gestalt/jasper_definitions_test.rb +++ b/test/unit/ruby/gestalt/jasper_definitions_test.rb @@ -63,7 +63,7 @@ def test_jasper_intelligence end def test_jasper_server - expected = ['Scripting', 'Ruby', 'jaspersoft', 'jasper_server', 'jasper_server_keyword'] + expected = ['scripting', 'ruby', 'jaspersoft', 'jasper_server', 'jasper_server_keyword'] rb = SourceFile.new('jasper.rb', :contents => 'def jasper_server; nil ; end') assert_platforms(expected, rb.gestalts) @@ -79,7 +79,7 @@ def test_jasper_server end def test_jasper_reports - expected = ['Scripting', 'Ruby', 'jaspersoft', 'jasper_reports', 'jasper_reports_keyword'] + expected = ['scripting', 'ruby', 'jaspersoft', 'jasper_reports', 'jasper_reports_keyword'] rb = SourceFile.new('jasper.rb', :contents => 'def jasper_reports; nil ; end') assert_platforms(expected, rb.gestalts) diff --git a/test/unit/ruby/gestalt/java_definitions_test.rb b/test/unit/ruby/gestalt/java_definitions_test.rb index e70d9de..f3a3bb1 100644 --- a/test/unit/ruby/gestalt/java_definitions_test.rb +++ b/test/unit/ruby/gestalt/java_definitions_test.rb @@ -6,26 +6,26 @@ class JavaDefinitionsTest < Ohcount::Test def test_weblogic_via_maven assert_gestalts 'weblogic_maven', [ - Base.new(:platform, 'AppServer'), - Base.new(:platform, 'Java'), - Base.new(:platform, 'Maven'), - Base.new(:platform, 'WebLogic') + Base.new(:platform, 'appserver'), + Base.new(:platform, 'java'), + Base.new(:platform, 'maven'), + Base.new(:platform, 'weblogic') ] end def test_weblogic_via_descriptor assert_gestalts 'weblogic_descriptor', [ - Base.new(:platform, 'AppServer'), - Base.new(:platform, 'Java'), - Base.new(:platform, 'WebLogic') + Base.new(:platform, 'appserver'), + Base.new(:platform, 'java'), + Base.new(:platform, 'weblogic') ] end def test_webshpere_via_descriptor assert_gestalts 'websphere', [ - Base.new(:platform, 'AppServer'), - Base.new(:platform, 'Java'), - Base.new(:platform, 'WebSphere') + Base.new(:platform, 'appserver'), + Base.new(:platform, 'java'), + Base.new(:platform, 'websphere') ] end @@ -36,9 +36,9 @@ def test_ejb30_by_default JAVA ) assert_equal [ - Base.new(:platform, 'Java'), - Base.new(:platform, 'EJB3+'), - Base.new(:platform, 'EJB3.0') + Base.new(:platform, 'java'), + Base.new(:platform, 'ejb3+'), + Base.new(:platform, 'ejb3.0') ].sort, sf.gestalts.sort end @@ -52,9 +52,9 @@ def test_ejb31_through_annotation JAVA ) assert_equal [ - Base.new(:platform, 'Java'), - Base.new(:platform, 'EJB3+'), - Base.new(:platform, 'EJB3.1') + Base.new(:platform, 'java'), + Base.new(:platform, 'ejb3+'), + Base.new(:platform, 'ejb3.1') ].sort, sf.gestalts.sort end @@ -66,9 +66,9 @@ def test_ejb31_through_global_jndi JAVA ) assert_equal [ - Base.new(:platform, 'Java'), - Base.new(:platform, 'EJB3+'), - Base.new(:platform, 'EJB3.1') + Base.new(:platform, 'java'), + Base.new(:platform, 'ejb3+'), + Base.new(:platform, 'ejb3.1') ].sort, sf.gestalts.sort end diff --git a/test/unit/ruby/source_file_list_test.rb b/test/unit/ruby/source_file_list_test.rb index 51412d9..90d8ba6 100644 --- a/test/unit/ruby/source_file_list_test.rb +++ b/test/unit/ruby/source_file_list_test.rb @@ -9,8 +9,8 @@ def test_source_file_list_supports_analyze assert list.size > 0 # assume: the paths variable points to the directory containing this and other simple ruby test files - ruby = Ohcount::Gestalt::Base.new(:platform, 'Ruby') - scripting = Ohcount::Gestalt::Base.new(:platform, 'Scripting') + ruby = Ohcount::Gestalt::Base.new(:platform, 'ruby') + scripting = Ohcount::Gestalt::Base.new(:platform, 'scripting') list.analyze(:gestalt) # this should work assert list.gestalts.include?(ruby) From 86d178649b646d21fd9dcf80642e521240ad97b4 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Wed, 16 Sep 2009 14:30:36 -0700 Subject: [PATCH 240/387] [NEW] Add .ml4 to the list of OCaml extensions --- src/hash/extensions.gperf | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index eba9a8f..fcadae6 100644 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -97,6 +97,7 @@ m4a, BINARY mf, LANG_METAFONT mk, LANG_MAKE ml, LANG_OCAML +ml4, LANG_OCAML mli, LANG_OCAML mm, LANG_OBJECTIVE_C mov, BINARY From c57b2b696f543a47d44af7b18fc994f92cfe3109 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 22 Sep 2009 16:06:47 -0700 Subject: [PATCH 241/387] [CHANGE] Remove java_jar, java_import We aren't using these results, and they generate tons of data. Can restore later if we need them. --- ruby/gestalt/definition.rb | 1 - ruby/gestalt/jasper_definitions.rb | 2 +- ruby/gestalt/java_definitions.rb | 8 --- ruby/gestalt/rules/find_java_imports_rule.rb | 54 -------------------- ruby/gestalt/rules/logical_rule.rb | 4 -- test/unit/ruby/gestalt/definitions_test.rb | 58 ++++------------------ .../ruby/gestalt/find_java_imports_rule_test.rb | 32 ------------ 7 files changed, 10 insertions(+), 149 deletions(-) delete mode 100644 ruby/gestalt/rules/find_java_imports_rule.rb delete mode 100644 test/unit/ruby/gestalt/find_java_imports_rule_test.rb diff --git a/ruby/gestalt/definition.rb b/ruby/gestalt/definition.rb index 9d9419a..b565fe1 100644 --- a/ruby/gestalt/definition.rb +++ b/ruby/gestalt/definition.rb @@ -13,7 +13,6 @@ require 'gestalt/rules/gestalt_rule' require 'gestalt/rules/java_import_rule' require 'gestalt/rules/csharp_using_rule' -require 'gestalt/rules/find_java_imports_rule' require 'gestalt/rules/maven_parser' require 'gestalt/rules/maven_rule' require 'gestalt/rules/csproj_parser' diff --git a/ruby/gestalt/jasper_definitions.rb b/ruby/gestalt/jasper_definitions.rb index 70609f2..fd6ba52 100644 --- a/ruby/gestalt/jasper_definitions.rb +++ b/ruby/gestalt/jasper_definitions.rb @@ -29,7 +29,7 @@ module Gestalt define_platform 'jasper_reports_java' do _or do maven_dependency /jasperreports/ - java_keywords '\bnet\.sf\.jasperreports\b' + java_keywords '\bnet\.sf\.jasperreports\b' end end diff --git a/ruby/gestalt/java_definitions.rb b/ruby/gestalt/java_definitions.rb index 2c31103..4a82a2d 100644 --- a/ruby/gestalt/java_definitions.rb +++ b/ruby/gestalt/java_definitions.rb @@ -1,14 +1,6 @@ module Ohcount module Gestalt - define_java_jar do - find_filenames /([^\\^\/]*\.jar)/i, :name_from_match => 1 - end - - define_java_import do - find_java_imports - end - # Java Application Servers define_platform 'glassfish' do diff --git a/ruby/gestalt/rules/find_java_imports_rule.rb b/ruby/gestalt/rules/find_java_imports_rule.rb deleted file mode 100644 index 3625706..0000000 --- a/ruby/gestalt/rules/find_java_imports_rule.rb +++ /dev/null @@ -1,54 +0,0 @@ -module Ohcount - module Gestalt - - # Will yield one trigger per java import - each with the name of the imported - # namespace. Example java source file: - # - # import com.foo.bar; - # - # will yield a trigger with name='com.foo.bar' - class FindJavaImportsRule < FileRule - attr_reader :keywords, :language - - def initialize(*args) - @trigger_hash = {} - super(*args) - end - - def process_source_file(source_file) - return unless source_file.language_breakdown('java') - - java_code = source_file.language_breakdown('java').code - java_code.scan(import_regexp).each do |matches| - name = matches[0] - @trigger_hash[name] = @trigger_hash[name].to_i + 1 - end - end - - # implement deep clone - def clone - self.class.new(:min => @min_count) - end - - def triggers(gestalt_engine) - triggers = [] - @trigger_hash.each do |k,v| - triggers << Trigger.new(:name => FindJavaImportsRule.truncate_name(k, 3), :count => v) - end - triggers - end - - def import_regexp - /^\s*import\s+([a-zA-Z][\w\.\*\-]*)\b/ - end - - # Truncates the java import namespace to a maximum depth. - # For instance, - # truncate_name("com.sun.identity.authentication", 3) => "com.sun.identity" - def self.truncate_name(s, max_depth) - s.to_s.split('.')[0, max_depth].join('.') - end - - end - end -end diff --git a/ruby/gestalt/rules/logical_rule.rb b/ruby/gestalt/rules/logical_rule.rb index d62b838..32d1856 100644 --- a/ruby/gestalt/rules/logical_rule.rb +++ b/ruby/gestalt/rules/logical_rule.rb @@ -85,10 +85,6 @@ def find_filenames(*args) new_rule FindFilenamesRule, *args end - def find_java_imports(*args) - new_rule FindJavaImportsRule, *args - end - def method_missing(m,*args, &block) if m.to_s =~ /^(.*)_keywords$/ language = $1 diff --git a/test/unit/ruby/gestalt/definitions_test.rb b/test/unit/ruby/gestalt/definitions_test.rb index 7d8de42..0f5a240 100644 --- a/test/unit/ruby/gestalt/definitions_test.rb +++ b/test/unit/ruby/gestalt/definitions_test.rb @@ -31,10 +31,7 @@ def test_wx_widgets def test_eclipse_platform assert_gestalts 'eclipse_platform', [ Base.new(:platform,'java'), - Base.new(:platform,'eclipseplatform'), - Base.new(:java_import,"java.text.SimpleDateFormat"), - Base.new(:java_import,"java.util.Map"), - Base.new(:java_import,"org.eclipse.core") + Base.new(:platform,'eclipseplatform') ] end @@ -100,8 +97,7 @@ def test_moodle def test_spring_framework assert_gestalts 'spring_framework', [ Base.new(:platform, 'java'), - Base.new(:platform, 'springframework'), - Base.new(:java_jar, 'spring.jar'), + Base.new(:platform, 'springframework') ] end @@ -173,24 +169,6 @@ def test_netbeans assert_tool('netbeans', :netbeans) end - def test_java_imports_from_java_file - java = SourceFile.new("foo.java", :contents => <<-INLINE_C - import com.foo; - import net.ohloh; - import com.foo; - // import dont.import.this; - INLINE_C - ) - - expected_gestalts = [ - Base.new(:java_import, 'com.foo', 2), - Base.new(:java_import, 'net.ohloh'), - Base.new(:platform, 'java'), - ] - - assert_equal expected_gestalts.sort, java.gestalts.sort - end - def test_arm asm = SourceFile.new("foo.S", :contents => <<-INLINE_ASM orrs 3, eax @@ -230,16 +208,6 @@ def test_arm_neon assert_equal expected_gestalts.sort, asm.gestalts.sort end - def test_imports_from_java_file - jar = SourceFile.new("foo/foo.jar", :contents => '') - - expected_gestalts = [ - Base.new(:java_jar, 'foo.jar'), - ] - - assert_equal expected_gestalts.sort, jar.gestalts.sort - end - def test_moblin_clutter c = SourceFile.new("foo.c", :contents => <<-INLINE_C clutter_actor_queue_redraw (CLUTTER_ACTOR(label)); @@ -308,14 +276,10 @@ def test_android INLINE_C ) - expected_gestalts = [ - Base.new(:java_import, 'android.app.Activity'), - Base.new(:platform, 'java'), - Base.new(:platform, 'android'), - Base.new(:platform, 'mid_combined') - ] - - assert_equal expected_gestalts.sort, java.gestalts.sort + names = java.gestalts.map { |g| g.name if g.type == :platform }.compact + assert names.include?('java') + assert names.include?('android') + assert names.include?('mid_combined') end def test_iphone @@ -418,13 +382,9 @@ def test_opensso import com.sun.identity.authentication; INLINE_JAVA ) - expected_gestalts = [ - Base.new(:platform, 'java'), - Base.new(:platform, 'opensso'), - Base.new(:java_import, 'com.sun.identity') - ] - - assert_equal expected_gestalts.sort, java.gestalts.sort + platforms = java.gestalts.map { |g| g.name if g.type == :platform }.compact + assert platforms.include?('java') + assert platforms.include?('opensso') end def test_windows_ce diff --git a/test/unit/ruby/gestalt/find_java_imports_rule_test.rb b/test/unit/ruby/gestalt/find_java_imports_rule_test.rb deleted file mode 100644 index 932d787..0000000 --- a/test/unit/ruby/gestalt/find_java_imports_rule_test.rb +++ /dev/null @@ -1,32 +0,0 @@ -require File.dirname(__FILE__) + '/../../test_helper' - -class FindJavaImportsRuleTest < Test::Unit::TestCase - include Ohcount::Gestalt - - def test_truncate_name - assert_equal "", FindJavaImportsRule.truncate_name(nil, 3) - assert_equal "", FindJavaImportsRule.truncate_name("", 3) - assert_equal "", FindJavaImportsRule.truncate_name("net.ohloh.ohcount.test", 0) - assert_equal "net", FindJavaImportsRule.truncate_name("net.ohloh.ohcount.test", 1) - assert_equal "net.ohloh", FindJavaImportsRule.truncate_name("net.ohloh.ohcount.test", 2) - assert_equal "net.ohloh.ohcount", FindJavaImportsRule.truncate_name("net.ohloh.ohcount.test", 3) - assert_equal "net.ohloh.ohcount.test", FindJavaImportsRule.truncate_name("net.ohloh.ohcount.test", 4) - assert_equal "net.ohloh.ohcount.test", FindJavaImportsRule.truncate_name("net.ohloh.ohcount.test", 5) - end - - def test_arm_from_java_import - java = SourceFile.new("foo.java", :contents => <<-INLINE_C - import org.opengroup.arm40.transaction.ArmConstants; - // import dont.import.this; - INLINE_C - ) - - expected_gestalts = [ - Base.new(:java_import, 'org.opengroup.arm40'), - Base.new(:platform, 'Java'), - Base.new(:platform, 'arm'), - ] - - assert_equal expected_gestalts.sort, java.gestalts.sort - end -end From 53961647e903e34f4830fc57cbe5c9eb9fbe286a Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 22 Sep 2009 16:26:42 -0700 Subject: [PATCH 242/387] [CHANGE] Remove unused .NET-related platforms --- ruby/gestalt/dot_net_definitions.rb | 84 ++-------------------- test/unit/ruby/gestalt/definitions_test.rb | 12 ---- test/unit/ruby/gestalt/dot_net_definitions_test.rb | 83 ++++++--------------- test/unit/ruby/test_helper.rb | 8 ++- 4 files changed, 33 insertions(+), 154 deletions(-) diff --git a/ruby/gestalt/dot_net_definitions.rb b/ruby/gestalt/dot_net_definitions.rb index abb6701..78d5a1b 100644 --- a/ruby/gestalt/dot_net_definitions.rb +++ b/ruby/gestalt/dot_net_definitions.rb @@ -2,90 +2,18 @@ module Ohcount module Gestalt define_platform 'dot_net' do - language :csharp, :min_percent => 10 + _or do + language :csharp, :min_percent => 10 + gestalt :platform, 'asp_net' + gestalt :platform, 'wpf' + gestalt :platform, 'silverlight' + end end define_platform 'asp_net' do filenames('\.(aspx|ascx|ashx|asax|axd)$') end - define_platform 'nunit' do - _and do - gestalt(:platform, 'dot_net') - csharp_using /^NUnit\b/ - end - end - - define_platform 'nhibernate' do - _and do - gestalt(:platform, 'dot_net') - csharp_using /^NHibernate\b/ - end - end - - # BizTalk - define_platform 'dot_net_biztalk' do - _and do - gestalt(:platform, 'dot_net') - _or do - csharp_using /^Microsoft\.Solutions\b/ - csharp_using /^Microsoft\.BizTalk\b/ - end - end - end - - # Connected Services Framework - define_platform 'dot_net_csf' do - _and do - gestalt(:platform, 'dot_net') - csharp_using /^Microsoft\.Csf\b/ - end - end - - # Microsoft Content Management Server - define_platform 'dot_net_cms' do - _and do - gestalt(:platform, 'dot_net') - csharp_using /^Microsoft\.ContentManagement\b/ - end - end - - # Exchange - define_platform 'dot_net_exchange' do - _and do - gestalt(:platform, 'dot_net') - csharp_using /^Microsoft\.Exchange\b/ - end - end - - # Microsoft Operations Manager (Mom) - define_platform 'dot_net_mom' do - _and do - gestalt(:platform, 'dot_net') - csharp_using /^Microsoft\.EnterpriseManagement\.Mom\b/ - end - end - - # A general category of software. - # Not a particular technology, but it "smells" like middle-tier/enterprise software. - define_platform 'dot_net_enterprise' do - _and do - gestalt(:platform, 'dot_net') - _or do - gestalt(:platform, 'dot_net_biztalk') - gestalt(:platform, 'dot_net_exchange') - gestalt(:platform, 'dot_net_cms') - gestalt(:platform, 'dot_net_csf') - gestalt(:platform, 'dot_net_mom') - csharp_using /^System\.Runtime\.Remoting\b/ - csharp_using /^System\.DirectoryServices\b/ - csharp_using /^System\.ServiceModel\b/ - csharp_using /^System\.(Data\.)?Linq\b/ - csharp_using /^System\.Data\b/ - end - end - end - define_platform 'wpf' do filenames '\.xaml$' end diff --git a/test/unit/ruby/gestalt/definitions_test.rb b/test/unit/ruby/gestalt/definitions_test.rb index 0f5a240..ab78748 100644 --- a/test/unit/ruby/gestalt/definitions_test.rb +++ b/test/unit/ruby/gestalt/definitions_test.rb @@ -48,18 +48,6 @@ def test_win32_enough ] end - def test_wpf - assert_gestalts 'wpf', [ - Base.new(:platform, 'wpf') - ] - end - - def test_asp_net - assert_gestalts 'asp_net', [ - Base.new(:platform, 'asp_net') - ] - end - def test_ruby_just_enough assert_gestalts 'ruby_just_enough', [ Base.new(:platform, 'ruby'), diff --git a/test/unit/ruby/gestalt/dot_net_definitions_test.rb b/test/unit/ruby/gestalt/dot_net_definitions_test.rb index ac1e630..c54f955 100644 --- a/test/unit/ruby/gestalt/dot_net_definitions_test.rb +++ b/test/unit/ruby/gestalt/dot_net_definitions_test.rb @@ -3,63 +3,20 @@ include Ohcount include Ohcount::Gestalt -class DotNetDefinitionsTest < Test::Unit::TestCase +class DotNetDefinitionsTest < Ohcount::Test - def test_nunit - sf = SourceFile.new('foo.cs', :contents => <<-CONTENTS -using NUnit.Framework; -CONTENTS - ) - assert_equal [ - Gestalt::Base.new(:platform, 'dot_net'), - Gestalt::Base.new(:platform, 'nunit') - ], sf.gestalts.sort - end + def test_wpf + platforms = get_gestalts('wpf').map { |g| g.name if g.type == :platform }.compact + assert platforms.include?("dot_net") + assert platforms.include?("wpf") + end - def test_nhibernate - sf = SourceFile.new('foo.cs', :contents => <<-CONTENTS -using NHibernate.Connection.DriverConnectionProvider; -CONTENTS - ) - assert_equal [ - Gestalt::Base.new(:platform, 'dot_net'), - Gestalt::Base.new(:platform, 'nhibernate') - ], sf.gestalts.sort - end + def test_asp_net + platforms = get_gestalts('asp_net').map { |g| g.name if g.type == :platform }.compact + assert platforms.include?("dot_net") + assert platforms.include?("asp_net") + end - def test_remoting_implies_enterprise - sf = SourceFile.new('foo.cs', :contents => <<-CONTENTS -using System.Runtime.Remoting; -CONTENTS - ) - assert_equal [ - Gestalt::Base.new(:platform, 'dot_net'), - Gestalt::Base.new(:platform, 'dot_net_enterprise') - ], sf.gestalts.sort - end - - def test_biztalk_implies_enterprise - sf = SourceFile.new('foo.cs', :contents => <<-CONTENTS -using Microsoft.BizTalk; -CONTENTS - ) - assert_equal [ - Gestalt::Base.new(:platform, 'dot_net'), - Gestalt::Base.new(:platform, 'dot_net_biztalk'), - Gestalt::Base.new(:platform, 'dot_net_enterprise') - ], sf.gestalts.sort - end - - def test_linq_implies_enterprise - sf = SourceFile.new('foo.cs', :contents => <<-CONTENTS -using System.Data.Linq; -CONTENTS - ) - assert_equal [ - Gestalt::Base.new(:platform, 'dot_net'), - Gestalt::Base.new(:platform, 'dot_net_enterprise') - ], sf.gestalts.sort - end def test_silverlight_via_asp_keyword sf = SourceFile.new('foo.aspx', :contents => <<-CONTENTS @@ -68,10 +25,10 @@ def test_silverlight_via_asp_keyword CONTENTS ) - assert_equal [ - Gestalt::Base.new(:platform, 'asp_net'), - Gestalt::Base.new(:platform, 'silverlight') - ], sf.gestalts.sort + platforms = sf.gestalts.map { |g| g.name if g.type == :platform }.compact + assert platforms.include?('dot_net') + assert platforms.include?('asp_net') + assert platforms.include?('silverlight') end def test_silverlight_via_csproj_import @@ -81,9 +38,11 @@ def test_silverlight_via_csproj_import CONTENTS ) - assert_equal([ - Gestalt::Base.new(:platform, 'silverlight'), - Gestalt::Base.new(:tool, 'visualstudio') - ], sf.gestalts.sort) + platforms = sf.gestalts.map { |g| g.name if g.type == :platform }.compact + assert platforms.include?('dot_net') + assert platforms.include?('silverlight') + + tools = sf.gestalts.map { |g| g.name if g.type == :tool }.compact + assert tools.include?('visualstudio') end end diff --git a/test/unit/ruby/test_helper.rb b/test/unit/ruby/test_helper.rb index 93bd79b..a43a4d2 100644 --- a/test/unit/ruby/test_helper.rb +++ b/test/unit/ruby/test_helper.rb @@ -47,11 +47,15 @@ def assert_platform(path, *platforms) end def assert_gestalts(path, expected_gestalts) + assert_equal expected_gestalts.sort, get_gestalts(path) + end + + def get_gestalts(path) sfl = SourceFileList.new(:paths => [test_dir(path)]) assert sfl.size > 0 sfl.analyze(:gestalt) - assert_equal expected_gestalts.sort, sfl.gestalts.sort - end + sfl.gestalts.sort + end def test_dir(d) File.expand_path(File.dirname(__FILE__) + "/../../gestalt_files/#{ d }") From 679e04ab0603b1f17abd93fa1f49ab7e4e80ebc6 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Wed, 30 Sep 2009 10:38:55 -0700 Subject: [PATCH 243/387] [README] add min gcc version --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index df7bc3f..dfea440 100644 --- a/README +++ b/README @@ -69,7 +69,7 @@ On Debian/Ubuntu, install with "sudo apt-get instal doxygen". == Building Ohcount == -You will need ragel 6.3 or higher, bash, pcre, gcc and SWIG to build ohcount. Once you have them, go to the top directory of ohcount and type: +You will need ragel 6.3 or higher, bash, pcre, gcc (version 4.1.2 or greater) and SWIG to build ohcount. Once you have them, go to the top directory of ohcount and type: > bash build or > ./build From a6783afcf61f18e9f1aef3e2655b30af7501c902 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 1 Oct 2009 14:32:16 -0700 Subject: [PATCH 244/387] [FIX] Avoid null dereference in disambiguate_inc() --- src/detector.c | 18 ++++++++++-------- test/detect_files/empty.inc | 0 test/unit/detector_test.h | 1 + 3 files changed, 11 insertions(+), 8 deletions(-) create mode 100644 test/detect_files/empty.inc diff --git a/src/detector.c b/src/detector.c index 4d0e1f4..9b4d8d2 100644 --- a/src/detector.c +++ b/src/detector.c @@ -452,14 +452,16 @@ const char *disambiguate_in(SourceFile *sourcefile) { const char *disambiguate_inc(SourceFile *sourcefile) { char *p = ohcount_sourcefile_get_contents(sourcefile); - char *eof = p + strlen(p); - while (p < eof) { - if (*p == '\0') - return BINARY; - else if (*p == '?' && strncmp(p + 1, "php", 3) == 0) - return LANG_PHP; - p++; - } + if (p) { + char *eof = p + strlen(p); + while (p < eof) { + if (*p == '\0') + return BINARY; + else if (*p == '?' && strncmp(p + 1, "php", 3) == 0) + return LANG_PHP; + p++; + } + } return NULL; } diff --git a/test/detect_files/empty.inc b/test/detect_files/empty.inc new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index cd36b6d..628b6cc 100644 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -77,6 +77,7 @@ void test_detector_detect_polyglot() { ASSERT_DETECT(LANG_IDL_PVWAVE, "foo.pro"); ASSERT_DETECT(LANG_ASSEMBLER, "foo.z80"); ASSERT_DETECT(LANG_PHP, "php.inc"); + ASSERT_NODETECT("empty.inc"); ASSERT_DETECT(LANG_FSHARP, "fs1.fs"); } From c0b28d67f27f6e954c93dabd71d098854896d679 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 1 Oct 2009 15:43:42 -0700 Subject: [PATCH 245/387] [FIX] Null dereference error in disambiguate_in() --- src/detector.c | 3 +++ test/detect_files/empty.in | 0 test/unit/detector_test.h | 4 ++++ 3 files changed, 7 insertions(+) create mode 100644 test/detect_files/empty.in diff --git a/src/detector.c b/src/detector.c index 9b4d8d2..863b379 100644 --- a/src/detector.c +++ b/src/detector.c @@ -437,6 +437,9 @@ const char *disambiguate_in(SourceFile *sourcefile) { buf[length] = '\0'; SourceFile *undecorated = ohcount_sourcefile_new(buf); p = ohcount_sourcefile_get_contents(sourcefile); + if (!p) { + return NULL; + } // The filepath without the '.in' extension does not exist on disk. The // sourcefile->diskpath field must be set incase the detector needs to run // 'file -b' on the file. diff --git a/test/detect_files/empty.in b/test/detect_files/empty.in new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index 628b6cc..a26adaa 100644 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -36,6 +36,9 @@ void test_detector_disambiguate_m() { ASSERT_DETECT(LANG_OCTAVE, "foo_octave.m"); } +void test_detector_disambiguate_in() { + ASSERT_NODETECT("empty.in"); +} void test_detector_disambiguate_pro() { ASSERT_DETECT(LANG_IDL_PVWAVE, "foo.pro"); ASSERT_DETECT(LANG_MAKE, "qmake.pro"); @@ -119,6 +122,7 @@ void test_detector_xml_with_custom_extension() { void all_detector_tests() { test_detector_smalltalk(); test_detector_disambiguate_m(); + test_detector_disambiguate_in(); test_detector_disambiguate_pro(); test_detector_fortran_fixedfree(); test_detector_detect_polyglot(); From 46193a10f40dcd8f0f4dc22e50bf27b8b927e9b2 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Thu, 1 Oct 2009 21:38:19 -0700 Subject: [PATCH 246/387] [NEW] create separate binaries based on distro --- build | 2 +- ruby/print_arch | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100755 ruby/print_arch diff --git a/build b/build index ad71874..238ec6b 100755 --- a/build +++ b/build @@ -114,7 +114,7 @@ run_test_suite() build_ruby_bindings() { - arch=`ruby -rmkmf -e 'print Config::expand(CONFIG["arch"])'` + arch=`ruby/print_arch` echo "Generating Ruby bindings for $arch" sh -c "swig -ruby -o ruby/ohcount_wrap.c ruby/ohcount.i" || exit 1 mkdir -p ruby/$arch diff --git a/ruby/print_arch b/ruby/print_arch new file mode 100755 index 0000000..2a32c26 --- /dev/null +++ b/ruby/print_arch @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +require 'mkmf' + +arch = Config::expand(CONFIG["arch"]) + +distro = if File.exist?("/etc/issue") + # this is "", "CentOS" or "Ubuntu" + `cat /etc/issue`.split.first.downcase +end + +unless ["centos", nil, "ubuntu"].include? distro + STDERR.puts "unhandled /etc/issue result: #{distro}" +end + +# either or _ if distro is non-null +puts [arch, distro].compact.join("_") From f62f995b8caeb4771afbe5c6854e6e110825f1ff Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Wed, 7 Oct 2009 17:35:48 -0700 Subject: [PATCH 247/387] [FIX] load new centos/ubuntu differentiated binaries and clean them properly --- build | 6 ++++-- ruby/ohcount.rb | 5 ++--- ruby/print_arch | 6 +++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/build b/build index 238ec6b..67cb333 100755 --- a/build +++ b/build @@ -40,6 +40,9 @@ fi # C compiler and flags cc="gcc -fPIC -g $CFLAGS $WARN -I$INC_DIR -L$LIB_DIR" +# ARCHITECTURE +arch=`ruby/print_arch` + # Ohcount source files files="src/sourcefile.c \ src/detector.c \ @@ -114,7 +117,6 @@ run_test_suite() build_ruby_bindings() { - arch=`ruby/print_arch` echo "Generating Ruby bindings for $arch" sh -c "swig -ruby -o ruby/ohcount_wrap.c ruby/ohcount.i" || exit 1 mkdir -p ruby/$arch @@ -156,7 +158,7 @@ then rm -f src/hash/*.c rm -f src/$SHARED_NAME rm -f ruby/$RB_SHARED_NAME - rm -rf ruby/`ruby -rmkmf -e 'print Config::expand(CONFIG["arch"])'`/* + rm -rf ruby/$arch/* else echo "Usage: build [all|ohcount|shared|tests|ruby|clean]" fi diff --git a/ruby/ohcount.rb b/ruby/ohcount.rb index c238bc0..27cfc0e 100644 --- a/ruby/ohcount.rb +++ b/ruby/ohcount.rb @@ -7,9 +7,8 @@ begin require 'ohcount.so' rescue LoadError - require 'rbconfig' - include Config - require "#{Config::CONFIG['arch']}/ohcount.so" + print_arch = `#{File.dirname(__FILE__)}/print_arch`.strip + require "#{print_arch}/ohcount.so" end module Ohcount diff --git a/ruby/print_arch b/ruby/print_arch index 2a32c26..48322f4 100755 --- a/ruby/print_arch +++ b/ruby/print_arch @@ -3,9 +3,9 @@ require 'mkmf' arch = Config::expand(CONFIG["arch"]) -distro = if File.exist?("/etc/issue") - # this is "", "CentOS" or "Ubuntu" - `cat /etc/issue`.split.first.downcase +distro = if File.exist?("/etc/issue") + # this is "", "CentOS" or "Ubuntu" + `cat /etc/issue`.split.first.downcase end unless ["centos", nil, "ubuntu"].include? distro From 25275bd800bec458529329989f72b8c20ff261e1 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Wed, 7 Oct 2009 17:46:03 -0700 Subject: [PATCH 248/387] [FIX] remove old file --- ruby/x86_64-linux/ohcount.so | Bin 2680693 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 ruby/x86_64-linux/ohcount.so diff --git a/ruby/x86_64-linux/ohcount.so b/ruby/x86_64-linux/ohcount.so deleted file mode 100755 index 65ee0e2dc2aaa4280b05116da9302907ddd5cc75..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2680693 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�uF#P-@}1-A(d3cwC~)dYjMW8jZj!8h+L#icJ&_z4_$ z$vSEnY}m-!;0L&<=vMGc+-vWD;m+d*7hFpVQuR+}?2M;$+1-E4nUGeJ&Pn zEWsl~le&Nj{UFtid$#~0$$nsBVU3WmQj7vujE%r3_{$v>C_wNVzfj4~n4Ya-oCQ^Z zh@(`CwCd!$vsAOSDsg+Z>MpIyOv_erV+meAWvSBTC`UZyb5VXO%Q$@!%JJ;j=_6Rq zvP>UjuC>>T^xozv=XMuR9p|CK#w2)HwoK2k{pN;sqF{2-aE6TJJRVcWlG9?iBvVJ= z-yzA$5?mlxyFGeQe&Dn}rmA!Zl=qBTmFz0pjdDyxsW)w!$fj~MTGHE!hb=+hfSLV` zTMtq;V=C`P12<(`tZ5uL@eRVxqRW(|D@bIXnc;K zciUBP!#Z*15=IZ~O)&w>GDjz?;RTaGqb5G@+l?FT?QkKY$1@adHR{L|<)>LLFjCg& zg-VWKo+O%9DFBSvmzD)p8Tat{_>ZkOil(I+1A??`aMc#e-vouqZB<$SCcW zG4Fi|wyDUW?0dAbyzswH_(A|Gl*r5M_ZaYTk;zscl%qPDNi-BpthN)p)fp()ghLZ@ zDH2D);(=AoGvM8BF>RsBa7(MX1h6#H|m@yRm#Y%Wb4w%<_ROZz1J@ zEcc8dIm2q6*-GkmXB~0}S}c%UmiYXzWZ8Nvx?W|lf^B}4C2-%G;QEZc1g0YI4u!+j zORz!Ih`f(g$-MXl4HbM1R52^~3N9{8OaR0~%q#~~)xW_cI9rhDJJ8khJOQ5by38Ul z5AJpg8J3tv`nsm*&d$~f%6iC|atNkDj8a`8{t`SKBB823tNMtb!CsUs71@_nJ84xH zuavgi&^RS#j?AnvLGzrbB`%MKLI{W18vb^O6B5qhcvkR>yTF`+9EQT1w^3x!MqXxh zD*P(QO$P<&MOImn=WsD$fFDcNfMO0QMoCC3x=Sg>%O&1q-uhfLr^7UvAJ)24$LAjy zE%?~YWDSm(uotVFu==Q}*=ihU(py+POr%umL)B?m{eg$cURhsZ)0NLbCYFHTG1!rzC6uKR8$49f3Jy7<@9Zw0^dcix!AgKXCIpQ8KH10kS^ig zpbe3P0+-`Vv7*YnhDS>n4|!}weY^5OsH+EdR~`fGF4VAFhkp1g?GCb9Q3f^_nXQEJ(Hh`gc*DZf{ysI6oEoQ&y zYZ7v@U4U%K3~7*l4bt{0{X=A^Xn2uwF62L^mo1GmXa}+&V%Ywq!iQoE^WLYdQb2H> z>dx3=*wBvY+=;+Owv}U6tUD+nFx9Uxnxik$xtT!=s7oZiqcx*Ly>m3}qeD5_ox>h+ zGf>_G{TvH`hkGi-k-!6oVcgBsQ!CUsvp=zJ1f;Bmr&aUNBRTX1Y>H-qut5m1Yit+C zb_KgP-G9|YXR@J@pKF6~wdO9^B$4S+-We^3OB);c<|A7c_W+&Z$93e(Csr+1 zn(nq1RdA(;aPRT}L!J#PckE)Q%0N048g_?}4YC-_ybl_sE5N-P#0{}z8(aVM1=53$ z4#lY4)^Q~e2+~7rM`|*MIZG8ylqJ{)1P$O|%(23OTWR25$g{uZLs`+8%{&VI;CsuC zfx`)9c;P(Iw$S@S3Xa$r)Jgk)(#<1&W{wee(5ABQJJ2C~y} zWZ+$aKmk9qf=61Vm^R$!SCZ~u4s(6tl<~yM4H8d-dvK*pg?Eulqz^kC0OqbjcH$iV z_&YL&-_As9!p^o3Jmgv2dTQ)uQ1+8ElZ>y8S>gM%qcIn0$57=BgvSae>;?(lnwO6L zC~GGTG1x4_01c>5M%OSwJ3<~Tm;1z0MW-LZGl{U|VX4Rtw_y2MEwLf^?|+vDYJ%(V zF9!hNALG^qYZ$D6#RhJ}v%cieYRFq}di*557^1NHaJ3bP1lj}wd^`ZnyMIW0YA`LD;G7v#^)btgM;Ng%&7(JXERPxs+1WmXlM{5t zDg<#x4TQxPsC(la{9`uihC!dSgeHoNHaL`?QxGSP4THo&;y;G3R{*KeI!|CC23to8 zRN}z?0I9SW0<_kcA+)XP=|8H2R5-tf#G*B`Vq0)qOg`*=0l@(C>;*--3iCe;dS3xu zwy*)rlMJNJn5TclXw!AtFnOv*#AGYgZ0Z!}$zjGEqGqVGw|e)~6HOw>rI{zPMA2Ek z6YEM{>(Z)2oDpQ^b}DZV&Y3RpVdw%E03sx+XDJ16T45m{yobt_K%_HQa}6g>}YE#B6J&`8}AmSu>&C1z6^&zB)Jc)PLoq zZiIX1U~)xnCh6SNvGe zh;l-u_d^VX*YO!x@|9TIGfC8drBqYKo1|yk1a`4leHuD|ctEsi?CXFUggCzcmD8E# z4A2u>9Kfr|*ZvSTS@keo#nId2|2?H&a-=A zh$fT5p&%DXE;#nF^Ebd%yJXDobj?&`Bw2pW`erQuk%MLbmMrh`upB_iQjuNA@|GMd zxAd{Z3oMZGYdp}vae_PrrKe}i2@F@>S()`%S)Hj}#ylhaRJ)9#-`N$V$&806{vcA! zDW!|h?F3)JMWTKRM2;T{k=HQx`cN=tI9@^lsSWJDBJx4D$UFhTOj;@vDOGeV=c5%F zbv@RS8{l(!bZ}t`pFVu>rU%2r`992;?VXeZD&tfICCtymeLb(ME@I01pt zS(t}I%_HdzV`yoQ!CSZw`Ei_SXPw4E%Y zR#sor->gJ_X*&s0!tUsb?iEII8S@n%!?}An0!wjFQ-{Z2&R$|)*h;Fn(W|qG>Rh94 zy7hh>@3G$E0gm;Q2eSS1K+#d-fENn5stpC-Nk_pC#js=r_BeKa*=$bNL^JR-nc6y+*T`I6 zqjUMoaW({NAokot90+b?(6x&CtrZApgj(-hz7d{`P{^rs&2Ttzt!FMj4<_I>NiLCT zxR`_WP^1d0vc)3=RXUfqkny3i?F~4S0_0Z324^NCym-#J z3zHQa5F%nDGv?yeo)B0p8Icvf^b2YUN7_pt3S&}w61cv2JOcE9Hy-xda3w0%2~6u0 zro|ODOzWUpvc!SuECh_j#Xxrn(|*%e;|I9&sWHR+;9^{}$21yoxDtiyJYtr%Vm^js z$8O^ggVz*D4BpQXh;|$13iKwUhh+ODi`!GAODK|Efili}?HH$(K!wT71}nY+_%xYa z-V*PE!NUVSSIjha{Y{^D_+j7l88~XJjVqUu{rfq%wih*usy{<(j-{kMHstwc;2vNC zUT4T9vMnxVfu0)YpMj@v+syrwvy@DFTTt`Nz<@gemmqC!F#$Ini8HSAAhFlM4idk? zoiP#TH{?d*H<%?K5+lI`NSq*-NM~HkQ=(`zKN3S__wPZXLdMS%mS4#HpFnZ^wH_#T z3Oi8zfGGng=6sqPiXZUEARiP(U;-$Pl1roj7xS=a+6okdKc#XWD6Ww4eNbe>@)Nr7 zbJ}O8`=)!vk=J;j=z5R?#n+ssR?&=4azpVoa;JPy91kXdVxU|iKOYDv?h;K~fubMw zdOj%5m+^g2bayAn13!~`v#n5vkFgI$*;O@ZM4j|GAjE7V#%1j)BT9SK>hSJ+oJtDaeLhK%oXgHVEJ6(G%x`Kz2y=yeE~sIG;GBc_LdzZA+TNHR2kpv z3Vm%?I8&p-=5~d?agQtfw~vFv>emH_n?B6#3agQY<#UCR&>T4IDVInCSehF|%~o7t zH|NyRSv8NB@qMmPqOK4=mNK~;p^tSz-rT`*`*IH~YkNDeEPPF1x$=YDuq;ISoe!21 z0R&(P$tAK9EX{?Ybt|xR;x^d3ZuFP&eXx|;u=Jx$E-Wi_b@szjY^Sg<)GMhuS8`>Z zXa2Pm_PqjkU@4bN z=9r(ERKe@|EcrK*2j9{rK2<W_Jb__g${Jo+Og%cuV* zU_$-n5^0Z%nI-DAroSA5c@q3FGQL-TIWwdEa~+Fqg8eV>>c6|I{}R>z%{=-eY;r_LuR!`ge2euk+vU|4zW}N_mk9m}i|wXMZtejg7Y9 zV8Gs{rvpdhVg&5&Zpyk4#XlLamn__@0ejZ@wtNiOSN3q^JDLJnMSpuk%mr-x55kTH z8u zvfehzgUXq^Ij9^cQWbTh2sx6F1CfK~L*-jA0V;a|4m@@pjFS06lx_u;1UI8zRGxpi zIVx_-I{tMpEQjd{`R0b@y7N4+99itZvXh8a^xJE>Vc7{eXg*jz0u#VeDCk7?LCLHV zty_WRVs1vgu-x}j3s{_#^#aP|X7ar>aoF6joO`YZmOi^WumnY{qOVrwh9wBs%?Ha$ zFaa#T$|ceb7c)<^ZUvSy+4g!;)=ESQ{~RiHQq~hFlM72%%_jV?I1z9!o76m`;AQ@5 z%6jBT8y!Z#uDdwseEp&?WvxQ-Pe#B+^EPV)eC!;L^)BDpk?$x9WEFL<&27D-fJQ#+ z6+%hq8kI}rWUw^9a0}jA1iXv8QLj_iRB`+q5fF>fMm_EJ8|;5yvS*%cBfymP(w!Ux zq9Q@jwl#u4ijt@0-gt`9e_Af z)|GnrhGl89q^vVXc=g}W)nCRh+IB@A{gH#_(|-gsrv7q?oCKEUCsD68{kg;R=|8`@ z{!YreQcu}7oBn5c_20qOU&b%m_SHQ4BL~f=|0U3v`pYG95?Gp_M7`GZmrbiDWqlR% z92WN2-$_|l;t&M0X|w7753l~)yZX!cMcXdVqd#)ceEN@t#?)Ufk(0pE{G@yG{3+`+ z?ooaAf1$blPRhDc=l^EY|4gs`-Cg}<{Gx4N$)i6~?0ovCpfUBAOXMW5G(U-Yt=XSD zRGx>=D~Ka2yPAJTHp0r*zQ& zPn@!MetNSm*gu_S%f~HCb&(_AozD`kqD!mAT)@V^Ww{e*nm<3#a#Bgd)vzRITq~jyGzs}x@CDpQvv_tz3E$)PfzurGP|3D%J{j0%Bd6~ z$ChP0vdVm@^al<=9b!+_2OR z_rP-dHV!NoJR`6SrU*G;xd6FzK3IAI2*9#RE|D={X|@+%XvJAxEKM76 zhE`yCm>WkgEN?&60v2b>a@WgVSpK2egdY|s0$yyBnhgqG21sW=>+mODmAn098y!Z# ze{^-wISA5uB4Cih{<#R)>50u60e>v>SZ{HmBi|iQ61}2|mvUS04xo|Gde4Cgbln1G z!|}u;D48R~IIUQ3E%%pR>vfayy>mSPe7JEiW{B<{{RaErw=CbEWFx>W%gZ4Lf!pQ? z0@p1R1X^raZiCn4Te5e8nZc`_Tp|yFr5Vf(e6p1#`*Yc}dQ#S{WqfbS+5w1j%d)LL zi1RPmn;!KWPxN@g3tKrj+%#Koxbnr^o^TU#(R`k84m1Z28{`tX8!SzKF?1`Q@F91K zUQg&G<9j{932$(PL3()acZE%d;*%3RP(0Daf#P~hJxq$xRk@+K9%*SlD2fz{?|}g( z#T2kKee{?j|4HUs+%$Tj*f@*h`=GEx8lX5>&++|G{O_~kqvLG|I4d6O>_9M9L?}9M zfk4n=R*Xevnr~KYFS>{S4c!5O1(s%CF?K7nVios|0)f4e-|)CV;MvGI@0kTODs1jq z@y;-hD?G5JgG0HO5@W#9Y%dmX z1&SBBmGnZ<_-G3#`nqdHF?Lohp!nZs#jD5K5O7vZ?dU)-N<=6+?gfFM#jF^GoG$OI z5Z%M|&>axO!P0Ci#%^U+%;#>>J1f4LDG+#OMF}A1TJeoO-SW?hP0)X+SN{&K{xW{i zanI+`AIV!j{dA zIdm>X$N|fhaNT^c^aBupVYyxx zR6i_E1boycH9My}%&ePp{{sDgo@dwYr=qHk^})(`eTvE(-g zifMNX6jNs9hGH5L@O)4_4nF`C@*MsLL{zT|Gw3q_HP?}Gv%+d2Qzlk?3D zMdKh36fbOWptxzeK#_PnHxxG^`^yK#U@!p`SHc~T7Tt}K=`Tia1&R;3oAg4_Nyhg< zk=^MI($jK36#x77=BrX00>;W`|LZ_7=`Mj_{9^(^i&!}csb0QV`7rDcUYE%wawk}t zeq!uaV&%WMn-mD_SlM32_r^-+6IEMkfY{uz@{_|nuJFWv92~B{Q*apbXl_@y9=TmU zSBOD#;4oS|A~FRmO&_szE3WVsca>gO*f@>j`&^;KofQY`9&U5F!bgXCT;Z`_9SFvX z2u1Okxm{r_^0<7iaGyeOo?IdpSekvs(yh3{D%m=EcDftx5C}Xw{Zc^Aoqj;0!sd2` zcOo8Fcp&58P%d&5UGhk7S13mopU)K@gYn@CXUZj#086vGSh^KgSk4`z*A>>^-oh1P z>I&i24^v|2TSms~itKlbOp3v_kf+^{@4zyr%=KRd7-DPk2JMiFwr zawM|He6ZXD{{Sp~O~Q9z|seV@T*sV!g`L0HVm zw~#W5U-Zi06f2P4gWukv-`LfbNl1x#mtFa_v-m=;7_7_RIcY}3A7YDxf?w3u>@4~+ z|CcTq4&r>-60Y?uXTNl*PK)b#k#Ak%cQ5JpeuNM406QF*RFTNMPx-B)w;m8+VNL%5 z*ZZ(?K41@ohr!>L08s$@<&OaNM!_vQ-Sf)%OnzU>%>QoW_qEJ4y1iwTp048ye)?rb zKnq`kYL&!NL)XK|b^7AQ4-y|U@{KX4D+PWruKL9`kRD$E^|Xv0enEv8K_LoM2*d*S zOJn?B0QC^JlwRwuooKQuGX4$0=`+4R-x_prwCwvssW-<(dY4bE#n&U*{R^rij-0yikc2^nS$?x#} zJFjD!sF83;UnWmInnjZTJ=g!wK{f`=^inp^K<-stXca=BY8=4OEc*9Ho zc96IgaRJ_N)7`nf;a22q`Mja8KoGtbZU7`^fTbBE#%{$MKI1;m>kVCHe2+Jz^^l1+ zG3F=)G9c?;sayAk4O|=Wl~LX={91p2#|xHx>*ziWlMcF1nV#DVrXex&>hAr*uR)@8 zcpS_R-DiTOiHeb#=DT0s=l{a5FS)_e`TGc``wd8 z_uKBuZTGv8ihFhUesSS3qI7ry3=Z9Afu%WG%-V|G8@Z|U+I@Q&-(&aPG=+!V!#~|g zk)7Orrml&8AJ}wU8v1&0nUi*KxnYvvaxF#3k*(c;tTZ1kLj;iUg>VMoG8HV%{$lc0 za9PcrrWcn28Q+6TvF7l^<*8|2TyECm_RWn;Z66OVw}0c{a>0#)%Q+Mw2QC*NEzO5Z zQ~(K|07n5XW5CjEFYeF^E-!ND>BXh7lH+@D*%j%Xt{UNacX)9r*G1Zg%kuHbikD;f zQHofyjK2}k#2|s|pUX)zHg#<~2`w)N_?>hwYi@dXZyT zCkk9le(;^3MRRVal+n48qQ>jIqC5jPa@IN~si5&DsnbM^@HAKr(!69K%^4~UGG#YO z^=HZ(xDga->{M)Dm4;am{8+x>x5>oygbeFkc-?IjucATI=I3=et%WeoZ#B05`EqAd zVQ(fF{5{_q_{+Ywg_r{D00k7G=?NlKbSsBehxUEj<8*kD*FxUlKS{s{-vHA9lgGaX zCNVKUE5YAz7buw6DL{7_-*ISu)3*I^$bkoWn13z6*)YG?KK#k8f);*)L36JRfXcqD z`e!0zcK0Q&?QXZ)$k!~c*vAHp&rlk_asWGjg1A(*ZgcR1SMhqa*Os2O!n@5W;2cX8 zoi8wj-vIJJ>l*MgJBWj{GW{3I#?$j4^qU)GaPeo^7xFiY@M~|?9h&2&=c>S!-=r=9 zV{kF>$?k>f%~KV^tjhg@*+L)-6!8_6Z(r+qFqy4>7kfaL`p+Po-Ph*&GU0Ro=0Uj6 zmkz=~QL<=@sc6j+V}qC%UYGQ)$z259a7P8X8(5lof?+Elm&yL$19Ihf!KFcihUd$K z!x!B`ft?k3YhCSq5q90CqjK!t9#pnp>!9-8^^~fpX-aNXzC+rT50xjt1U~#Dd=9Sn z`xijvK|S=yf7*5!x2@il=TaHpou~+>?i(9tP$n0a|LUT)xnb$o%L7Xr=%Dedew@Ja zK`J*a^{`PsSndK7z_JEj0$9HO9I#9lty^)HUfjrfVHqyt`(VL*VSEoqDU%D!T1j!5 zxE^I z#um>Uaz8`en=-kuyrHY;U-FiECL-C;BHxrP(U50l8oWF1>4BxQJBenGrMK`9gsTjE zxM+q&LMMjeoacmym)n0!R%8S zd+pm#&wd*;esgV%X1@*GSq4A7N#Qg{se>VadzQhzIlkZ6N&MXJIo1^J{oQTI_;$-f zpE{m&^>sM##5W?3!%tCgIU#Tu1B=AFdIk#=<@@5ATKUT3x8t6LBhPxW*$(2mIErxL z?&~V@G}bg2{Fx-w)Lhi}9raJc5gkhphpOIXWlNnB&tWbgQY`ueCjN(5u$6>%z|7|fq`Z8r1#vxn_xG|#OcJAM`t$%+am=Qd9WnPoon#08S@Hj2zH zU}=_!;;oqHEN(Ep=DB5zAd}xb`^Zv~*E~&dG$`~f>;m)Ly#_+`S0VDBlYYqEq&Ez7 zQX%SKR7^Gd7`r33Ce6(A!`F|7K68`Z990UGw z4fvTI#QX#!&-9h;s~3!KFfAnvOANuu;0JI7z|RBIbsCQAeXi1AYA%;9*>9#EhAh7- zW(7wvOya54-|)M8uQ7{A22W>IDma!qpJcF1OTBqX2K(V+_SXHK{xVd2dni)KYT0+E zg6)JdYSJT}#aX|FpaDEhPjERT+Q1*)+CWIs{5?Rple__jEAH`g#PN5rxetUYd*k5{ z>X1gUJ-Cp)BUfOavEo-X1LcRK+t6Iy~_rWKL939f-@1kp%Fc zu*Pr9QbGJE1Al2zwbkE&tmO|kYNPxvB+C4COvw$jEfK9{2T=gOc3RmD+erxe#%>-# z3;3g90I-ex8Xw$r0bB8-NTEsF{VwDWc*$wa8VZ;Fg_c4qc>WFi-L_EW+o-PzmZ4OD zJ18sr{KnZVSVd*ZDC2Vr`-fO3D9HgiNxB1^rZo5X$bGO2!Xz531x~2)gPnW+WG347 z#8{0IT#-0=UGOrZ0Tw0ZBVCrs4(^UR`8~=9fI+4J7(CD31EQJGq$nVBci@HQzYM3T zh=kU0|D@G|-;FN~EP?a^(|H3boTu6ts_5JnLX?;w*C>0KA@(p=zhiddQB^7uX3SoR zg)e4B?gV4~Dbsyf+Xs;c6bJDBaiu7CDT-O!MJaaXeWg;I;8JvDZTbq~(T(>bm7=dp z(Vn#{m7*i>2Pwr?F2x20(Z`kIci!)+6zi^cBwfeaN~K^3H^1>D+KRm9Qv8dxBbDM^ z-hZSNvs{WA)(%pNmArpZDQDh0irmZlxKa#uDQ;)& zM@n%I?@v^UVwYknYhP4~X}p(Hbu04wI7iz%SbLXJJk0x$@>t_i+{W6tQryb>Z?R|r zkA*J9^{hQnDaP{tb)}f@Qv8#(`zytzynjL|u5u|xur{O=az9BaPI4)ZCB?Uw2_DDr z{ye2Pz@<2ZwXZA1!Ms0QDGFVR-C6sDQtZb2-IU_r6%HOrTBsryD5d-->np*T#ENdvGG#T_I=)8trSPN z6tA)NW2Jb5_hm}a!=+fv+Lx3{f^-( z6)ETa`ATt+OEHqQZz#ptypJly)-J^`*3MCiV|m|GDVnZxw2iPfsT2cvU!W9kx)gm` zd%jW}#QRT~-dK?*U5Xy8jVi^iykDdgH@Orc*7j72t$2U0QjB&feyc}qfl~aJ_tz-J zkuF6eYd^h2@c4@NrzpklF2#GSU8EH6@II^*ZCr}wti4w$tFV*x3yQHmFN z|NU*E?P8bWN!FgC6i@U1Ev2~6rI^jyuu{z9{ZmSDtxGYJwc9Ag!@ReYVz^5&m9^hr zEZU}ce}PgQ>{29H`<7Bn=KWDh(aoh8$J(cqLa6spiXX0Vw7rrPmQq~7`?g9^=TeMh z?FC99_n+M=cs%V=oJ5MFltS*8D89n!Xm|LrI7ohm10|$;yO}1qZHTjelMk1f3>6SKUtenipzN)REoDD{70To9 zE=3>KesO`|u`lmWSBhRP#g439subJv{t%_u!ll@fwGS#qXWnn86lOYt>pPgjbyynjb2X1Ej|vi1}k0D#bXL;!W0WrxdGre~VI_;ZiJQ z?N6gc+XcM8L@D~a6pyj?9i^Db`(u=%yGt>hwa=2m3SL+U4P`5riQ^8xzQ@LyBhbhn zv<;rqi3ng95*f{QD||dE%q9Pn&QUh4$sJhmT-?@_7E8ModB40g;7D}6YIWs%9PeC_ zXx9*BCR9&>5JO$X##7Hiqd>VG+Xc!!*lvZlK!xeSNN)xIvlXid)Z8)~eAj#jR`f z;L*a6R{hr%AW4O1y#ro}Gto<|`h<83+fQM;6`qa?GlUV`3f{~{vFar_f;5qlQhSxw zI(m*l6Zq~-zB{UnC;2JfyIUx_Qj1?XvK2hQPqC6(q{0QH_?J=?`Y9Hx@2sr>#XP0> zcL$NqkwZS?nF`mC;&!E2MT#s|C6v?(&S$M+H3zp@tak29hQwmd<+#HOo^ONKDQBRU zVD(gx9oc>$+wnX0s4&Hh?pAOr8wIN$@E(BadXCgytF?}dzo7|yzh4c$-;u8s9PX!> zbH7k*K`q`;ii7_WfKrtEDb~#t9z#j7y;7V&iY!)_Q&KB9khO}{{-vZzGY0__;pJMH!LUHqQP@Jd~XZR^rDc;YLVt=LR@28mkxbV1#6d|SP?x&bM zODHNy@h$bUf*)Cyn!xwVH^BD`^0k8Z`6=2`M*Oz&E1+1a6xaGGeo=~*%Rup< zQVjP~tW&!`Ns0=kIM`3|+0!!0Eu=VIDY}s&i`6JfY6X8Upvsb1{D|8uR$p#Gb&185 z7vnA!zJfaKdJ1|8Rzuk?SnbGmD?AVt#%S8nS2{Cu7y@L>2O4X3&{_wpQ*Z-{7gvGr z0`j$j8Gp?C;2ELlxfB%Bl;V9q#Ztxl66$%SQoP`&c<@=_aW{D!uN1fWDJDNB6k+n{ zqZF6^5I0UL(ch zN@4u-Y@<>vAVsB8tRO|!s+UyB*mGH{R(%w=S*wO*NLuy&3qg_!&v_lZjxIwlvFd^V zJFX5f zL@7%B6z@_CtolnpalcaR;-^@tzB8K?*D1w@jfYV>M~=k{g-41Mrz*vVq{w1*I3=}$ z%UP>fy@=Z^R$oZ?Ar_ZkAXr^X+;=_+y#yr@%5**xA8O`ur7d~+W8TES-Xc>YU5@eQ@OT`6Q9XZ3tQ@&1Gqmn+2&oYPr~v5SPq za#9?p6m@=z^A-!m98&D36i@ppj$I-Yg65V=akHPIU$szlT?8JDC*mIaI6p=4QlU73 zqtqxx%un&VQhY)lk1EBUeu}S`36E{aBcT-S{1mUgA{1>&akf%??)ROA%Z1|S#h^G$ zDXRSx&%7!WpOIo`rFg(kF>{4b^nV!?|2+ZsR&cDJ;@ujdc#J$gP>R$16vwX=iU&xs zKq*T66mPyJ6iHG{Q;Kc<6jiSaML8+1REqWfc`$vIP>dkO@k;TwpJKurLU9Z!`Y6R* zKgEzYg`y8Bx+ujIKgHm;gkn!pq>snF6};F_QBo%qMWk4%6o2H-1LGR&b%8;8p z6gR#n6g3M$alcYr<)^sreW935itCi(BtOMv8e3ANI8`YQ@Kc;uFFanSq^BsFg?@?> z)#Y<~d6Dw?_iuuMqwTzpgvUx!{CFJht>7v@#Q`4+#XM51R*KoA$lC0s52W86tkpQ2 z#I0+y$d4nlM;sfJ+ch#CX6DLQrk2H$U*b2~`o@wK^-D$v0s-^kv0%vOtyV?7Sp>QH zE=6=hqPie9GGktrRz8q!f~8R(8(C*Rv6biK_epqTZ)uz^?-uCWU1kN|a0tc{ml!<1 zB?X_~nk)B10WVLOg3$cHz~1G%c#D0?`7*cLdPaPyx7fQJ&+R=!;W>G-tS;R_Xz=M} zZ7jn>{bAj64BYxi=v@XGF?e!tp6dQU%fJmC47;qHj8;-*1Ti) z@{Zlh9P5mIUh}cf^^M)jH+C->dvJDaX?DiuJ1`(m4({tpA>Ir%_)Z2T2vs%!C9S|L zp#`N)km>9e)ajcLf3{$*`q?ou5%k5L(8L>s1zxObgPXfuWi z$JV2l3qv6sA%ohCRoWM>$xnM{%p8$f>RdvP$G|UE!W8n!{syy)SOu?W@Pq2*JCYY9 z?0_phq=eU+(o$;R^70H?iWfb0l|i?l?ZmS(cE60>Pg$0hxcx^!=qh;c++^94$)U4` zB%?DxGsCtTEC-8fJi&~Uufd5viLWN$*An0bK`T1TEdWefx-^D{I^5$AZ<0W!zr$s; zLZ-HR-`$FDfVfrWYu6bOI|`+1c1oiseW^rK5VkJbB9 znd|!cRQgnOh5Z9oY@l-|Gg#`J*RBvmN(NO)NE#dymQY$=z0a7{%GQ`(M+u(jC_Zh! znT2WU{zm$6N6cozC*yT0?>zEyq>Z_g(J$?~nFvA^D?!-G^z|5GB zvuXqJC%|l$DQaz`(K$x~l-`j5b#|moo{@&api8kpBNIz3>tNf%m{Y_7 zr4ds{8Vk_~matxbG-AobtAXQ+tg;MO&!u~>PQHfmnv%nIN^fJ8A)n27E4#C;rK_Tr zb8Q6tr2Hfs?(}Y2J8T4(a{Wpid40Adfp>V#CF&sP)`B2Fchf|`8Z*KiPD;L*8k$&} zHDkJ6^DokYQquEl$gDZV;trrU@7UAReqlR(8QyVrzoG}7N=yMpz?6V$b}kY)97D%gk4S4W zRZ}_wB04$24eN##B0EVgs`_r@#&csK#^gcK_ZBum z-&kr<6G%;eDz3F8nZ9CTko7o@)ArMjpq7<&WSdyT3m_f@zBQHWSipbj_6fPik|PA> zG3`^YeRv7P*Eo%*5)+~K;(sE2Fj-j(+L}sZGj?QnUyv3V8YfX%YmxG<*~VOmwq)g6 z^swY#+c+Z!3BPK$UX-7w-Bw^CE@G1zNbi<@v{5DNXeN=sHa{&jjdB4cw$onH?y9>$ z#q+8gs>C@rdMF;FWP(krQYOL+)^%-xDS?@FZtTErV#@NMiNe?12~>;-NKe6Ei8*~R z+45fA{Pk=^24!2CZ4>s&w!}F3oXtzjym6?@jVq_yGR$0gq}#&9(QO%SPSrU{30h8N z)V7$ZI+Y)$K}7Ht1nyKuZ%pMeLW$MrQrx&G6fP--<&AY1*vLwU?4kxW^akF#dqm!2 zg1GhFoqJ_ zBf1c;BGg*H7Smk4 z_n#cV5(;~&AdxepIs0t?9%74-s^p}O71XT=^l{qyHgCg+ybCY~8^ld@gfoPu+3f!u zh&J9Y2xsTv=P*oCrnOG)7W0j4%_>Y4yPflmb(n9M37kBk`K4PAY!}}>TigaG7)7zv zJQ3a!M9d-ZzjTi*&DH}u#J6ciGjE_kz-VQ*R~7uT6J{btLQu=;Yoln75tsf^&Pffg zn3K1zc`9#d6g`36;%$8W#biqEfZ z8{Oc>sJ@IV3Tyk&q{juYHCQe=R~%R$#64gIl3jCR`miHFeoP6)6>W# zKc=Di?OjazI3fWte_m%R+bJ|@j;riL9%UaqPj3SV8%T__s|tcG==Xa1pV;BlHe9 z7N*dl1?omZ#6wrW#yING{jkAL=enCiu-ZqE!{Z#nSy{q7PPdiobnQbo{uQS?6G!cT zFp+2DUA(_Ak)KBdZE1t^$mEY~AjjjJ!W}(RxRZDKeM0ORcXCeQYF{h%74E`1mFaMD z(X8KFuBgd|Sh8|D8e%n-JW7V6a#X}(H+8M2o}Y%(W6NP8qph>_~IYeOB`3{iSPZk{R04bfhlF~9YP)<|Ha zZgOEPAvXxu-r?Y%_=wy9X}Wre1CNgSB$uXSWuZdDOMs6gv_hd7gW+o`XX0OCp6;ag zKnSuuN_-NF*jP{=Z2YV}DjgIjGQNTpF@?AT+r-a=t}Mw)azel62Ftdce6UE>L8am) zP<{qjNd={{#78#PL3E1OIGO`zhbkz?B9@Y&lBvlcNN)+Z;SE&)A#a_&`)Xgc$CyI% zA_mXxNrmRj1EpU;1>+@9j`QhCsmQ|BSic2_5h2aqVd+Ejfl@BX%3>)g!I%=XFx#@* zGSuiT3Yri)m{aKoRI=&Ho$N9}?NYv#r_?FF3Z_@yHn-KWy_d$4wF{3IewpKAp`(`B z+NoR98RyB!sfrn96{eBn?<y%WD(1bmR0S7%w5JDn>Aqr^ICYpz(++N=vfaUah)p>yQzv6ZB#u4$Hxj25^ zT|G+lOf2FB%l_Xv&2`GO6@^$&w0WgM#pP7UDRrbm(syAyqL~VxMApdzB$5uaIko$< zoLs*B%ipv|fxa|e7F@IHAbJhFSsEZy47psapqf)Uv;YfSb)umI;y5|5s|$;L$gL5v zg{2pjg4TSBDd-w|VvuzKJ3OS6qKo>wp*<3dcu{|s3Xi{=w!p)QxCr5u4ea4m=uVgs zS0@?D4#gr8nj<+(qPkP=2s>4I$;BUGy)DVgxk9%{FVjSVRCxZ=&ZqX5au7?KQ{g?I zgy|0D%u80*vtwcrFYt=4qRTX?ga<9=%rPhJ4-)$7y|A_LI2i$>(S{P*pj6e`!nCk*gkM3&F6TKGa6a@T<_sX6VE_#I^V4~HQ>1o z3RhDyIf6x1UE?^hJvN-F@V0Xx_-Jtup=I3`tUF2T>amM%fV&(io`7#{2u&QoTV{(< ztXENd+e7o`eo<~j^JH`9O$GT>Uy_$ZnRR&L$$nfeE1(134wwN|S!I<~JGt7K)UMiG zMeS1U+M-h}I#=V`kjAnt&n20+MWHdHLbQP)!G30m*F$Qr_|T`7I0hdIh0sa&GmxvDEemRc?u~n$h+s?*g>< zLD3r!3!jStZ72_a(a7vcfZB>6GRw58_9 zPD%4)WlUB%ljG>kR`h0>=kf7~pHod0@MP6=B*aq#&S1&P(G)Nxp<%q~3D1=kBsw1B zwpcp$2*74=N!=7BqT>t1k;WI8Z>Tkwo>n`?-?jttG~ifRf;N(r3A-Z)L)5`|870igQNAnU=V-t-hUID}*2Mw*P%xk)178O&1AjUH7T zs=P#ePtNOtFjPY*ak_YherMDPrfM(rcHXztgWr7fEncjTt(6LMhik|Ak4OZoYy1st z`4}7Lh{18QC;`MVGBM?yO(O!yTSRiJs{u~_@d$qJx>zC;4Bb)<*vy_P5jc=8uP}I0 z68r}C#3*%*KoyzgGLwr!-iiwLCrMb5^ihqrHn>LnsDcD zfI1bt!tRBJI`{CA@AYAU;?~x?KK_GB@2%<0-V(cE{w{`94gJf4~no z_l^-(4KdwXI=OuA-7Pmfn3;0%?{2kanp~38GN7|L$@!s?ewSh4Si~l?H72IrZV9oI zlX`pVQ6M%hD*~6GBYBu#dq4pDL@Kd}yQe_;KWi#Wc!U4aM_F?3hGJ64+e$hv;{y&L zc0iVR(f#!86nC^Wm22^@^xroj{R?ukkw?o9C^bMs7y-RmcHXcb1?!lDL-S$Ok?^#Z~GIeYe*=1@80WGnUU!9z}=m2(vilkc!g)U=PXe!#?a z?UD1aYc4#SOB-{cvD4|wm2~CCz4UNPq|-e!rGARc3u1bV!22tCz$GKv2Lrw1AN((Z z9{q=c{?ZeICiT!cu_%DC1LeIj6z>qEIv^aqd>4%V7Mu-JllnY~vZK!_j$^4Zjc>s^ zW+auD6A-EZoO7&V=*JY6TP|~;kKWFrTJ(|RGE{jU?e7QYtk6U`%&}{mdxLprS4SS( z?k#xl5fFLetIXqnNNdZnQX-7_4m}AnEXdaUC2yJuXq$UeOg#KCfUs z_rK%a>RAsnzFD#;yU*-UW*vUP%026;lCz!{pn;zCR5|M^UO;_wN8-sd9-Lwg(gNhB z3Vl&mYtDrE*k20OyRZPtNlICb7W{#1TdoScxqk;?SSN*H+p~aY4t$m0f9CS4u*!Mn zvQSxMz#?P5NvCamu{y&;b3ZrT|e+Jd=V^q@$uY3#5^7`Jbovf z@No!&IKobMp)8%YL%x;W{a-N?Z+$eNO8~s=O@Hi$b$vPSbEZ_;{Gz53$DNWXWFPF- zRN@H1u0u4m?_dJCbJBrQ(Nvu}v53BnP2`RU3N_;4l&0}pNMJ84&Q?+;0bR^~{woiJ z%`0TqR;%piq1H4`9ymR{-90Qo+TS)bs4Kp~^8D=cF4PmbD{8mFM_s z`JTeS%aFX<4_WQS;ai6bN#zF0k{&Doc&3=098K+>}i0nARv3LB~Y>jXm z9q(LINo!N$H0FSWtv@2qnwiFm_pmk z$Nu1Ht&GfUa+jSvtI!d_8JMxC&4>z~9FzM4M=IaLRWg!=fHxGJR|={*rBjle(rw!# z-r3IR8)sp%d3yDX_X3RU<>a3I?m+k$T_oWHy@+%{;}y+&mF1M7rz}Q}48`sn8b~HTkbJAa7DuCo_m+BEeJ7=FB@*s*@A?KhM^YMr~T95cXb_v;m9aM0dE$z;+-X)yieFYX~>N>F- z`P9Q)4!6{d*EVgw3^O#bob-cy^nZ}?4i>YiD7u`8f}HFH<`>vbN47&jzL908W77;g zt9-Fp^oKp|O!sM;O9PSQwNx?RE=lmUcS)-dJM!nXcT9yxT(hlsuqUszSbdIGd-B>z ztUgAoJ$da|Rv#qQalA~#l^$R@(%R`PWoqFPwiARVlro@s?0G{LZBFj~p~~~KHO>St zF6Ta1l(mBZ-1RWhsav;krlkEm=Hpu+=aWDmsm}rCaLj|Ow}9ss7^#Kb6#a<}qK{4{ zJCVAR-2UNk`)TWD+_?7UfPYhJYdDR;b+YUE_{cG6{;k!A{onUgb#rd^Ekv zOC653e7{Wr$HgJhHk_rF{@K_Iy``pOysJH}@*C+QU3HpxX+8xofaBJ>=Wt58=U^$j z2un#<)6j$mGIY?sAQ&LgdfYBfsRVW7c)nYdl8qA2kmBKE zVv!`8JQnVnPr1DBQxIP)` zl6^?jiJzh<8?PL5o?%7rv!eIu1Fy+3CJ;5ygjIatHA8cXneYtXYcH44M0|eYJ_kc| zjZU_|SU);h<{@4i<0A?=AfD_<%AO*r&=i+{LD5Lwu^f`>ZG^uOF&!!f(r`wtJ3an4 zfF^ajIdx~osq$oJiuaD=kv3l<#f$LM1LZphNMPt4kHwPGtz&G=G; z!T5YBqHiIDcQ%^=iqj9!?=53b#_-#|KY%o+=)K6M~z0Y~rd|O@m&j&m$ zkh9u#z!7YGsq+3Edv$xAGCwc^>F&bZNDcI(Jk{{!YV7-0at9_aiNiC{7@VL3ao3L@ z5^4G7cIu?v3$YH!@?_~7r#@%aDl4Vy*U(vD+2@Z~9zm9psABHRuFKC-s_dsT$+8)Z zFJtjlq4iKgP&T7GLxJfzWgfx-QUMKAa`6w~ZAtP~9lU!)wBalIr4Z9`twk)TGjDgq zC~a}Hgu|}Jneb!;#5zp5XdT0WKE#t-Jj656PQ(=Ulhz!GN;?>Bv3ykr`jDdKuR{$05L(xE!VSIPpB9b7}L46dQJc155VjKGa&VPF)RaH3!kMGK~56T}ZR z9*yLP&lN3v4t;t}y9uB`)M0ssTc%_ZW2W2L@QNW;*>s`mG7J9N(jyCMVTryxRK<&c3p=8?A)A8q^d;$Gce#7*)jNm#?%`GIMZ zYb&5+OvoSO!gi8B-RNA^kp3P-CYak!pyl@*b@ot!% zm{RB3zMUTG;sj{Hb6km3bXh+)KchL^XuU43$aJcKOJI6yTe*=>*~*Q5R7INI3a8yD z(hbV#4@Ek=6-JkF-%^rCq`D`YiL_lSoZcj-e~aV(F-mVflOLszx$${a8MQzu(p;p8 zt#De-R}WABlOhdhh0&gP5zB0yN2J+vT$JS9SNphDzPdp^Cw(G(8>=xBtigqz`|eU_ z#R_Tf77MSWERVtCHDzI>t#>}OojyUA#R6&|f}vO z^;rr#3*`G?R&b2eBVqBt0`$1T0+w@V3kIbuEa-Ct`_xb_3N|iVvN^lhBmLlq+rfHw zilX~LDCxYCi>b-fJCNpCm!l3jqZ7+XXp4!ZY{rUh=$U0-%fG9R?YtMNJ0=Ka$Nr$8j)2J;s z+rf*ds${%p3v2}NICfxN(Hoe=c30G&k4fNS^zbZC;ak$VO~0Vz7Cr=BwrPXQ!YbMw zA0h$QUmv$q?oza6DSIIBXG@(SlCn%JqLP8~t*qd8_&iCn@(2{uovorTS(?TYn9c-K zE5$+*(>eGXijo%wuM>^<3x%PHJr5RZk0GsWnl93c^QD5ZCl%ZgT=@}E$t8hWD!4aa zRrc(cWLJm{DR#P8yV7_xX}>;?lphs|%$C^4!MH(=qe7gl04K0nPE?qUJU$JcCaoAN zFlzd!Wb|iLefk&$Q#nq=sO~3g;mN^ep2nZ?uCps7_YorKh^(OX{J?!^%06%)h*uxO z9LE&E$FrvMGg@s?lfY+1C1F6)FaQbf1U|xq_f>-)bN8Lt-mk=x^|93%{-0?0UHhR$ zJ~>c}&v=a*5dC@FRve9Extl)ni&Fa`Et41w`#veuX z51s0UcUgju+m!f_86shubQw5p4?qx26u@Ahzy`66R>yRIH&*5X&41-?=<_8;X9RL) zU3urwg6Pkqvc1pnh&Rj`6yE><)CA+PsI#2`D?xBS5BY9bX6+9bCz;p<3q6e!edbi_ zaHFp(^RYfZ*6!MdoAX&{o5fAV|D*29!*#0O{z-?7M>0ezQyD6vh@{bxN`q3Av68XK zl*kkgj-eDH%1|mv(x3<>Dv@NUNQE+;2Pq;n@cZ1uUh7`=^L$^|d%b`BzSs4>efPT8 zTKDH3*S+^X&uw?_3FFXcf&XK#_=VSlN-sDv=2@TM4M;XK*}Kq8u|MeL2u&^6I~9Cs zXJGW48T%63`P@;7a%OCz*kP6G&GgA_|J^%`FPy-kP0i zq6?mjsEwV=);1iKcEihbYDIIsbZ#hqc64@ie&S$GEtT$1kG=Gx-jt_D;;T#9VB7Ri z$!ti+86P7{=<*!=0|{6$O6X&X(!YZMc4=vdwNW^v_{cg6P=YwI4RZedk{oWm%45(# za{+hkbRc~V@5zC52~BVn_!8?^Tc{k;GcOfF8*Gy$;PHoM5dH0~u*^U1 z*nUToS%nivs*zS{TR8!;G8;jYAxr4LC(?&rbvoXH%3xp-xj3Fav<4(dEX6jVpbuUy za-|O)LbAOg9N*;l!x4}H_S0D|w#cZo=J1c`)>wqVg4=0zVO;E*p(W?v=}H;R?!;7i zqtCShGRv{bt@>1yiE0+ToJIc$HWTy>Ad6+!feoW~h|mW{=!GKmTQNnYh`lw5w&HM7 zZyb~h)+QIM=3Nb_Q{d8q4M%9{#jF67v5W2UsB(MfA?fe z&70|AA?@(-6NwT6-_Za(6a$!I0B+Q44^S`wXf%rNcm(H{SI)_C-HCOHx4G7(y{i^Y zAF4|B)o^AdcTV$4{>(nJN|rD(EZ12tLl*B1mFx`g>@tU-Bn2>RGt>YKiUGW@6tdz2 zF@Q<|K%itURg&IrVDGD{WY1O@oM|8n#vpGnkiT(sSjWwuO7;kKnojK$js7@(VlRco zySzfe;w{}T|L8J>#ZIM=LeIpwHx0N43e^P&yoPP3!L{z@u^x7~L2cen`8$AE<6N0` z5v%_iws73iDKOdYzng7ATW*mpxVni}6KUIvdI}tQK`Fzq9H*emqWi^(6WM08Me>R7 z9*5PJ$;sft;O#K~h_UW7z@Y^4)>)wxvQ7`Z_VH8)jJ)jw>l8xKpqO4K?%oPRFyw<^ z^p`RDc`?W)1~Nws@^dJj0&)hrF969tpJ*T!X>@t5ve+#W5ijbj*XqI45H|`0bSPxq zd=qv!pN}VoGD^H%nZ5lyNGo#SPgo}s(}XhIQ^p9T7gMMdB%Tn;gG`~4ljtav#!SH* zuN;Y{Lb=B8$`HyWOo5|wBrX%myHnV!dOO*lOo~7(E|bp%lWlbJ7@nq~WS?O22A%v- zCR+rP7s@0y&0$wdv)d5*SKocfKnx?CCeiiI9pd@ zS5cUsM=s^tfzq^^NbgS8WLfpRQtriaUh_K#F4d{@%z^^a%dy%(ld#aCifn{`FyT`5 zHw+y5Y_tzQNh=cs6o8_ke?z%r+#G zOLi@p>oG4S^K4~iO6HpcZ%gLIkv?=bPUNkU3F9ykX8%g1Q1**`?8#e~_l75LiD@`_ z*Z=BEW-S9yBL>jH02I}0pNN|$kw6hZaJ;;Q&I?mA2dPC}$-EI}WT%mm?=T-xaxUA~ z9&tOALQ0O+YcIn+feccwYg60Dulsz-Y-|8-jR6cX0M%juhbN{~axI#ENJ%Z3Jyc09 znOk_9=(HIVq2mf0$i+JAbs8K%icXIJE4w6g;^T9W;odLC{T-!{#ahL zDVcL%2!^DRxx$!yuST1PENdXY(pe8V4vMFM>>`lt^R@_>QYpYN=J64>XMFu6KfS~MG>)-v}gQ}C=iHrHw0wL!{e0l zH_P{5my4y?}s00c^Q2ac&O#Uh>Pfozb0>=%Q4M=5;%#~>>Nkm9&>(rM97 ztuEyZ_w!=hn;7mnV%$F;Yb_QiG#d>xPzd68gG*c%&%q8ic#XGH9{x(PiRw}azdOLN zxCS!kVO|W}mQPt)+VY`n!PNo)@F{RR_;D7sds-=nu^beaMfyONo83fQB%gxnk{4V! zX{fsVX!R$=;DM}`QpondXykc!&w>;_X#(r?M=P1BF1JBUhNSA!(Ljz-roOr?R|-LP zjX~B-4Ov(qxw_;w5LIFjN7*eB;ss(5>z_)g)%)mz5TEx43+J;1*x?4bh@p%UWlFQR zr!z4f6>a_jEzZhk$(ig5v?ZD_Awf3e~ng37M8P&WoR|OcT3N#Cm^pl zR=I>#qJm6ZY|+oR=$oBY)`BePYruxlABxcXMd^qVn7vBb|a6KJb{1$dqlqo3nh z3hTAvj4hR<;+%$gsW=UlnW;EG5xhN&Tabhx@L{|Hvy?CttIHYM7KCF;p;@tytvH=| zZ}hk!2iJ}C^NiDe_7$g{0eBz=Fv$Sa*K41h`2v6-JGY`CgtAj#0nSs4x{A{qu5n8K zGRiBtMWWUegrY`8C8s`9mX=G6c($RGjf_Guk5g6jYpv;KJZkaXK06KE*L=ljc*UkaZr_ zYadUwz{uM^uugvbj>uG;A7KcFq>6LInEad=WMc#QuLg#PTn@!kKu*OkjsVFOXS{(} zpiI2ahp}5EA|}Tm+N6f4FA&fnzjbp1>~Iczh8W5yF}E0dyDD=eZ~Q~b@u^*kX;H-~ zKqG`lf7$TwaMF@CeCakMm=*NiLg5lc zQ&EXJQIy5a6FG~5^Dp?=={Daf@&=iZ@n5HCB2lk}NK9!uOewptoGJaq;QUZDSwK$X z*r9!GgjM26naCo3bfgn{KZ|~aL%+nKUlgG)11MvCpQ-2_BJ|fto~T3}WL)=GswW)J z?`eWL^u~HEQNNy*q(rsGym;poWoAm$l?vug?}b2MedwX60&kVbD3xq+m&3hPp8sx)~YHjmfZmXk5w9&{~w;_j_NWw(ufRax*1DaF<-z04&y7ujJqW zAW*U;a7allQ8^-==%J{yfovaxd{HT6*PCLH=>eoT?yoH9^eXzD__!))xaW;=zs7Li zs{!N{dV7eqSfJ1ZfIuM#)dDVYSv(Ot+~8T>PIPS?P@)deW;z6@M6Iy;Yi#+$ysTP; zZ2y(cdh3h>BcC*Zbvld?ck5rN>Of3}q!QJ{Kt3LWoU0Uqye|e>CN<>W!x@r&e!$3G zEC#Wi-6A1=M5DuNwdBc^TFnp$NY=r+`DN^IKHpCaWt7OD&fXry9LXE^I-mAtT2yg5 z(uh5~f-NQg%%J=$gRbJVq4Gl&hc2RuGpi6)9HMZ=p^K>EjKLHzCqPuTJ)QX@tlT%S zF-b1+kKkWHtBJH`kjC21flBF#mWv z;(S5y_AtJYB&6iwzkl#n38c9UZ41Hu8y8xbj1}Uk(i+I=obcg{=H2^oq015{Hfs%WNh>}`yo>C?Gq3BqD4jX=&J&cL4 z$X#S0H|ng{=|$cf*;RBJ0j%uH*K5U@Vz^I?asNswWU)Rm?$-p|1BJ?qLfEzkTDt@1 z0_<>uGQ6Ggw;i!Y9uCL9)_~#D8pvF624mp1)MFFUmdj)duBy{&B7M>TGtfZ1tW3OC-PkRXLzyv%TT(+*6A0+=CscPn ztBxIR(2p3(DDnIm?Ck@hlD=}wPyG4p?1-iGJku6sV#pHuud6ORpz1;wQFXZ)?1aMA zg{GqFQcaMqi0n+&r3wa4tevbCMZ^!JJ>!2*fk323`)XVb@1vCBnBp~WimkZ1tjfdc z)L^&MzOlk8@wQAXBz|-n6Z#ws9C~|)-qN8rr`5#eAV3)_Z-hPx%bBu~C{cAO=S1N@ z^1R`A=5;(@!+NbQ=aNkBPE3D7@HFP7x_rw@NM7i#?m8)$J9ra7V11~%G~ulhGK;9~-qtA1B!Gkosl-4ymWV^3~-JUL*j&v2ONczrX;j(^;R169a(YoO&2I z=6R+bTunMTB~Q0Xb~Q3|j>#}XDWv4BF&WMZWRR2iaDON{d$q4Fg$zKx7{Ij#U>^jf zLg1Brr?<6YpyU|fnCF>GRY|TcQ+S)$b)qu$XTeuW;qyNRc})N*I#nT^zWY+EOFhHA zPKg_U_EJh=Oo8IENdL%Fmfb{LB%gxnQUP2zX{fp!vHEKQ zdD}Nu3fcZ&4Giz@<&eTBP2lcHPXyJaBeY^jsxCtf{Jh2cAa^Wt6BZzt&yE9O>C5CzQ%`etp7N zcbdxN4e(Ia%z|6vEffT2I+G8$ZXxsw#m% zhe%??<`|hQ$deR1Kga~Gj`bj$L{DFPX~c23P_0MMKdHQ4gE!b&qQS>HYcwbjY4Bw? zqd^yjicVr5RH{KXeoqLn4!nwltmTAk5(wGA30c$#Svw|VZX;x=xRC8Zg5sl!U1)_| zNj7)o;$$KBHh^58^AeJ9JUNfe^$yb_GtQ(@R^h#8W6h)DV7&nuDKk-zQ+nnFUvpDo-JNx#g<+`p2AUg9P%Q}ydC>vb*GUWJKBn@d%jp-bsw zk7;GiR56{RZ#v>TplGRi^((p?dmJ}c__cmMiP}7HH_6)TOl-fNw^Iq-M}oW4af_%? zUZ;D~Y4ob(0_RjIz4jq|hnf9H;>*;#Wsj0Q;<1XK>`#1*kBYrr0MVJD%LNcg z2ByvNS}@4sjvs1stVN><+!r(|ZAlkI%orMQn`3bjf~)L!7pCb$f2_*K%`>!?@5w4i z`^q3DNG84y)4L8r&cy3`{l`ph4nZH|N^LUa`ayL_ZJ#~wTjEZ^pM^bwy!X8<*5 zbNsrwTa@lQ8cTL_ zp|K79mD{v+QTw42Q@Az4k-7O#I~u72uvq%=KEz(=zN7Ij;JA*)1{k=G#>$YBt7Lfy z-BZIJMUy%j|An9A>}gIDeBK`GNM|Z4Y>q^_v}x=Hg-^oFSCZ49_ctl+1|9u$K)K-L{I7zjlU_ zFMa6W1LZaVr^Ntj8-N|GlC|Q<03c8@6FBBQP^CyG`n&eHhrC^%R;J#rpDBfO>K216 z5kQJgTo|0*1N~<8XIt8szDX%$`@?Jt>+UHmYf|fs?I`ZnziZ!*l?+KwUi}Q@ zbY<$@{hd+>a&Qc?QfkQZ0?F@zN*aiIF^K%kMDqCj7{q7nw4_?C>=5~UEEYMReffYH z6eorDB{F)0(sk%^4$f>lF3n>9|UAd+543;56hWyqu7f7%5b`Xtahxb2&=^2GOXua7QKN*&*`=t0a?%w zgU0Bi0m@h}w^2%s2)!H06IGYRv=w*Udf$@ac)sj-UWfHsU7C_iE-$pYRK~nmp{p`8 zf5Sdq!CZA2LJ~&RWj}D>)TgosxNt3~4bL>KYk#Gon>;4BIwT^67`5 zWc~Mib(z)LTXCkc@VUQPDWv4E7{J8=K%itr;F#*NN|oflGSoDX)nkzD4dhud$c1c= zP^VAZLZ?UH)#|dbl~-s33uwb4ui-vlXT8^&2iyaNS_1?M!44N{2=fKC=7!uq|jySJ{HAM`$&XP6t2E!*g0HWj2Pt}4kdhPcWp8ug z9H%J0AgojhDcLI~!#RNrqU5=x>Smg5Px29&W2LlP_ONlk|@IY}s1@48^?i6T*f!m*l5h>~ZCCxa;{sxWn z@LBL<%Io(ir8cHOIl1E8#I7MOl21X!X#_3|P8H{T+zhuiM zwa(HO;%==t&tN4(QpK5LOum-YwUD_DR*u#>xg*b3dE*)LTiq0wP5#NfSX|9K{C}iMOnxoe*}SNEdUcDw&spUckOh5PlnA{e^r!Ap^m8Nh z79>wpqF$q|{-NknC&p8b=fzmBCF=TQtt3S;FIKounVE;8-w58G-d#vS5cqA>_n3_y zioRuN8~XW$9iQ!DA6r3Mvieb6%1L+cy*TNL&hjPdaRbmZ1~6MGl+O3)wa=}8Sg!~m zIK2-vlXTV}_AXP4x)PNI*_@Jx?(|Cj&O%!yFElc&*I6&aCltKzkk8y7ha1Ru^86fgdbS4(LoD zKV#kLzzH9UzEcWWXRu!Tc&fy*Mz#;EbM8GsiP{fCFeH_zyaw`;803QnGCc-4pDmgc za^Bqx$tCJl!lgK;^Z~} zr^Ntj8-N|Gxdj**00h}N5IE+c=nkwTot%;-tdfHpvA4N!4p0=IOYbR#lx!1|A$K5y zD0v1cxn#PpIAsmMxiNsd48RFyXO(<~4V3genBG{F)QWS1D#;aR?k!%Y*~--Gv`s0b z)94svjQ~<~st2s>#5AoqcNp%CV%!HC?p0&lzhPq}RcO;4tPq5nhD9!qHs5Rp-(n!a zd=9Zj#rZKWp91wEwL1l_z`*T4$kI~MWs_!{W4i#rdDtKPm@@t*rIg1MC?`J@UCwSI zE|O0{#km4p7@R6jKI71;Y)g9w(^e^D`@(wd&*t}8)}+>X<92bkJ{0xCN`|D0GtroQ z5gXV-9#9HFzNpt8@`luqR|_OpoXZVFvlzsM%tQ`~D`ODb*l9_%+HqUt^Ea@_`D|B1 zGpJ4sWh${h4}1Gnv7G*rb17DfU(dr*sxH(Maw@GP)4(o8E6Gqn+84Q&&iAcW#>t2n z3B|FbJx9?~w3>qC0*J(vt8P@vmsrk}2gFwVJafK)>~^d&gjFK9Omwm6_gnPRZc7n| zUN}O34WNwmQ3FN4H9{Xv@N44T423am+ttUr_T%hBTs$IixoyH zGxI!izJj@fcPbD#YN@*9<*gDlX|mZ=m%2)!s1^Izb8!s0-2Et24ymk0IHc-N@zrG( zw2vN`X0mQJEjBBK0EX$cPm7BKfS|gR1&*mM2TxXVA+|atD;OEd#ALX~$Z%RrhFNT& zC~ri`*|$K+){}j8S)SpQ{FsHdN*-1UDLF&0y^=Qu0D+R%1BaB<>atUng)e8*bR7Rjfex_nQYqvx49R)64x&ojBzBINFObkM z5xf0_u}%4yS_k0Q=y*!AYDw?OoghJoQN^kgmr2@tGM+cZ4XT|RYb2`YUPr7+$bPh$ zg_+E>=!tAJjhKF)5psZ9+TSZSGD5b|S+>0h`6fs#eoRG45QLT^4&sPsQ)IOdDtU2A6d zF?U<~pJf9k#Tz4d|I7Z2K37xtrRdMtL2_`EZf1$d&tK36q7`evw5UI08%*mCn{%+p z4cgHM;!E+&JXIG<|3h`RdextD;P}PYBzXAhG*tEEAVy{Krg;_h(S26#Yh; za72i&#lS8fsXt=_&mvEJe?~JS$6}!RAHQRLT{AgQC;7MGu0P{-FX;cjpP}kmmy9pA zUVt#yQ}2K1&)B9bZGXnI;Dl55f0;5czwKh{yS9T zK{Wjtuh{k0Wz?TB!c3O7lmET_8T0FS`*ie9`7i$t)z%wKvbpb2Rd)KVg)Fp7Q|Z2IW5{(bV74Xc+E~P&a`Igp+;8T;Lscq$`14p1`wrDZz;Rt0 z%`k9X8$BQ=*Us_~`Xh~Z{q^IG2uL}RUZDvt12R&NfUrswlZn@eA3ebk z`eY0o`rQuw7KeTlttRws0A;KrHI*_9%bD^S$rHWCDC|Vxm*meoo<~R^UOxfr)mu+e zx1qZm($^UMF)vnFPJ8&|bKjwAreN+h#zr8xdztHbt2~`tEt}1~Q%|MPy_49--pjno zd!u_9dBR^-7f-|eNBY+oKSO&+#4o6SV%_Y+(OCxIW1aOkXBh!N@W^)`aLj9ri{NU~ z$tihI3H-O`mPUqqV=_Fg6jHKoOomT*Z>Z$I4{zPIw7(QWM&Ll-2YYn9w$8u0y7U^$Q)7eeLMe-?ljZp+#7@S^`@3i_8V&Lv;ltQ-O z%g(h)(~Z@OY#&%>SZ#5)zQ$+@F&UCxV{|u=&nZ(MVXKuwkdMb8k3(_)x-oz(DUkdc zBi%q;7K6yiHkLdt7K50Q8sg(CBA*X~>dt4MR5ybH#89T9uTGr_l75FuzdCgS66hNJ z>J-JXb_42Hr+#2c9y~HeU!7X%cj;HBK41#ohq$j!)q^bXq24{_kr+zoSEtGZlY2-~ z#H4<8DpxT1l}_qcr*>Ux+0K(mc&HWxpaOZSt%6CuIu#X2{p!@|QFKy?Is#ufGrz+E zQc%yLz~e-CHA;kf5RfTNs%dI$$8x6hk2{{<(FAkoiS=3_lYVuo1?J^Uc}ba> z_xx8Vn5!M{1A+CShyAj=RpS0!*=&yXyOctSC-$+qp2>ToT$chl<8qv{Er$34xfI&d z0YWSmvu?I_98?O;PStB)J1PVKL1xzhjwz7&;A+yzDY;GwTp+J9GSrUA(8b75Dkj5p z-Ww{p>@q0Xd$2E%KV0IK+$d>btXR+hEYw-AI= z_KHEip%j8_8iV`^vZpAJM=xbaE|B|;+(lv#+gNVN<3nt3dld9d4KY<9AlXA;;e0;5 ziW%%BhB6g>b!r6WebKtp`E?Up<v3Yj7?Z8iin#@K#rn@ zw3S-Rif?Qc;EDKs+1y>P%iI6p5Jg|O{!EOIAJEugtUb%v&- z>P@VXhx*m2>F@-*lpZO2KAsMOkx!byI(aS%s>>!Af+4B8{9#O9A_jS@ zfjq{>u87k;xG&)kmZOsv<6lk}@oqcJbuS99-)v;@}$nn6Eg$mt{-y zX}^zkv)NhB0IbnjpPfwtfFL_N0>?bhTnSf`PEN_3R>_Br3>{)JOjQagd2>vLwY)b} z^5BI~^0i*R;^a2~d13(d3_t>c((SKTvTFbkC^-^1=6U84Rgx>tq%z*Fttzd-`SUqSc@)ceO&&2gKNRU#r$#$gd%%En z*RM{UWzln6^iP~sK9DT{oewsQ-Y7zUFhW0w<&0h(QxtssP}GmM`iG)4C&q)0XHKlw z5|#9;Qwbo5JF6)(^HB6D!Q0dO29gj2ekhvDTct!voY`#K#=^*~*vDpD5s2mEQc6_S zvN-7yU44nV)d1Y2?0jwwGyoUrwLiVz=DkVN`SUW8&iYU^Q7!69R4drpDY>!~o0!Yw zXY4bpD~ZRbQ%h*>`S|7iJEA*kBf0%sT8tUuNe2gd2dpM z&KHHSZ5Kpv$5mPEaD&pko$~hqVvRi1uTG7EC)lNQ3Jk!&ZK=ch(3Wbl1y|%Z&cjd7 z)~x%Xgi<P`*sXxl_U1VZ06qtPedDUBz1^kZQ|j^H9`9DU>{79~;Tj zd2e*I$icO^6b`Q59eu_50ov130I}G}y4mb3XaE-Ktk2GC0)QYpn*hf=6kPyUlTJ>_ zeM;c6+SJH!S4@U1rI3U*V=^q_y`hpnm4uSdcJLMF&$GOe2PqMtuus-X2H+c=^-A6s z00c_*0*-koIy=°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
  • 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

    P1!x7de;XyEl1u(#Oq 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

    ;y>;T^|?={PqknA?n31Ho;^ z<$0-eoXcgg`8nTCDO5b-AKP(`uoI)=k&ZJb4I5XdD!${ahxN1@l8Cizo89eCDuuYS z^xBuoxBwui&N{#`H$?>yYO={0xmyX`R_hrZZi?yfh|!^BOoyC-4r1iSA7SLsYkkN0 z;ahLyJ}QLZSMr4hV2yIUk#Dk(BQFL-q)Kk!L z{-(wBGmSdVXV!krEx-MjQIC-Czfi9C&bz!esdsvRA9S4BP?I64CxU&8v*KV9Iz*=Q*XtKiplO6p%SiR1Oi9ct9AHEqW=7{w>+eg1-V; z(7&KGB=qhP`mo(f$rqtFC4HjqGKH419Te&!wZsOv6|BQ(y)#4c~-_Z%~8WFe!&TIG5j z=CTVyBYOcnt;ChSyF6h4hQ|PwD}{`_KL*e+00@lCrbg=h%$sT?-_H~j>48Bt0fKgkWm%CHuDjF* znj2it&{RP~Ni@1kLjICATN9bP%T&9*HT!~=G?68^YDBY%w10=z{9oIZ@+77w=`Js_ z&uEF%Q_x+eLJH>-b(aT>cP9ZS{4ud!Dde60dhPS+E?yh?KJZSyZ-Vaf9UQ@s)Ll*) zmlumc-eDj!#~^7ROsBiNwud3PyS!*1-q-B%F&|?x;$`J}t45{|(Lf+zLp~ekMu>)s z`D79(qv%9QO6t-rd=6&KSL6mcC6boGoL|7MG$zZ4Q~7a!llh$bqw4OBzl;74hsstU zpl3kxp|TbXN550Y%AZ!}fI$1Rykj?&M%+RsGM&;TpSXh$l?~p&O80lnpLMw&Dm(F| zx8_c@Mh}(kGOU`)!VC1n(lX-gMWX6vdg1(G>XIqLb4W$3ri`XOk{4S1&C5yggQU3o z?W7;~`C8e0sO%mS%x&a|;MZ^t!(F0WAL=P=ZPEm8x?8e|4waQu-MGsfQ7Kds9b$Md z81Bt6yz=Se{kTiElmG7HK3l&a!_zrbb_40balV>0qBs|W3z=46I*ik$pjShPT`E5W zscx`}=DE>2jND)@p}Wy%PQ>T}eGq#{-LOsft@9~^+|1*ojvIaB(9EH-8z4YVDA1v@ zt7$Ze4ktipe+V5th6a47Y%_-P!=W)-#9Q9*QJ3?tt_C!he>iLrLNz8xB`!RjpAU2S zQz4i9b0wyKsElw#i8A8gXba$v`&3}Ao{1V&_XLbsxYgItHz!38Ik5xgB*T1LnXIHc zRJIJ%=)BXgfk!f=j4j9IRCjy*QFS+uu6qOrqbAqK|1yCxEG;vrs}Sr}^{dz2oHFz@ z?+Pu5vbp}Kt@X=%Sbx;^`dfad|Ay^7CF{Vci}PP~KS_Bf!~NCko_IVD4I*I&7RYGT zIm#ZW>{W!d`M`ww_+9q7xAD;5&e#9pP}zQ+32)%{og6AV2uY~#GY^%0A!OawnvmzQ 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%0A96fW?@ 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

    #W;u0S_LCbIu!xOY+E=ab?| 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ƴ#!cG)vNG9Y^ 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�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 From f1c0b0d15a920b47f7f25346232d3e0b8dbba781 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Mon, 12 Oct 2009 13:07:24 -0700 Subject: [PATCH 249/387] OH-81 Simplify ohcount.so loading path --- ruby/ohcount.rb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ruby/ohcount.rb b/ruby/ohcount.rb index 27cfc0e..c9f0b43 100644 --- a/ruby/ohcount.rb +++ b/ruby/ohcount.rb @@ -3,13 +3,9 @@ # Ohcount module tweaked for use by Ohloh. $: << File.expand_path(File.dirname(__FILE__)) +$: << "#{File.expand_path(File.dirname(__FILE__))}/#{`#{File.dirname(__FILE__)}/print_arch`.strip}" -begin - require 'ohcount.so' -rescue LoadError - print_arch = `#{File.dirname(__FILE__)}/print_arch`.strip - require "#{print_arch}/ohcount.so" -end +require 'ohcount.so' module Ohcount class SourceFile From 7deae3c65c0398dd272f8cee47ddd6abdca5d83c Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Tue, 20 Oct 2009 15:19:51 -0700 Subject: [PATCH 250/387] [Ticket 48] crash on some OSX 10.6 machines; need to close a popen --- src/detector.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/detector.c b/src/detector.c index 863b379..3d039f0 100644 --- a/src/detector.c +++ b/src/detector.c @@ -150,7 +150,9 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { remove(path); free(path); } - if (language) return language; + pclose(f); + if (language) + return language; } return NULL; From be51ff939418ead3404ad25d09e5b51071ce799d Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 12 Nov 2009 15:20:44 -0800 Subject: [PATCH 251/387] [Ticket 48] Rollback -- do not pclose() twice. --- src/detector.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/detector.c b/src/detector.c index 3d039f0..a42972c 100644 --- a/src/detector.c +++ b/src/detector.c @@ -150,7 +150,6 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { remove(path); free(path); } - pclose(f); if (language) return language; } From 3a2d28fc4dffe8ef792b0702ac73c0402c5e5c51 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 24 Nov 2009 09:44:00 -0800 Subject: [PATCH 252/387] [Ticket 51] Change license from GPL2 to GPL3 --- COPYING | 911 ++++++++++++++++++++++++++++++++++++++++++++-------------------- README | 4 +- 2 files changed, 625 insertions(+), 290 deletions(-) diff --git a/COPYING b/COPYING index d511905..94a9ed0 100644 --- a/COPYING +++ b/COPYING @@ -1,285 +1,626 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble + Preamble - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of this License. - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it @@ -287,15 +628,15 @@ free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least +state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) - This program is free software; you can redistribute it and/or modify + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -303,37 +644,31 @@ the "copyright" line and a pointer to where the full notice is found. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + You should have received a copy of the GNU General Public License + along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README b/README index dfea440..0b45da7 100644 --- a/README +++ b/README @@ -7,10 +7,10 @@ ON BUILDING AND REFERING TO THE DOXYGEN DOCS. Ohloh/SourceForge's source code line counter. This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 2 as +it under the terms of the GNU General Public License Version 3 as published by the Free Software Foundation. -Ohcount is specifically licensed under GPL v2.0, and no later version. +Ohcount is licensed under the GNU General Public License Version 3. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of From 9a33fdba5cee08b829e9f8ed162ed20b1d94cb77 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 15 Dec 2009 14:24:21 -0800 Subject: [PATCH 253/387] [FIX] Ruby binding memory performance improvement This patch corrects the terrible memory thrashing that occurs when Ohcount is called through the Ruby binding layer. Each call into Ohcount is accompanied by an array of filenames. This list of filenames is used for hinting in detector.c. For each call into Ohcount, The Ruby binding layer allocated and then freed a clone of this array of filenames two times -- once in the SWIG layer, and once in sourcefile.c. This is OK for small arrays, but in some cases we have thousands of filenames. This caused a massive amount of heap churn and, eventually, resulted in kernel OOM panics. Ohcount no longer clones the list of filenames. Instead, we just use pointers into the original Ruby strings. Presto: no more heap churn; a huge boost in speed; and no need to force a Ruby GC after every call into the library. --- COPYING | 911 +++++++++++++++------------------------------- README | 4 +- ruby/ohcount.i | 7 +- src/detector.c | 9 +- src/sourcefile.c | 64 +--- src/sourcefile.h | 21 -- src/structs.h | 5 +- test/unit/detector_test.h | 32 ++ test/unit/parser_test.h | 4 +- 9 files changed, 336 insertions(+), 721 deletions(-) diff --git a/COPYING b/COPYING index 94a9ed0..d511905 100644 --- a/COPYING +++ b/COPYING @@ -1,626 +1,285 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble + Preamble - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to this License. - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it @@ -628,15 +287,15 @@ free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least +convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) - This program is free software: you can redistribute it and/or modify + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -644,31 +303,37 @@ the "copyright" line and a pointer to where the full notice is found. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program. If not, see . + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/README b/README index 0b45da7..dfea440 100644 --- a/README +++ b/README @@ -7,10 +7,10 @@ ON BUILDING AND REFERING TO THE DOXYGEN DOCS. Ohloh/SourceForge's source code line counter. This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License Version 3 as +it under the terms of the GNU General Public License Version 2 as published by the Free Software Foundation. -Ohcount is licensed under the GNU General Public License Version 3. +Ohcount is specifically licensed under GPL v2.0, and no later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/ruby/ohcount.i b/ruby/ohcount.i index f0b4004..b636494 100644 --- a/ruby/ohcount.i +++ b/ruby/ohcount.i @@ -64,9 +64,8 @@ char **fnames = calloc(length + 1, sizeof(char *)); VALUE *iter = RARRAY(filenames)->ptr; for (i = 0; i < length; i++, iter++) - fnames[i] = STR2CSTR(*iter); - ohcount_sourcefile_set_filenames(self, fnames); - free(fnames); + fnames[i] = StringValuePtr(*iter); + self->filenames = fnames; } SourceFile(const char *filepath, VALUE opt_hash=NULL) { SourceFile *sourcefile = ohcount_sourcefile_new(filepath); @@ -85,6 +84,8 @@ return sourcefile; } ~SourceFile() { + if (self->filenames) + free(self->filenames); ohcount_sourcefile_free(self); } }; diff --git a/src/detector.c b/src/detector.c index a42972c..2e43cc7 100644 --- a/src/detector.c +++ b/src/detector.c @@ -256,7 +256,7 @@ const char *disambiguate_basic(SourceFile *sourcefile) { } // Attempt to detect from associated VB files in file context. - char **filenames = ohcount_sourcefile_get_filenames(sourcefile); + char **filenames = sourcefile->filenames; if (filenames) { int i; for (i = 0; filenames[i] != NULL; i++) { @@ -338,7 +338,7 @@ const char *disambiguate_h(SourceFile *sourcefile) { strncpy(path, sourcefile->filename, length); path[length] = '\0'; *(path + length - 1) = 'm'; - char **filenames = ohcount_sourcefile_get_filenames(sourcefile); + char **filenames = sourcefile->filenames; if (filenames) { int i; for (i = 0; filenames[i] != NULL; i++) @@ -446,8 +446,7 @@ const char *disambiguate_in(SourceFile *sourcefile) { // 'file -b' on the file. ohcount_sourcefile_set_diskpath(undecorated, sourcefile->filepath); ohcount_sourcefile_set_contents(undecorated, p); - char **filenames = ohcount_sourcefile_get_filenames(sourcefile); - ohcount_sourcefile_set_filenames(undecorated, filenames); + undecorated->filenames = sourcefile->filenames; language = ohcount_sourcefile_get_language(undecorated); ohcount_sourcefile_free(undecorated); } @@ -480,7 +479,7 @@ const char *disambiguate_m(SourceFile *sourcefile) { int octave_syntax_detected = 0; int i, has_h_headers = 0, has_c_files = 0; - char **filenames = ohcount_sourcefile_get_filenames(sourcefile); + char **filenames = sourcefile->filenames; if (filenames) { for (i = 0; filenames[i] != NULL; i++) { p = filenames[i]; diff --git a/src/sourcefile.c b/src/sourcefile.c index a46f755..3d175a9 100644 --- a/src/sourcefile.c +++ b/src/sourcefile.c @@ -319,61 +319,9 @@ LocDelta *ohcount_sourcefile_calc_loc_delta(SourceFile *from_file, return delta; } -void ohcount_sourcefile_set_filenames(SourceFile *sourcefile, - char **filenames) { - if (sourcefile->filenames) { - int i = 0; - while (sourcefile->filenames[i]) - free(sourcefile->filenames[i++]); - free(sourcefile->filenames); - } - - if (filenames != NULL) { - int length = 0; - while (filenames[length] != NULL) length++; - char **fnames = calloc(length + 1, sizeof(char *)); - - int i; - for (i = 0; i < length; i++) { - int len = strlen(filenames[i]); - char *fname = malloc(len + 1); - strncpy(fname, filenames[i], len); - fname[len] = '\0'; - fnames[i] = fname; - } - sourcefile->filenames = fnames; - } else sourcefile->filenames = NULL; -} - -char **ohcount_sourcefile_get_filenames(SourceFile *sourcefile) { - if (sourcefile->filenames == NULL) { - char dirpath[FILENAME_MAX]; - strncpy(dirpath, sourcefile->filepath, sourcefile->dirpath); - dirpath[sourcefile->dirpath] = '\0'; - struct dirent *file; - DIR *d = opendir((const char *)dirpath); - if (d) { - int length = 0; - while ((file = readdir(d))) length++; - closedir(d); - - char **filenames = calloc(length + 1, sizeof(char *)); - int i = 0; - d = opendir((const char *)dirpath); - while ((file = readdir(d))) { - int len = strlen(file->d_name); - char *filename = malloc(len + 1); - strncpy(filename, file->d_name, len); - filename[len] = '\0'; - filenames[i++] = filename; - } - closedir(d); - sourcefile->filenames = filenames; - } - } - return sourcefile->filenames; -} - +/* NOTE! Does not free sourcefile->filenames. + * Calling code is responsible for alloc+free of filenames. + */ void ohcount_sourcefile_free(SourceFile *sourcefile) { free(sourcefile->filepath); if (sourcefile->diskpath) @@ -386,12 +334,6 @@ void ohcount_sourcefile_free(SourceFile *sourcefile) { ohcount_license_list_free(sourcefile->license_list); if (sourcefile->loc_list) ohcount_loc_list_free(sourcefile->loc_list); - if (sourcefile->filenames) { - int i = 0; - while (sourcefile->filenames[i]) - free(sourcefile->filenames[i++]); - free(sourcefile->filenames); - } free(sourcefile); } diff --git a/src/sourcefile.h b/src/sourcefile.h index 0d63ab1..e1d8fa6 100644 --- a/src/sourcefile.h +++ b/src/sourcefile.h @@ -155,27 +155,6 @@ LocDelta *ohcount_sourcefile_calc_loc_delta(SourceFile *from, SourceFile *to); /** - * Sets the given SourceFile's directory contents to the string array given. - * The given array is copied and may be 'free'd immediately. - * @param sourcefile A SourceFile created by ohcount_sourcefile_new(). - * @param filenames String array of filenames. If NULL, the next call to - * ohcount_sourcefile_get_filenames will access the SourceFile's directory. - */ -void ohcount_sourcefile_set_filenames(SourceFile *sourcefile, - char **filenames); - -/** - * Returns a string array of the given SourceFile's directory contents. - * If the existing 'filenames' field is NULL, the directory is accessed and its - * listing is returned. - * The returned pointer and its contents are used internally and must not be - * 'free'd. - * @param sourcefile A SourceFile created by ohcount_sourcefile_new(). - * @return pointer to a list of filenames (NULL-pointer terminated). - */ -char **ohcount_sourcefile_get_filenames(SourceFile *sourcefile); - -/** * Frees a SourceFile created by ohcount_sourcefile_new(). * @param sourcefile A SourceFile created by ohcount_sourcefile_new(). */ diff --git a/src/structs.h b/src/structs.h index 3bd9b67..82cdfc0 100644 --- a/src/structs.h +++ b/src/structs.h @@ -303,10 +303,7 @@ typedef struct { */ LocList *loc_list; - /** - * A string array of all filenames in this file's directory. - * Do not use this field. Use ohcount_sourcefile_get_filenames() instead. - */ + /** A string array of all filenames in this file's directory. */ char **filenames; } SourceFile; diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index a26adaa..26f4905 100644 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -2,6 +2,7 @@ // See COPYING for license information. #include +#include #include #include @@ -9,8 +10,38 @@ #include "../../src/languages.h" #include "../../src/sourcefile.h" +char **get_filenames(SourceFile *sourcefile) { + if (sourcefile->filenames == NULL) { + char dirpath[FILENAME_MAX]; + strncpy(dirpath, sourcefile->filepath, sourcefile->dirpath); + dirpath[sourcefile->dirpath] = '\0'; + struct dirent *file; + DIR *d = opendir((const char *)dirpath); + if (d) { + int length = 0; + while ((file = readdir(d))) length++; + closedir(d); + + char **filenames = calloc(length + 1, sizeof(char *)); + int i = 0; + d = opendir((const char *)dirpath); + while ((file = readdir(d))) { + int len = strlen(file->d_name); + char *filename = malloc(len + 1); + strncpy(filename, file->d_name, len); + filename[len] = '\0'; + filenames[i++] = filename; + } + closedir(d); + sourcefile->filenames = filenames; + } + } + return sourcefile->filenames; +} + #define ASSERT_DETECT(x, y) { \ SourceFile *sf = ohcount_sourcefile_new("../detect_files/" y); \ + get_filenames(sf); \ const char *lang = ohcount_detect_language(sf); \ assert(lang); \ assert(strcmp(x, lang) == 0); \ @@ -18,6 +49,7 @@ } #define ASSERT_NODETECT(x) { \ SourceFile *sf = ohcount_sourcefile_new("../detect_files/" x); \ + get_filenames(sf); \ assert(ohcount_detect_language(sf) == NULL); \ ohcount_sourcefile_free(sf); \ } diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index 23291de..7ef9447 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -213,9 +213,9 @@ void test_parser_verify_parses() { if (strcmp(s_p, "visual_basic.bas") == 0) // This file needs frx1.frx in the directory contents to be // detected as Visual Basic. - ohcount_sourcefile_set_filenames(sf, test_basic_vb_filenames); + sf->filenames = test_basic_vb_filenames; else - ohcount_sourcefile_set_filenames(sf, test_parser_filenames); + sf->filenames = test_parser_filenames; TestParserUData *udata = malloc(sizeof(TestParserUData)); udata->sf = sf; From ca709296669fb56b8fe7d5fb468f7b4ce92397aa Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 15 Dec 2009 15:08:35 -0800 Subject: [PATCH 254/387] [Ticket 54] Count files only; not directories In the course of fixing this problem I discovered that the gestalt FilenameRule was comparing only to the base filename, not the entire filepath. This has also been fixed. --- ruby/gestalt/rules/filename_rule.rb | 2 +- src/sourcefile.c | 1 - test/gestalt_files/netbeans/nbplatform/foo | 0 3 files changed, 1 insertion(+), 2 deletions(-) create mode 100644 test/gestalt_files/netbeans/nbplatform/foo diff --git a/ruby/gestalt/rules/filename_rule.rb b/ruby/gestalt/rules/filename_rule.rb index 8f14e13..a658c7c 100644 --- a/ruby/gestalt/rules/filename_rule.rb +++ b/ruby/gestalt/rules/filename_rule.rb @@ -11,7 +11,7 @@ def initialize(*args) end def process_source_file(source_file) - @count += 1 if regex.match(source_file.filename) + @count += 1 if regex.match(source_file.filepath) end def regex diff --git a/src/sourcefile.c b/src/sourcefile.c index 3d175a9..79c107a 100644 --- a/src/sourcefile.c +++ b/src/sourcefile.c @@ -388,7 +388,6 @@ void ohcount_sourcefile_list_add_directory(SourceFileList *list, ohcount_sourcefile_list_add_file(list, filepath); } closedir(d); - ohcount_sourcefile_list_add_file(list, directory); } } diff --git a/test/gestalt_files/netbeans/nbplatform/foo b/test/gestalt_files/netbeans/nbplatform/foo new file mode 100644 index 0000000..e69de29 From 8371531a43b79303453fc2694383e08763fd7319 Mon Sep 17 00:00:00 2001 From: JK Date: Tue, 15 Dec 2009 15:15:45 -0800 Subject: [PATCH 255/387] [Ticket 3] print full path with ohcount -i --- src/ohcount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ohcount.c b/src/ohcount.c index 4a0bb72..babbbf7 100644 --- a/src/ohcount.c +++ b/src/ohcount.c @@ -173,7 +173,7 @@ void individual(SourceFileList *list) { printf(" %10d", liter->loc->blanks); printf(" %10d", liter->loc->code + liter->loc->comments + liter->loc->blanks); - printf(" %s\n", iter->sf->filename); + printf(" %s\n", iter->sf->filepath); liter = liter->next; } iter = iter->next; From 7d14ade9c618938e36d9b244d46e1068f66e02b3 Mon Sep 17 00:00:00 2001 From: Michael Wild Date: Tue, 15 Dec 2009 15:47:31 -0800 Subject: [PATCH 256/387] Changed ordering of tests: - believe modeline - use file-extension - use file-name - use UNIX 'file' command The modeline parsing now allows for non-alphanumeric modes (e.g. C++) and also queries the extension-table (e.g. C++ is not in the name-table). It also tries find the lower-case mode name in both tables. --- src/detector.c | 201 ++++++++++++++++++++---------------- test/detect_files/uses_cpp_modeline | 2 + test/unit/detector_test.h | 1 + 3 files changed, 113 insertions(+), 91 deletions(-) create mode 100644 test/detect_files/uses_cpp_modeline diff --git a/src/detector.c b/src/detector.c index 2e43cc7..b28acf1 100644 --- a/src/detector.c +++ b/src/detector.c @@ -25,40 +25,8 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { char *p, *pe; int length; - // Attempt to detect based on file extension. - length = strlen(sourcefile->ext); - struct ExtensionMap *re = ohcount_hash_language_from_ext(sourcefile->ext, - length); - if (re) language = re->value; - if (language == NULL) { - // Try the lower-case version of this extension. - char lowerext[length + 1]; - strncpy(lowerext, sourcefile->ext, length); - lowerext[length] = '\0'; - for (p = lowerext; p < lowerext + length; p++) *p = tolower(*p); - struct ExtensionMap *re = ohcount_hash_language_from_ext(lowerext, length); - if (re) return re->value; - } - if (language) { - if (ISAMBIGUOUS(language)) { - // Call the appropriate function for disambiguation. - length = strlen(DISAMBIGUATEWHAT(language)); - struct DisambiguateFuncsMap *rd = - ohcount_hash_disambiguate_func_from_id(DISAMBIGUATEWHAT(language), - length); - if (rd) return rd->value(sourcefile); - } else return ISBINARY(language) ? NULL : language; - } - - // Attempt to detect based on filename. - length = strlen(sourcefile->filename); - struct FilenameMap *rf = - ohcount_hash_language_from_filename(sourcefile->filename, length); - if (rf) return rf->value; - - char line[81] = { '\0' }, buf[81]; - // Attempt to detect using Emacs mode line (/^-\*-\s*mode[\s:]*\w/i). + char line[81] = { '\0' }, buf[81]; p = ohcount_sourcefile_get_contents(sourcefile); pe = p; char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); @@ -74,87 +42,138 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { p = pe; } else break; } - char *eol = line + strlen(line); - for (p = line; p < eol; p++) *p = tolower(*p); p = strstr(line, "-*-"); if (p) { p += 3; while (*p == ' ' || *p == '\t') p++; - if (strncmp(p, "mode", 4) == 0) { + // detect "mode" (any capitalization) + if (strncasecmp(p, "mode", 4) == 0) { p += 4; while (*p == ' ' || *p == '\t' || *p == ':') p++; } pe = p; - while (isalnum(*pe)) pe++; + while (!isspace(*pe) && *pe != ';' && pe != strstr(pe, "-*-")) pe++; length = pe - p; strncpy(buf, p, length); buf[length] = '\0'; + // First try it with the language name. struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); - if (rl) return rl->name; + if (rl) language = rl->name; + if(!language) { + // Then try it with the extension table. + struct ExtensionMap *re = ohcount_hash_language_from_ext(buf, length); + if (re) language = re->value; + } + if (!language) { + // Try the lower-case version of this modeline. + for (pe = buf; pe < buf+length; pe++) *pe = tolower(*pe); + // First try it with the language name. + rl = ohcount_hash_language_from_name(buf, length); + if (rl) language = rl->name; + } + if (!language) { + // Then try it with the extension table. + struct ExtensionMap *re = ohcount_hash_language_from_ext(buf, length); + if (re) language = re->value; + } } - // Attempt to detect based on Unix 'file' command. - int tmpfile = 0; - char *path = sourcefile->filepath; - if (sourcefile->diskpath) - path = sourcefile->diskpath; - if (access(path, F_OK) != 0) { // create temporary file - path = malloc(21); - strncpy(path, "/tmp/ohcount_XXXXXXX", 20); - *(path + 21) = '\0'; - int fd = mkstemp(path); - char *contents = ohcount_sourcefile_get_contents(sourcefile); - log_it("contents:"); - log_it(contents); - length = contents ? strlen(contents) : 0; - write(fd, contents, length); - close(fd); - tmpfile = 1; + // Attempt to detect based on file extension. + if(!language) { + length = strlen(sourcefile->ext); + struct ExtensionMap *re = ohcount_hash_language_from_ext(sourcefile->ext, + length); + if (re) language = re->value; + if (!language) { + // Try the lower-case version of this extension. + char lowerext[length + 1]; + strncpy(lowerext, sourcefile->ext, length); + lowerext[length] = '\0'; + for (p = lowerext; p < lowerext + length; p++) *p = tolower(*p); + struct ExtensionMap *re = ohcount_hash_language_from_ext(lowerext, length); + if (re) language = re->value; + } } - char command[strlen(path) + 11]; - sprintf(command, "file -b '%s'", path); - FILE *f = popen(command, "r"); - if (f) { - fgets(line, sizeof(line), f); - char *eol = line + strlen(line); - for (p = line; p < eol; p++) *p = tolower(*p); - p = strstr(line, "script text"); - if (p && p == line) { // /^script text(?: executable)? for \w/ - p = strstr(line, "for "); - if (p) { - p += 4; - pe = p; - while (isalnum(*pe)) pe++; + + // Attempt to detect based on filename. + if(!language) { + length = strlen(sourcefile->filename); + struct FilenameMap *rf = + ohcount_hash_language_from_filename(sourcefile->filename, length); + if (rf) language = rf->value; + } + + // Attempt to detect based on Unix 'file' command. + if(!language) { + int tmpfile = 0; + char *path = sourcefile->filepath; + if (sourcefile->diskpath) + path = sourcefile->diskpath; + if (access(path, F_OK) != 0) { // create temporary file + path = malloc(21); + strncpy(path, "/tmp/ohcount_XXXXXXX", 20); + *(path + 21) = '\0'; + int fd = mkstemp(path); + char *contents = ohcount_sourcefile_get_contents(sourcefile); + log_it("contents:"); + log_it(contents); + length = contents ? strlen(contents) : 0; + write(fd, contents, length); + close(fd); + tmpfile = 1; + } + char command[strlen(path) + 11]; + sprintf(command, "file -b '%s'", path); + FILE *f = popen(command, "r"); + if (f) { + fgets(line, sizeof(line), f); + char *eol = line + strlen(line); + for (p = line; p < eol; p++) *p = tolower(*p); + p = strstr(line, "script text"); + if (p && p == line) { // /^script text(?: executable)? for \w/ + p = strstr(line, "for "); + if (p) { + p += 4; + pe = p; + while (isalnum(*pe)) pe++; + length = pe - p; + strncpy(buf, p, length); + buf[length] = '\0'; + struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); + if (rl) language = rl->name; + } + } else if (p) { // /(\w+)(?: -\w+)* script text/ + do { + p--; + pe = p; + while (*p == ' ') p--; + while (p != line && isalnum(*(p - 1))) p--; + if (p != line && *(p - 1) == '-') p--; + } while (*p == '-'); // Skip over any switches. length = pe - p; strncpy(buf, p, length); buf[length] = '\0'; struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); if (rl) language = rl->name; + } else if (strstr(line, "xml")) language = LANG_XML; + pclose(f); + if (tmpfile) { + remove(path); + free(path); } - } else if (p) { // /(\w+)(?: -\w+)* script text/ - do { - p--; - pe = p; - while (*p == ' ') p--; - while (p != line && isalnum(*(p - 1))) p--; - if (p != line && *(p - 1) == '-') p--; - } while (*p == '-'); // Skip over any switches. - length = pe - p; - strncpy(buf, p, length); - buf[length] = '\0'; - struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); - if (rl) language = rl->name; - } else if (strstr(line, "xml")) language = LANG_XML; - pclose(f); - if (tmpfile) { - remove(path); - free(path); } - if (language) - return language; } - - return NULL; + if (language) { + if (ISAMBIGUOUS(language)) { + // Call the appropriate function for disambiguation. + length = strlen(DISAMBIGUATEWHAT(language)); + struct DisambiguateFuncsMap *rd = + ohcount_hash_disambiguate_func_from_id(DISAMBIGUATEWHAT(language), + length); + if (rd) language = rd->value(sourcefile); + } else language = ISBINARY(language) ? NULL : language; + } + return language; } const char *disambiguate_aspx(SourceFile *sourcefile) { diff --git a/test/detect_files/uses_cpp_modeline b/test/detect_files/uses_cpp_modeline new file mode 100644 index 0000000..11f0cf3 --- /dev/null +++ b/test/detect_files/uses_cpp_modeline @@ -0,0 +1,2 @@ +/* -*- C++ -*- */ + diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index 26f4905..b75c33d 100644 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -131,6 +131,7 @@ void test_detector_no_extensions() { ASSERT_DETECT(LANG_TCL, "tcl_script"); ASSERT_DETECT(LANG_PYTHON, "python.data"); ASSERT_DETECT(LANG_PYTHON, "python2.data"); + ASSERT_DETECT(LANG_CPP, "uses_cpp_modeline"); } void test_detector_csharp_or_clearsilver() { From e6fa68622acc1ec32c5acb476fa23185e72070b4 Mon Sep 17 00:00:00 2001 From: Michael Wild Date: Tue, 15 Dec 2009 15:58:10 -0800 Subject: [PATCH 257/387] FIX: Allow disambiguate_h to parse keywords at BOL --- src/detector.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/detector.c b/src/detector.c index b28acf1..8169a9f 100644 --- a/src/detector.c +++ b/src/detector.c @@ -347,7 +347,7 @@ const char *disambiguate_fortran(SourceFile *sourcefile) { } const char *disambiguate_h(SourceFile *sourcefile) { - char *p, *pe; + char *p, *pe, *bof; int length; // If the directory contains a matching *.m file, likely Objective C. @@ -368,7 +368,8 @@ const char *disambiguate_h(SourceFile *sourcefile) { // Attempt to detect based on file contents. char line[81], buf[81]; - p = ohcount_sourcefile_get_contents(sourcefile); + bof = ohcount_sourcefile_get_contents(sourcefile); + p = bof; pe = p; char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); while (pe < eof) { @@ -415,7 +416,7 @@ const char *disambiguate_h(SourceFile *sourcefile) { // Look for C++ keywords. p = line; while (p < eol) { - if (islower(*p) && p != line && !isalnum(*(p - 1)) && *(p - 1) != '_') { + if (islower(*p) && p != bof && !isalnum(*(p - 1)) && *(p - 1) != '_') { pe = p; while (islower(*pe)) pe++; if (!isalnum(*pe) && *pe != '_') { From 485ced682054edadbb5b9f1b6c354ccf6849dc09 Mon Sep 17 00:00:00 2001 From: Andy Verprauskus Date: Tue, 29 Dec 2009 12:06:54 -0800 Subject: [PATCH 258/387] [NEW] Add test that tmp files are found (mostly for centos) --- test/unit/sourcefile_test.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/unit/sourcefile_test.h b/test/unit/sourcefile_test.h index 1c03d07..98df899 100644 --- a/test/unit/sourcefile_test.h +++ b/test/unit/sourcefile_test.h @@ -214,6 +214,29 @@ void test_sourcefile_list_language_facts() { ohcount_loc_list_free(list); } +#define FALSE 0 +#define TRUE 1 +char *tmp_file_from_buf(const char *buf); + +void test_tmp_dir() { + char buf[] = "This is just some bogus text."; + char *tmp_path = tmp_file_from_buf(buf); + + SourceFileList *list = ohcount_sourcefile_list_new(); + ohcount_sourcefile_list_add_directory(list, "/tmp"); + int has_tmp = FALSE; + SourceFileList *iter = list->head; + + for (; iter != NULL; iter = iter->next) { + if (strcmp(iter->sf->filepath, tmp_path) == 0) { + has_tmp = TRUE; + break; + } + } + assert(has_tmp); +} + + void all_sourcefile_tests() { test_sourcefile_initialize(); test_sourcefile_language_breakdowns(); @@ -224,4 +247,5 @@ void all_sourcefile_tests() { test_sourcefile_calc_diff(); test_sourcefile_list_language_facts(); + test_tmp_dir(); } From a2903082b8e57657b37d636d18afb5ad8de296c7 Mon Sep 17 00:00:00 2001 From: Guilherme Balena Versiani Date: Sun, 27 Dec 2009 02:37:18 -0200 Subject: [PATCH 259/387] Use of stat instead of d_type from dirent struct. --- src/sourcefile.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/sourcefile.c b/src/sourcefile.c index 79c107a..468a319 100644 --- a/src/sourcefile.c +++ b/src/sourcefile.c @@ -6,6 +6,10 @@ #include #include +#include +#include +#include + #include "detector.h" #include "diff.h" #include "languages.h" @@ -374,17 +378,15 @@ void ohcount_sourcefile_list_add_directory(SourceFileList *list, DIR *d = opendir(directory); if (d) { while ((file = readdir(d))) { + struct stat st; int length = strlen(file->d_name); strncpy(f_p, (const char *)file->d_name, length); *(f_p + length) = '\0'; - if (file->d_type == DT_DIR && *file->d_name != '.') // no hidden dirs + stat(filepath, &st); + if (S_ISDIR(st.st_mode) && *file->d_name != '.') // no hidden dirs ohcount_sourcefile_list_add_directory(list, filepath); - else if (file->d_type == DT_REG -#ifdef TMP_FILES_ARE_DT_UNKNOWN - || file->d_type == DT_UNKNOWN -#endif - ) + else if (S_ISREG(st.st_mode)) ohcount_sourcefile_list_add_file(list, filepath); } closedir(d); From fd3a380d9a3e20415e93d1e16b5d5c35d484f690 Mon Sep 17 00:00:00 2001 From: Guilherme Balena Versiani Date: Sun, 27 Dec 2009 02:58:19 -0200 Subject: [PATCH 260/387] MinGW/MSYS support (and probably for Cygwin too) --- src/detector.c | 5 +++++ src/diff.c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/detector.c b/src/detector.c index 8169a9f..1963bd4 100644 --- a/src/detector.c +++ b/src/detector.c @@ -20,6 +20,11 @@ #define ISAMBIGUOUS(x) (x[0] == '\2') #define DISAMBIGUATEWHAT(x) &x[1] +#ifdef _WIN32 +# include +# define mkstemp(p) _open(_mktemp(p), _O_CREAT | _O_SHORT_LIVED | _O_EXCL) +#endif + const char *ohcount_detect_language(SourceFile *sourcefile) { const char *language = NULL; char *p, *pe; diff --git a/src/diff.c b/src/diff.c index 1aa6bcf..5465c9d 100644 --- a/src/diff.c +++ b/src/diff.c @@ -2,6 +2,11 @@ #include #include +#ifdef _WIN32 +# include +# define mkstemp(p) _open(_mktemp(p), _O_CREAT | _O_SHORT_LIVED | _O_EXCL) +#endif + /* * The bulk of this software is derived from Plan 9 and is thus distributed * under the Lucent Public License, Version 1.02, reproduced below. From f982cfffd0f031ee3a5295114758d03d85959e69 Mon Sep 17 00:00:00 2001 From: Boris 'billiob' Faure Date: Sat, 26 Dec 2009 18:06:47 +0100 Subject: [PATCH 261/387] [README] add gperf as dependency --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index dfea440..b823757 100644 --- a/README +++ b/README @@ -87,4 +87,4 @@ Read http://labs.ohloh.net/ohcount/wiki/HowToSubmitPatches for information about DEPENDENCIES ============ -SWIG, pcre, ragel, bash +SWIG, pcre, ragel, gperf, bash From e4880394a8df660f6b132eb68e53da93b621322c Mon Sep 17 00:00:00 2001 From: Boris 'billiob' Faure Date: Sun, 27 Dec 2009 18:43:11 +0100 Subject: [PATCH 262/387] [NEW] add brainfuck and brainfuck++ detectors --- src/hash/extensions.gperf | 2 ++ src/hash/languages.gperf | 2 ++ src/languages.h | 2 ++ test/detect_files/foo.bf | 16 +++++++++++++++ test/detect_files/foo.bfpp | 50 ++++++++++++++++++++++++++++++++++++++++++++++ test/unit/detector_test.h | 8 +++++++- 6 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 test/detect_files/foo.bf create mode 100644 test/detect_files/foo.bfpp diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index fcadae6..f89cb4e 100644 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -22,6 +22,8 @@ awk, LANG_AWK b, DISAMBIGUATE("b") bas, DISAMBIGUATE("basic") bat, LANG_BAT +bf, LANG_BRAINFUCK +bfpp, LANG_BFPP bi, DISAMBIGUATE("basic") bmp, BINARY bmx, LANG_BLITZMAX diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index 037b2bc..b051cfb 100644 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -12,6 +12,8 @@ awk, LANG_AWK, "AWK", 0 bat, LANG_BAT, "DOS batch script", 0 blitzmax, LANG_BLITZMAX, "BlitzMax", 0 boo, LANG_BOO, "Boo", 0 +brainfuck, LANG_BRAINFUCK, "Brainfuck", 0 +bfpp, LANG_BFPP, "Brainfuck++", 0 c, LANG_C, "C", 0 classic_basic, LANG_CLASSIC_BASIC, "Classic Basic", 0 clearsilver, LANG_CLEARSILVER, "ClearSilver", 0 diff --git a/src/languages.h b/src/languages.h index b19a649..3b3decd 100644 --- a/src/languages.h +++ b/src/languages.h @@ -12,6 +12,8 @@ #define LANG_AUTOCONF "autoconf" #define LANG_AUTOMAKE "automake" #define LANG_AWK "awk" +#define LANG_BRAINFUCK "brainfuck" +#define LANG_BFPP "bfpp" #define LANG_BAT "bat" #define LANG_BLITZMAX "blitzmax" #define LANG_BOO "boo" diff --git a/test/detect_files/foo.bf b/test/detect_files/foo.bf new file mode 100644 index 0000000..2220679 --- /dev/null +++ b/test/detect_files/foo.bf @@ -0,0 +1,16 @@ +>++++++[>+++[<<++++>>-]<-]<. +>+++++[<++++++>-]<-. ++++++++. +. ++++. +>>++++[<++++++>-]<++[<--->-]<-. +>>++[<+++++>-]<+[<+++++>-]<. +>++++[<++++++>-]<. ++++. +------. +>++[<---->-]<. +>>++[<+++++>-]<+[<------>-]<-. +. +. +. +. diff --git a/test/detect_files/foo.bfpp b/test/detect_files/foo.bfpp new file mode 100644 index 0000000..ce9ec71 --- /dev/null +++ b/test/detect_files/foo.bfpp @@ -0,0 +1,50 @@ += comment +>++++++[>+++[<<++++>>-]<-]<. +>+++++[<++++++>-]<-. ++++++++. +. ++++. +>>++++[<++++++>-]<++[<--->-]<-. +>>++[<+++++>-]<+[<+++++>-]<. +>++++[<++++++>-]<. ++++. +------. +>++[<---->-]<. +>>++++[<++++>-]<+[<---->-]<. +>+++++++[<++++++>-]<-. +>++++++[<++++++>-]<+. +>>++++[<++++++>-]<++[<--->-]<. +>+++++[<+++++++>-]<-. +>++++[>++++[<<+++>>-]<-]<. +>++++[<---->-]<-. +>++[<++++>-]<. ++++++. +>++[<---->-]<. +>+++[<+++++>-]<. +>+++[<------>-]<. +>++[<++++>-]<. +>++++[>++++[<<---->>-]<-]<. +. +>++[<----->-]<. +. +. +. +. +[-] += Try to open b file +>+++++++[>+++++++[<<++>>-]<-]<. +#[ + >>++++[<++++>-]<+[<++++++>-]<. + +++. + +++. + -------. + >>++++[<++++++>-]<-[<--->-]<. + >>++[<+++++>-]<+[<++++++>-]<. + >>++[<+++++>-]<+[<------>-]<. + >>++++[<++++++>-]<++[<+++>-]<+. + +. + >++[<----->-]<-. + >+++[<+++>-]<. + >+++[<--->-]<. + -. +#] diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index b75c33d..b73733f 100644 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -109,7 +109,7 @@ void test_detector_detect_polyglot() { ASSERT_DETECT(LANG_GLSL, "foo.glsl"); ASSERT_DETECT(LANG_GLSL, "foo_glsl.vert"); ASSERT_DETECT(LANG_GLSL, "foo_glsl.frag"); - ASSERT_DETECT(LANG_IDL_PVWAVE, "foo.pro"); + ASSERT_DETECT(LANG_IDL_PVWAVE, "foo.pro"); ASSERT_DETECT(LANG_ASSEMBLER, "foo.z80"); ASSERT_DETECT(LANG_PHP, "php.inc"); ASSERT_NODETECT("empty.inc"); @@ -152,6 +152,11 @@ void test_detector_xml_with_custom_extension() { ASSERT_DETECT(LANG_XML, "xml.custom_ext"); } +void test_detector_brainfuck() { + ASSERT_DETECT(LANG_BRAINFUCK, "foo.bf"); + ASSERT_DETECT(LANG_BFPP, "foo.bfpp"); +} + void all_detector_tests() { test_detector_smalltalk(); test_detector_disambiguate_m(); @@ -164,4 +169,5 @@ void all_detector_tests() { test_detector_csharp_or_clearsilver(); test_detector_basic(); test_detector_xml_with_custom_extension(); + test_detector_brainfuck(); } From 77cd2850c97344b6533047a210682b2bcf62519e Mon Sep 17 00:00:00 2001 From: Boris 'billiob' Faure Date: Mon, 28 Dec 2009 20:33:05 +0100 Subject: [PATCH 263/387] [NEW] brainfuck parser --- src/hash/parsers.gperf | 2 + src/parsers/brainfuck.rl | 107 +++++++++++++++++++++++++++++++++++++ test/expected_dir/brainfuck.bf | 19 +++++++ test/src_dir/brainfuck.bf | 19 +++++++ test/unit/parser_test.h | 2 + test/unit/parsers/test_brainfuck.h | 18 +++++++ 6 files changed, 167 insertions(+) create mode 100644 src/parsers/brainfuck.rl create mode 100644 test/expected_dir/brainfuck.bf create mode 100644 test/src_dir/brainfuck.bf create mode 100644 test/unit/parsers/test_brainfuck.h diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index ae37503..00f0eb3 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -8,6 +8,7 @@ #include "../parsers/bat.h" #include "../parsers/blitzmax.h" #include "../parsers/boo.h" +#include "../parsers/brainfuck.h" #include "../parsers/c.h" #include "../parsers/classic_basic.h" #include "../parsers/clearsilver.h" @@ -88,6 +89,7 @@ awk, parse_awk bat, parse_bat blitzmax, parse_blitzmax boo, parse_boo +brainfuck, parse_brainfuck c, parse_c cmake, parse_cmake classic_basic, parse_classic_basic diff --git a/src/parsers/brainfuck.rl b/src/parsers/brainfuck.rl new file mode 100644 index 0000000..fbebfea --- /dev/null +++ b/src/parsers/brainfuck.rl @@ -0,0 +1,107 @@ +// brainfuck.rl written by Boris 'billiob' Faure billiobgmailcom + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_BRAINFUCK_PARSER_H +#define OHCOUNT_BRAINFUCK_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *BRAINFUCK_LANG = LANG_BRAINFUCK; + +// the languages entities +const char *brainfuck_entities[] = { + "space", "comment", "operator" +}; + +// constants associated with the entities +enum { + BRAINFUCK_SPACE = 0, BRAINFUCK_COMMENT, BRAINFUCK_OPERATOR +}; + +/*****************************************************************************/ + +%%{ + machine brainfuck; + write data; + include common "common.rl"; + + # Line counting machine + + action brainfuck_ccallback { + switch(entity) { + case BRAINFUCK_SPACE: + ls + break; + case BRAINFUCK_OPERATOR: + code + break; + case BRAINFUCK_COMMENT: + comment + break; + case INTERNAL_NL: + std_internal_newline(BRAINFUCK_LANG) + break; + case NEWLINE: + std_newline(BRAINFUCK_LANG) + } + } + + brainfuck_operator = [+\-<>.,\[\]] @code; + + brainfuck_line := |* + spaces ${ entity = BRAINFUCK_SPACE; } => brainfuck_ccallback; + newline ${ entity = NEWLINE; } => brainfuck_ccallback; + brainfuck_operator ${ entity = BRAINFUCK_OPERATOR; } => brainfuck_ccallback; + ^space ${ entity = BRAINFUCK_COMMENT; } => brainfuck_ccallback; + *|; + + # Entity machine + + action brainfuck_ecallback { + callback(BRAINFUCK_LANG, brainfuck_entities[entity], cint(ts), cint(te), userdata); + } + + brainfuck_operator_entity = [+\-<>.,\[\]]; + + brainfuck_comment_entity = !(space | brainfuck_operator_entity); + + brainfuck_entity := |* + space+ ${ entity = BRAINFUCK_SPACE; } => brainfuck_ecallback; + brainfuck_operator_entity ${ entity = BRAINFUCK_OPERATOR; } => brainfuck_ecallback; + brainfuck_comment_entity ${ entity = BRAINFUCK_COMMENT; } => brainfuck_ecallback; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with Brainfuck code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_brainfuck(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + %% write init; + cs = (count) ? brainfuck_en_brainfuck_line : brainfuck_en_brainfuck_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(BRAINFUCK_LANG) } +} + +#endif + +/*****************************************************************************/ + diff --git a/test/expected_dir/brainfuck.bf b/test/expected_dir/brainfuck.bf new file mode 100644 index 0000000..6a0b41e --- /dev/null +++ b/test/expected_dir/brainfuck.bf @@ -0,0 +1,19 @@ +brainfuck comment Print "Hello World!!!!!" +brainfuck blank +brainfuck code Line that does nothing: >< +brainfuck code >++++++[>+++[<<++++>>-]<-]<. +brainfuck code >+++++[<++++++>-]<-. +brainfuck code +++++++. +brainfuck code . +brainfuck code +++. +brainfuck code >>++++[<++++++>-]<++[<--->-]<-. +brainfuck code >>++[<+++++>-]<+[<+++++>-]<. +brainfuck code >++++[<++++++>-]<. +brainfuck code +++. +brainfuck code ------. +brainfuck code >++[<---->-]<. +brainfuck code >>++[<+++++>-]<+[<------>-]<-. +brainfuck code . +brainfuck code . +brainfuck code . +brainfuck code . diff --git a/test/src_dir/brainfuck.bf b/test/src_dir/brainfuck.bf new file mode 100644 index 0000000..0eb2911 --- /dev/null +++ b/test/src_dir/brainfuck.bf @@ -0,0 +1,19 @@ +Print "Hello World!!!!!" + +Line that does nothing: >< +>++++++[>+++[<<++++>>-]<-]<. +>+++++[<++++++>-]<-. ++++++++. +. ++++. +>>++++[<++++++>-]<++[<--->-]<-. +>>++[<+++++>-]<+[<+++++>-]<. +>++++[<++++++>-]<. ++++. +------. +>++[<---->-]<. +>>++[<+++++>-]<+[<------>-]<-. +. +. +. +. diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index 7ef9447..79c58ae 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -83,6 +83,7 @@ void test_parser_verify_entity(SourceFile *sf, const char *entity, #include "parsers/test_bat.h" #include "parsers/test_blitzmax.h" #include "parsers/test_boo.h" +#include "parsers/test_brainfuck.h" #include "parsers/test_c.h" #include "parsers/test_clearsilvertemplate.h" #include "parsers/test_clearsilver.h" @@ -255,6 +256,7 @@ void all_parser_tests() { all_bat_tests(); all_blitzmax_tests(); all_boo_tests(); + all_brainfuck_tests(); all_c_tests(); all_clearsilver_template_tests(); all_clearsilver_tests(); diff --git a/test/unit/parsers/test_brainfuck.h b/test/unit/parsers/test_brainfuck.h new file mode 100644 index 0000000..a13f452 --- /dev/null +++ b/test/unit/parsers/test_brainfuck.h @@ -0,0 +1,18 @@ +void test_brainfuck_comment() { + test_parser_verify_parse( + test_parser_sourcefile("brainfuck", " #comment"), + "brainfuck", "", "#comment", 0 + ); +} + +void test_brainfuck_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("brainfuck", " #comment"), + "#comment", "#comment" + ); +} + +void all_brainfuck_tests() { + test_brainfuck_comment(); + test_brainfuck_comment_entities(); +} From d4aa15424d495a16e0a5ef42d4f5046d4f73d208 Mon Sep 17 00:00:00 2001 From: Boris 'billiob' Faure Date: Tue, 29 Dec 2009 18:15:43 +0100 Subject: [PATCH 264/387] [NEW] brainfuck++ parser --- src/hash/parsers.gperf | 2 + src/parsers/bfpp.rl | 126 ++++++++++++++++++++++++++++++++++++++++++ test/expected_dir/b.bfpp | 54 ++++++++++++++++++ test/src_dir/b.bfpp | 54 ++++++++++++++++++ test/unit/parser_test.h | 2 + test/unit/parsers/test_bfpp.h | 19 +++++++ 6 files changed, 257 insertions(+) create mode 100644 src/parsers/bfpp.rl create mode 100644 test/expected_dir/b.bfpp create mode 100644 test/src_dir/b.bfpp create mode 100644 test/unit/parsers/test_bfpp.h diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index 00f0eb3..4dfddf6 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -9,6 +9,7 @@ #include "../parsers/blitzmax.h" #include "../parsers/boo.h" #include "../parsers/brainfuck.h" +#include "../parsers/bfpp.h" #include "../parsers/c.h" #include "../parsers/classic_basic.h" #include "../parsers/clearsilver.h" @@ -90,6 +91,7 @@ bat, parse_bat blitzmax, parse_blitzmax boo, parse_boo brainfuck, parse_brainfuck +bfpp, parse_bfpp c, parse_c cmake, parse_cmake classic_basic, parse_classic_basic diff --git a/src/parsers/bfpp.rl b/src/parsers/bfpp.rl new file mode 100644 index 0000000..fcb029e --- /dev/null +++ b/src/parsers/bfpp.rl @@ -0,0 +1,126 @@ +// bfpp.rl written by Boris 'billiob' Faure billiobgmailcom + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_BFPP_PARSER_H +#define OHCOUNT_BFPP_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *BFPP_LANG = LANG_BFPP; + +// the languages entities +const char *bfpp_entities[] = { + "space", "comment", "operator", "include" +}; + +// constants associated with the entities +enum { + BFPP_SPACE = 0, BFPP_COMMENT, BFPP_OPERATOR, BFPP_INCLUDE +}; + +/*****************************************************************************/ + +%%{ + machine bfpp; + write data; + include common "common.rl"; + + # Line counting machine + + action bfpp_ccallback { + switch(entity) { + case BFPP_SPACE: + ls + break; + case BFPP_OPERATOR: + case BFPP_INCLUDE: + code + break; + case BFPP_COMMENT: + comment + break; + case INTERNAL_NL: + std_internal_newline(BFPP_LANG) + break; + case NEWLINE: + std_newline(BFPP_LANG) + } + } + + bfpp_operator = [+\-<>.,\[\]\%\!\#\^\:\;] @code; + + bfpp_line_comment = ('=') @comment nonnewline*; + + bfpp_include = '@include(' @code ( + newline %{ entity = INTERNAL_NL; } %bfpp_ccallback + | + ws + | + (nonnewline - ws) @code + )* :>> ')'; + + bfpp_line := |* + spaces ${ entity = BFPP_SPACE; } => bfpp_ccallback; + newline ${ entity = NEWLINE; } => bfpp_ccallback; + bfpp_line_comment; + bfpp_include; + bfpp_operator ${ entity = BFPP_OPERATOR; } => bfpp_ccallback; + ^space ${ entity = BFPP_COMMENT; } => bfpp_ccallback; + *|; + + # Entity machine + + action bfpp_ecallback { + callback(BFPP_LANG, bfpp_entities[entity], cint(ts), cint(te), userdata); + } + + bfpp_operator_entity = [+\-<>.,\[\]%\#^;:]; + + bfpp_include_entity = '@include(' any* :>> ')'; + + bfpp_line_comment_entity = '=' (escaped_newline | nonnewline)*; + + bfpp_comment_entity = (bfpp_line_comment_entity | + !(space | bfpp_operator_entity | bfpp_include_entity)); + + bfpp_entity := |* + space+ ${ entity = BFPP_SPACE; } => bfpp_ecallback; + bfpp_operator_entity ${ entity = BFPP_OPERATOR; } => bfpp_ecallback; + bfpp_include_entity ${ entity = BFPP_INCLUDE; } => bfpp_ecallback; + bfpp_comment_entity ${ entity = BFPP_COMMENT; } => bfpp_ecallback; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with Brainfuck++ code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_bfpp(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + %% write init; + cs = (count) ? bfpp_en_bfpp_line : bfpp_en_bfpp_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(BFPP_LANG) } +} + +#endif + +/*****************************************************************************/ + diff --git a/test/expected_dir/b.bfpp b/test/expected_dir/b.bfpp new file mode 100644 index 0000000..b3a4ce6 --- /dev/null +++ b/test/expected_dir/b.bfpp @@ -0,0 +1,54 @@ +bfpp blank +bfpp comment = comment +bfpp code >++++++[>+++[<<++++>>-]<-]<. +bfpp code >+++++[<++++++>-]<-. +bfpp code +++++++. +bfpp code . +bfpp code +++. +bfpp code >>++++[<++++++>-]<++[<--->-]<-. +bfpp code >>++[<+++++>-]<+[<+++++>-]<. +bfpp code >++++[<++++++>-]<. +bfpp code +++. +bfpp code ------. +bfpp code >++[<---->-]<. +bfpp code >>++++[<++++>-]<+[<---->-]<. +bfpp code >+++++++[<++++++>-]<-. +bfpp code >++++++[<++++++>-]<+. +bfpp code >>++++[<++++++>-]<++[<--->-]<. +bfpp code >+++++[<+++++++>-]<-. +bfpp code >++++[>++++[<<+++>>-]<-]<. +bfpp code >++++[<---->-]<-. +bfpp code >++[<++++>-]<. +bfpp code +++++. +bfpp code >++[<---->-]<. +bfpp code >+++[<+++++>-]<. +bfpp code >+++[<------>-]<. +bfpp code >++[<++++>-]<. +bfpp code >++++[>++++[<<---->>-]<-]<. +bfpp code . +bfpp code >++[<----->-]<. +bfpp code . +bfpp code . +bfpp code . +bfpp code . +bfpp code [-] +bfpp comment = [-] is used to clear a cell +bfpp blank +bfpp comment = Try to open b file +bfpp code >+++++++[>+++++++[<<++>>-]<-]<. +bfpp code #[ +bfpp code >>++++[<++++>-]<+[<++++++>-]<. +bfpp code +++. +bfpp code +++. +bfpp code -------. +bfpp code >>++++[<++++++>-]<-[<--->-]<. +bfpp code >>++[<+++++>-]<+[<++++++>-]<. +bfpp code >>++[<+++++>-]<+[<------>-]<. +bfpp code >>++++[<++++++>-]<++[<+++>-]<+. +bfpp code +. +bfpp code >++[<----->-]<-. +bfpp code >+++[<+++>-]<. +bfpp code >+++[<--->-]<. +bfpp code -. +bfpp code #] +bfpp code @include(nothing.bfpp) diff --git a/test/src_dir/b.bfpp b/test/src_dir/b.bfpp new file mode 100644 index 0000000..90d2653 --- /dev/null +++ b/test/src_dir/b.bfpp @@ -0,0 +1,54 @@ + += comment +>++++++[>+++[<<++++>>-]<-]<. +>+++++[<++++++>-]<-. ++++++++. +. ++++. +>>++++[<++++++>-]<++[<--->-]<-. +>>++[<+++++>-]<+[<+++++>-]<. +>++++[<++++++>-]<. ++++. +------. +>++[<---->-]<. +>>++++[<++++>-]<+[<---->-]<. +>+++++++[<++++++>-]<-. +>++++++[<++++++>-]<+. +>>++++[<++++++>-]<++[<--->-]<. +>+++++[<+++++++>-]<-. +>++++[>++++[<<+++>>-]<-]<. +>++++[<---->-]<-. +>++[<++++>-]<. ++++++. +>++[<---->-]<. +>+++[<+++++>-]<. +>+++[<------>-]<. +>++[<++++>-]<. +>++++[>++++[<<---->>-]<-]<. +. +>++[<----->-]<. +. +. +. +. +[-] + = [-] is used to clear a cell + += Try to open b file +>+++++++[>+++++++[<<++>>-]<-]<. +#[ + >>++++[<++++>-]<+[<++++++>-]<. + +++. + +++. + -------. + >>++++[<++++++>-]<-[<--->-]<. + >>++[<+++++>-]<+[<++++++>-]<. + >>++[<+++++>-]<+[<------>-]<. + >>++++[<++++++>-]<++[<+++>-]<+. + +. + >++[<----->-]<-. + >+++[<+++>-]<. + >+++[<--->-]<. + -. +#] +@include(nothing.bfpp) diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index 79c58ae..20d96d3 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -84,6 +84,7 @@ void test_parser_verify_entity(SourceFile *sf, const char *entity, #include "parsers/test_blitzmax.h" #include "parsers/test_boo.h" #include "parsers/test_brainfuck.h" +#include "parsers/test_bfpp.h" #include "parsers/test_c.h" #include "parsers/test_clearsilvertemplate.h" #include "parsers/test_clearsilver.h" @@ -257,6 +258,7 @@ void all_parser_tests() { all_blitzmax_tests(); all_boo_tests(); all_brainfuck_tests(); + all_bfpp_tests(); all_c_tests(); all_clearsilver_template_tests(); all_clearsilver_tests(); diff --git a/test/unit/parsers/test_bfpp.h b/test/unit/parsers/test_bfpp.h new file mode 100644 index 0000000..cef3077 --- /dev/null +++ b/test/unit/parsers/test_bfpp.h @@ -0,0 +1,19 @@ +void test_bfpp_comment() { + test_parser_verify_parse( + test_parser_sourcefile("bfpp", " = comment"), + "bfpp", "", "= comment", 0 + ); +} + +void test_bfpp_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("bfpp", " = comment"), + " comment", "= comment" + ); +} + +void all_bfpp_tests() { + test_bfpp_comment(); + test_bfpp_comment_entities(); +} + From c7863a2fa9eb2e4d592431c22cd808b1b8ae61f5 Mon Sep 17 00:00:00 2001 From: Boris 'billiob' Faure Date: Tue, 29 Dec 2009 18:55:10 +0100 Subject: [PATCH 265/387] [NEW] detect the WTF Public License --- src/licenses.c | 10 ++++++++++ src/licenses.h | 1 + test/expected_licenses/wtfpl | 1 + test/src_licenses/wtfpl.c | 1 + 4 files changed, 13 insertions(+) create mode 100644 test/expected_licenses/wtfpl create mode 100644 test/src_licenses/wtfpl.c diff --git a/src/licenses.c b/src/licenses.c index f0cd90f..6cbaae6 100644 --- a/src/licenses.c +++ b/src/licenses.c @@ -720,6 +720,16 @@ License license_map[] = { PCRE_MULTILINE, NULL, NULL }, + { + LIC_WTFPL2, + "", + "WTF Public License", + "(\\bwtfpl\\b)|(\\bwtf\\s*public\\s*license\\b)|(\\b(do\\s*)?what\\s*the\\s*\\fuck\\s*public\\s*license\\b)", + PCRE_CASELESS, + NULL, + 0, + NULL, NULL + }, { NULL, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL }, }; int license_map_length = 0; // will be set dynamically diff --git a/src/licenses.h b/src/licenses.h index cc8acee..82dc149 100644 --- a/src/licenses.h +++ b/src/licenses.h @@ -95,6 +95,7 @@ #define LIC_APACHE_ISH "apache_ish" #define LIC_BSD_ISH "bsd_ish" #define LIC_BSD_2CLAUSE_ISH "bsd_2clause_ish" +#define LIC_WTFPL2 "wtfpl_2" /** * Attempts to detect the source code licenses for a given file. diff --git a/test/expected_licenses/wtfpl b/test/expected_licenses/wtfpl new file mode 100644 index 0000000..c0f1ca9 --- /dev/null +++ b/test/expected_licenses/wtfpl @@ -0,0 +1 @@ +wtfpl_2 diff --git a/test/src_licenses/wtfpl.c b/test/src_licenses/wtfpl.c new file mode 100644 index 0000000..443cfe6 --- /dev/null +++ b/test/src_licenses/wtfpl.c @@ -0,0 +1 @@ +// Do What The Fuck you Want to Public License 2 (WTFPL) From ce08d14ebe1ac2587d6162540b69d2d799db421d Mon Sep 17 00:00:00 2001 From: Guilherme Balena Versiani Date: Tue, 5 Jan 2010 20:12:52 -0200 Subject: [PATCH 266/387] Bundle of modifications done to ohcount to support Python only (no dependencies made to CMake, the building are done using default Python building using setup.py file). MinGW/MSYS and Windows compiling and fixes were applied too. --- .gitignore | 2 + mingw_setup.py | 100 +++++++++++++++++ python/__init__.py | 234 ++++++++++++++++++++++++++++++++++++++++ ruby/ohcount.i | 173 +++++++++++++++++++++++++++++ setup.py | 146 +++++++++++++++++++++++++ src/detector.c | 5 + src/diff.c | 5 + src/ohcount.c | 2 +- src/sourcefile.c | 16 +-- test/unit/license_test.h | 2 +- test/unit/parser_test.h | 2 +- test/unit/python/python_test.py | 68 ++++++++++++ 12 files changed, 745 insertions(+), 10 deletions(-) create mode 100644 mingw_setup.py create mode 100644 python/__init__.py create mode 100644 setup.py create mode 100644 test/unit/python/python_test.py diff --git a/.gitignore b/.gitignore index 8d60fe3..7573c6f 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ bin/ ruby/ohcount.so ruby/ohcount_wrap.c test/unit/run_tests.dSYM/ +build-python/ +python/ohcount.py diff --git a/mingw_setup.py b/mingw_setup.py new file mode 100644 index 0000000..1be8a29 --- /dev/null +++ b/mingw_setup.py @@ -0,0 +1,100 @@ +#=== mingw_setup.py by Phillip J. Eby +"""Create pythonNN.def and libpythonNN.a in 'PythonNN/libs' directory + +This script makes it possible to use the MinGW compiler tools to +build C extensions that work with the standard Windows Python +distribution. + +Before running, you should have installed the MinGW compiler toolset, +and placed its 'bin' directory on your PATH. An easy way to do this +is to install Cygwin's "binutils", "gcc", and "mingw-*" packages, +then run this script from the Cygwin shell. (Be sure to use *Windows* +Python, not Cygwin python!) + +Once this script has been run, you should be able to build extensions +using distutils in the standard way, as long as you select the +'mingw32' compiler, and the required tools are on your PATH. See +the "Installing Python Modules" manual for more information on +selecting a compiler. +""" + + +from distutils.spawn import find_executable +from distutils.sysconfig import get_config_var +from distutils import __file__ as distutils_file +import os, re, sys + +if sys.platform=='cygwin': + print "Please run this script using Windows python,", + print "not Cygwin python. E.g, try:" + print + print "/cygdrive/c/PythonNN/python", " ".join(sys.argv) + print + print "(where NN is the major/minor python version number)" + sys.exit() + +basename = 'python%d%d' % sys.version_info[:2] + +libs_dir = os.path.join(get_config_var('prefix'),'libs') +lib_file = os.path.join(libs_dir,basename+'.lib') +def_file = os.path.join(libs_dir,basename+'.def') +ming_lib = os.path.join(libs_dir,'lib%s.a' % basename) + +distutils_cfg = os.path.join(os.path.dirname(distutils_file),'distutils.cfg') + +export_match = re.compile(r"^_imp__(.*) in python\d+\.dll").match + +nm = find_executable('nm') +dlltool = find_executable('dlltool') + +if not nm or not dlltool: + print "'nm' and/or 'dlltool' were not found;" + print "Please make sure they're on your PATH." + sys.exit() + +nm_command = '%s -Cs %s' % (nm, lib_file) + +print "Building", def_file, "using", nm_command +f = open(def_file,'w') +print >>f, "LIBRARY %s.dll" % basename +print >>f, "EXPORTS" + + +nm_pipe = os.popen(nm_command) +for line in nm_pipe.readlines(): + m = export_match(line) + if m: + print >>f, m.group(1) +f.close() + +exit = nm_pipe.close() +if exit: + print "nm exited with status", exit + print "Please check that", lib_file, "exists and is valid." + sys.exit() + + +print "Building",ming_lib,"using",dlltool +dlltool_pipe = os.popen( + "%s --dllname %s.dll --def %s --output-lib %s" % + (dlltool, basename, def_file, ming_lib) +) + +dlltool_pipe.readlines() +exit = dlltool_pipe.close() +if exit: + print "dlltool exited with status", exit + print "Unable to proceed." + sys.exit() + +print +print "Installation complete. You may wish to add the following" +print "lines to", distutils_cfg, ':' +print +print "[build]" +print "compiler = mingw32" +print +print "This will make the distutils use MinGW as the default" +print "compiler, so that you don't need to configure this for" +print "every 'setup.py' you run." + diff --git a/python/__init__.py b/python/__init__.py new file mode 100644 index 0000000..d84397d --- /dev/null +++ b/python/__init__.py @@ -0,0 +1,234 @@ +import os, collections +from abc import abstractmethod +import ohcount + +class _OhcountBase(object): + + def __init__(self, base): + self._base = base + + def __getattr__(self, name): + if name == '_base': + return object.__getattr__(self, name) + raise AttributeError + + def __setattr__(self, name, value): + if name == '_base': + return object.__setattr__(self, name, value) + raise AttributeError + +class _OhcountDict(_OhcountBase, collections.Mapping, collections.KeysView): + + def __init__(self, base, mapping): + _OhcountBase.__init__(self, base) + collections.KeysView.__init__(self, mapping) + + def __getattr__(self, name): + if name == '_mapping': + return collections.KeysView.__getattr__(self, name) + try: + return _OhcountBase.__getattr__(self, name) + except AttributeError: + try: + return self.__getitem__(name) + except KeyError: + raise AttributeError + except: + raise + + def __setattr__(self, name, value): + if name == '_mapping': + return collections.KeysView.__setattr__(self, name, value) + try: + return _OhcountBase.__setattr__(self, name, value) + except AttributeError: + try: + return self.__setitem__(name, value) + except KeyError: + raise AttributeError + except: + raise + + def keys(self): + return self._mapping + + def __setitem__(self, key, item): + raise KeyError + + def __delitem__(self, key): + raise KeyError + + def __str__(self): + return dict([(key, self[key]) for key in self.keys()]).__str__() + + def iterkeys(self): + return iter(self.keys()) + + def itervalues(self): + for key in self.keys(): + yield self[key] + + def iteritems(self): + for key in self.keys(): + yield (key, self[key]) + + def items(self): + return [(key, self[key]) for key in self.keys()] + + def values(self): + return [self[key] for key in self.keys()] + +class _OhcountList(_OhcountBase): + + @abstractmethod + def _get_value(self, inner): + raise NotImplementedError + + def __len__(self): + count = 0 + for e in self: + count += 1 + return count + + def __iter__(self): + return self.next() + + def next(self): + iter = self._base.head + while iter is not None: + yield self._get_value(iter) + iter = iter.next + + def __str__(self): + return [v for v in self].__str__() + +class License(_OhcountDict): + + def __init__(self, base): + _OhcountDict.__init__(self, base, + ['name','url','nice_name']) + + def __getitem__(self, key): + if key == 'name': + return self._base.name + if key == 'url': + return self._base.url + if key == 'nice_name': + return self._base.nice_name + raise KeyError + +class Loc(_OhcountDict): + + def __init__(self, base): + _OhcountDict.__init__(self, base, + ['lang','code','comments','blanks','filecount','total']) + + def __getitem__(self, key): + if key == 'lang' or key == 'language': + return self._base.language + if key == 'code': + return self._base.code + if key == 'comments': + return self._base.comments + if key == 'blanks': + return self._base.blanks + if key == 'filecount': + return self._base.filecount + if key == 'total': + return self._base.total() + raise KeyError + +class LocList(_OhcountDict, _OhcountList): + + def __init__(self, base): + _OhcountDict.__init__(self, base, + ['code','comments','blanks','filecount','total']) + + def _get_value(self, inner): + return Loc(inner.loc) + + def __getitem__(self, key): + if key == 'code': + return self._base.code() + if key == 'comments': + return self._base.comments() + if key == 'blanks': + return self._base.blanks() + if key == 'filecount': + return self._base.filecount() + if key == 'total': + return self._base.total() + raise KeyError + + def __str__(self): + return _OhcountDict.__str__(self) + + def compact(self): + return LocList(self._base.compact()) + +class SourceFile(_OhcountDict): + + def __init__(self, base): + _OhcountDict.__init__(self, base, + ['filepath','filename','ext','contents','size','language', + 'licenses','locs']) + + def _get_licenses(self): + result = [] + list = self._base.get_license_list() + if list is not None: + iter = list.head + while iter is not None: + result.append(License(iter.lic)) + iter = iter.next + return result + + def _get_locs(self): + return LocList(self._base.get_loc_list()) + + def __getitem__(self, key): + if key == 'filepath': + return self._base.filepath + if key == 'filename': + return self._base.filename + if key == 'ext': + return self._base.ext + if key == 'contents': + return self._base.get_contents() + if key == 'size': + return self._base.contents_size() + if key == 'language': + return self._base.get_language() + if key == 'licenses': + return self._get_licenses() + if key == 'locs': + return self._get_locs() + raise AttributeError + + def annotate(self): + return self._base.annotate() + + def raw_entities(self): + return self._base.raw_entities() + +class SourceFileList(_OhcountList): + + def __init__(self, **kwargs): + _OhcountList.__init__(self, ohcount.SourceFileList(kwargs)) + + def _get_value(self, inner): + return SourceFile(inner.sf) + + def analyze_languages(self): + return LocList( self._base.analyze_languages() ) + + def add_directory(self, path): + if not os.path.isdir(path): + raise SyntaxError('Input path is not a directory: %s' % path) + self._base.add_directory(path) + + def add_file(self, filepath): + if not os.path.isfile(filepath): + raise SyntaxError('Input path is not a file: %s' % filepath) + self._base.add_file(filepath) + diff --git a/ruby/ohcount.i b/ruby/ohcount.i index f0b4004..6b7dcf8 100644 --- a/ruby/ohcount.i +++ b/ruby/ohcount.i @@ -8,6 +8,8 @@ %include typemaps.i +#if defined(SWIGRUBY) + %typemap(in) (register const char *str, register unsigned int len) { Check_Type($input, T_STRING); $1 = STR2CSTR($input); @@ -22,12 +24,60 @@ $result = arr; }; +#elif defined(SWIGPYTHON) + +%typemap(in) (register const char *str, register unsigned int len) { + if (!PyString_Check($input)) { + PyErr_SetString(PyExc_SyntaxError, "Invalid parameter"); + return NULL; + } + $1 = PyString_AsString($input); + $2 = PyString_Size($input); +}; + +%typemap(out) char ** { + int i; + PyObject *arr = PyList_New(0); + for (i = 0; $1[i] != NULL; i++) + PyList_Append(arr, PyString_FromString($1[i])); + $result = arr; +}; + + +#else +#error "You should define specific translation rules for this language." +#endif + %nodefaultctor SourceFile; %immutable; %include "../src/languages.h" %include "../src/structs.h" %mutable; +%extend Loc { + int total() { + return ohcount_loc_total(self); + } +} + +%extend LocList { + int code() { + return ohcount_loc_list_code(self); + } + int comments() { + return ohcount_loc_list_comments(self); + } + int blanks() { + return ohcount_loc_list_blanks(self); + } + int total() { + return ohcount_loc_list_total(self); + } + int filecount() { + return ohcount_loc_list_filecount(self); + } +} + %extend SourceFile { void set_diskpath(const char *diskpath) { ohcount_sourcefile_set_diskpath(self, diskpath); @@ -59,6 +109,7 @@ LocDeltaList *_diff(SourceFile *to) { return ohcount_sourcefile_diff(self, to); } +#if defined(SWIGRUBY) void set_filenames(VALUE filenames) { int i, length = RARRAY(filenames)->len; char **fnames = calloc(length + 1, sizeof(char *)); @@ -84,17 +135,92 @@ } return sourcefile; } +#elif defined(SWIGPYTHON) + void set_filenames(PyObject *filenames) { + int i, length; + char **fnames; + if (!PyList_Check(filenames)) { + PyErr_SetString(PyExc_SyntaxError, "Invalid parameter, expected a list of strings"); + return; + } + length = PyList_Size(filenames); + fnames = calloc(length + 1, sizeof(char *)); + for (i = 0; i < length; i++) { + PyObject *s = PyList_GetItem(filenames, i); + if (!PyString_Check(s)) { + PyErr_SetString(PyExc_SyntaxError, "Invalid parameter, expected a list of strings"); + return; + } + fnames[i] = PyString_AsString(s); + } + ohcount_sourcefile_set_filenames(self, fnames); + free(fnames); + } + static void py_annotate_callback(const char *language, const char *entity, + int start, int end, void *userdata) { + PyObject *list = (PyObject *) userdata; + PyObject *dict = PyDict_New(); + PyDict_SetItem(dict, PyString_FromString("language"), + PyString_FromString(language)); + PyDict_SetItem(dict, PyString_FromString("entity"), + PyString_FromString(entity)); + PyDict_SetItem(dict, PyString_FromString("start"), + PyInt_FromLong(start)); + PyDict_SetItem(dict, PyString_FromString("end"), + PyInt_FromLong(end)); + PyList_Append(list, dict); + } + PyObject *annotate() { + PyObject *list = PyList_New(0); + ohcount_sourcefile_parse_with_callback(self, SourceFile_py_annotate_callback, list); + return list; + } + PyObject *raw_entities() { + PyObject *list = PyList_New(0); + ohcount_sourcefile_parse_entities_with_callback(self, SourceFile_py_annotate_callback, list); + return list; + } + SourceFile(const char *filepath, PyObject *args) { + SourceFile *sourcefile = ohcount_sourcefile_new(filepath); + if (args) { + PyObject *val; + if (!PyDict_Check(args)) { + PyErr_SetString(PyExc_SyntaxError, "Invalid argument"); + ohcount_sourcefile_free(sourcefile); + return NULL; + } + val = PyDict_GetItem(args, PyString_FromString("contents")); + if (val && PyString_Check(val)) + ohcount_sourcefile_set_contents(sourcefile, PyString_AsString(val)); + val = PyDict_GetItem(args, PyString_FromString("file_location")); + if (val && PyString_Check(val)) + ohcount_sourcefile_set_diskpath(sourcefile, PyString_AsString(val)); + val = PyDict_GetItem(args, PyString_FromString("filenames")); + if (val && PyString_Check(val)) + SourceFile_set_filenames(sourcefile, val); + } + return sourcefile; + } + +#endif ~SourceFile() { ohcount_sourcefile_free(self); } }; %extend SourceFileList { +#if defined(SWIGRUBY) + static VALUE rb_add_directory(VALUE directory, SourceFileList *list) { if (directory && rb_type(directory) == T_STRING) ohcount_sourcefile_list_add_directory(list, STR2CSTR(directory)); return Qnil; } + static VALUE rb_add_file(VALUE file, SourceFileList *list) { + if (file && rb_type(file) == T_STRING) + ohcount_sourcefile_list_add_file(list, STR2CSTR(file)); + return Qnil; + } SourceFileList(VALUE opt_hash=NULL) { SourceFileList *list = ohcount_sourcefile_list_new(); if (opt_hash) { @@ -102,9 +228,56 @@ val = rb_hash_aref(opt_hash, ID2SYM(rb_intern("paths"))); if (val && rb_type(val) == T_ARRAY) rb_iterate(rb_each, val, SourceFileList_rb_add_directory, (VALUE)list); + val = rb_hash_aref(opt_hash, ID2SYM(rb_intern("files"))); + if (val && rb_type(val) == T_ARRAY) + rb_iterate(rb_each, val, SourceFileList_rb_add_file, (VALUE)list); } return list; } + +#elif defined(SWIGPYTHON) + + SourceFileList(PyObject *args) { + SourceFileList *list = ohcount_sourcefile_list_new(); + if (args) { + PyObject *val; + if (!PyDict_Check(args)) { + PyErr_SetString(PyExc_SyntaxError, "Invalid argument"); + ohcount_sourcefile_list_free(list); + return NULL; + } + val = PyDict_GetItem(args, PyString_FromString("paths")); + if (val && PyList_Check(val)) { + int i, length = PyList_Size(val); + for (i = 0; i < length; i++) { + PyObject *s = PyList_GetItem(val, i); + if (!PyString_Check(s)) { + PyErr_SetString(PyExc_SyntaxError, "Invalid 'paths', expected a list of strings"); + ohcount_sourcefile_list_free(list); + return NULL; + } + ohcount_sourcefile_list_add_directory(list, PyString_AsString(s)); + } + } + val = PyDict_GetItem(args, PyString_FromString("files")); + if (val && PyList_Check(val)) { + int i, length = PyList_Size(val); + for (i = 0; i < length; i++) { + PyObject *s = PyList_GetItem(val, i); + if (!PyString_Check(s)) { + PyErr_SetString(PyExc_SyntaxError, "Invalid 'files', expected a list of strings"); + ohcount_sourcefile_list_free(list); + return NULL; + } + ohcount_sourcefile_list_add_file(list, PyString_AsString(s)); + } + } + } + return list; + } + +#endif + ~SourceFileList() { ohcount_sourcefile_list_free(self); } diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..5c78c60 --- /dev/null +++ b/setup.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python + +import distutils.ccompiler +from distutils.core import setup, Extension +from distutils.command.build import build +from distutils.command.build_ext import build_ext +from distutils.command.install_lib import install_lib +import os, sys +from glob import glob + +if not hasattr(sys, 'version_info') or sys.version_info < (2,6,0,'final'): + raise SystemExit("Ohcount requires Python 2.6 or later.") + +class build_ohcount(build): + """Ohcount already have a script named 'build', from the original package, + so it conflicts with Python default build path. To solve this, setup.py + will use the directory 'build-python' instead. The original distutils + execute 'build_py' before 'build_ext', but we need the wrapper ohcount.py + created by SWIG to be installed too, so we need to invert this order. + """ + + sub_commands = [('build_ext', build.has_ext_modules), # changed + ('build_py', build.has_pure_modules), # changed + ('build_clib', build.has_c_libraries), + ('build_scripts', build.has_scripts), + ] + + def initialize_options(self): + build.initialize_options(self) + self.build_base = 'build-python' + +def newer_than(srclist, dstlist): + for left, right in zip(srclist, dstlist): + if not os.path.exists(right): + return True + left_stat = os.lstat(left) + right_stat = os.lstat(right) + if left_stat.st_mtime > right_stat.st_mtime: + return True + return False + +class build_ohcount_ext(build_ext): + """This class implements extra steps needed by Ohcount build process.""" + + def run(self): + parsers = glob('src/parsers/*.rl') + parsers_h = [f.replace('.rl', '.h') for f in parsers] + if newer_than(parsers, parsers_h): + os.system('cd src/parsers/ && bash ./compile') + hash_files = glob('src/hash/*.gperf') + hash_srcs = [] + for f in hash_files: + if not f.endswith('languages.gperf'): + hash_srcs.append(f.replace('s.gperf', '_hash.h')) + else: + hash_srcs.append(f.replace('s.gperf', '_hash.c')) + if newer_than(hash_files, hash_srcs): + os.system('cd src/hash/ && bash ./generate_headers') + return build_ext.run(self) + +# Overwrite default Mingw32 compiler +(module_name, class_name, long_description) = \ + distutils.ccompiler.compiler_class['mingw32'] +module_name = "distutils." + module_name +__import__(module_name) +module = sys.modules[module_name] +Mingw32CCompiler = vars(module)[class_name] + +class Mingw32CCompiler_ohcount(Mingw32CCompiler): + """Ohcount CCompiler version for Mingw32. There is a problem linking + against msvcrXX for Python 2.6.4: as both DLLs msvcr and msvcr90 are + loaded, it seems to happen some unexpected segmentation faults in + several function calls.""" + + def __init__(self, *args, **kwargs): + Mingw32CCompiler.__init__(self, *args, **kwargs) + self.dll_libraries=[] # empty link libraries list + +_new_compiler = distutils.ccompiler.new_compiler + +def ohcount_new_compiler(plat=None,compiler=None,verbose=0,dry_run=0,force=0): + if compiler == 'mingw32': + inst = Mingw32CCompiler_ohcount(None, dry_run, force) + else: + inst = _new_compiler(plat,compiler,verbose,dry_run,force) + return inst + +distutils.ccompiler.new_compiler = ohcount_new_compiler + +# Ohcount python extension +ext_modules=[ + Extension( + name='ohcount._ohcount', + sources= [ + 'ruby/ohcount.i', + 'src/sourcefile.c', + 'src/detector.c', + 'src/licenses.c', + 'src/parser.c', + 'src/loc.c', + 'src/log.c', + 'src/diff.c', + 'src/parsed_language.c', + 'src/hash/language_hash.c', + ], + libraries=['pcre'], + swig_opts=['-outdir', './python/'], + ) +] + +setup( + name='ohcount', + version = '3.0.0', + description = 'Ohcount is the source code line counter that powers Ohloh.', + long_description = + 'Ohcount supports over 70 popular programming languages, and has been ' + 'used to count over 6 billion lines of code by 300,000 developers! ' + 'Ohcount does more more than just count lines of code. It can also ' + 'detect popular open source licenses such as GPL within a large ' + 'directory of source code. It can also detect code that targets a ' + 'particular programming API, such as Win32 or KDE.', + author = 'Mitchell Foral', + author_email = 'mitchell@caladbolg.net', + license = 'GNU GPL', + platforms = ['Linux','Mac OSX'], + keywords = ['ohcount','ohloh','loc','source','code','line','counter'], + url = 'http://www.ohloh.net/p/ohcount', + download_url = 'http://sourceforge.net/projects/ohcount/files/', + packages = ['ohcount'], + package_dir = {'ohcount': 'python'}, + classifiers = [ + 'Development Status :: 5 - Production/Stable', + 'License :: OSI Approved :: GNU General Public License (GPL)' + 'Intended Audience :: Developers', + 'Natural Language :: English', + 'Programming Language :: C', + 'Programming Language :: Python', + 'Topic :: Software Development :: Libraries :: Python Modules', + ], + ext_modules=ext_modules, + cmdclass={ + 'build': build_ohcount, + 'build_ext': build_ohcount_ext, + }, +) + diff --git a/src/detector.c b/src/detector.c index a42972c..ea1b187 100644 --- a/src/detector.c +++ b/src/detector.c @@ -20,6 +20,11 @@ #define ISAMBIGUOUS(x) (x[0] == '\2') #define DISAMBIGUATEWHAT(x) &x[1] +#ifdef _WIN32 +# include +# define mkstemp(p) _open(_mktemp(p), _O_CREAT | _O_SHORT_LIVED | _O_EXCL) +#endif + const char *ohcount_detect_language(SourceFile *sourcefile) { const char *language = NULL; char *p, *pe; diff --git a/src/diff.c b/src/diff.c index 1aa6bcf..5465c9d 100644 --- a/src/diff.c +++ b/src/diff.c @@ -2,6 +2,11 @@ #include #include +#ifdef _WIN32 +# include +# define mkstemp(p) _open(_mktemp(p), _O_CREAT | _O_SHORT_LIVED | _O_EXCL) +#endif + /* * The bulk of this software is derived from Plan 9 and is thus distributed * under the Lucent Public License, Version 1.02, reproduced below. diff --git a/src/ohcount.c b/src/ohcount.c index 4a0bb72..c115dc7 100644 --- a/src/ohcount.c +++ b/src/ohcount.c @@ -272,7 +272,7 @@ int main(int argc, char *argv[]) { ohcount_sourcefile_list_add_directory(list, argv[i]); closedir(dir); } else { - FILE *f = fopen(argv[i], "r"); + FILE *f = fopen(argv[i], "rb"); if (f) { ohcount_sourcefile_list_add_file(list, argv[i]); fclose(f); diff --git a/src/sourcefile.c b/src/sourcefile.c index a46f755..9706c06 100644 --- a/src/sourcefile.c +++ b/src/sourcefile.c @@ -6,6 +6,10 @@ #include #include +#include +#include +#include + #include "detector.h" #include "diff.h" #include "languages.h" @@ -80,7 +84,7 @@ char *ohcount_sourcefile_get_contents(SourceFile *sourcefile) { char *path = sourcefile->filepath; if (sourcefile->diskpath) path = sourcefile->diskpath; - FILE *f = fopen(path, "r"); + FILE *f = fopen(path, "rb"); if (f) { fseek(f, 0, SEEK_END); int size = ftell(f); @@ -432,17 +436,15 @@ void ohcount_sourcefile_list_add_directory(SourceFileList *list, DIR *d = opendir(directory); if (d) { while ((file = readdir(d))) { + struct stat st; int length = strlen(file->d_name); strncpy(f_p, (const char *)file->d_name, length); *(f_p + length) = '\0'; - if (file->d_type == DT_DIR && *file->d_name != '.') // no hidden dirs + stat(filepath, &st); + if (S_ISDIR(st.st_mode) && *file->d_name != '.') // no hidden dirs ohcount_sourcefile_list_add_directory(list, filepath); - else if (file->d_type == DT_REG -#ifdef TMP_FILES_ARE_DT_UNKNOWN - || file->d_type == DT_UNKNOWN -#endif - ) + else if (S_ISREG(st.st_mode)) ohcount_sourcefile_list_add_file(list, filepath); } closedir(d); diff --git a/test/unit/license_test.h b/test/unit/license_test.h index b804f37..8977e8f 100644 --- a/test/unit/license_test.h +++ b/test/unit/license_test.h @@ -37,7 +37,7 @@ void src_vs_expected_tests() { length = p - file->d_name; strncpy(e_p, (const char *)file->d_name, length); *(e_p + length) = '\0'; - FILE *f = fopen((const char *)expected, "r"); + FILE *f = fopen((const char *)expected, "rb"); if (f) { SourceFile *sf = ohcount_sourcefile_new((const char *)src); LicenseList *iter = ohcount_sourcefile_get_license_list(sf)->head; diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index 23291de..ed2e3b1 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -202,7 +202,7 @@ void test_parser_verify_parses() { strncpy(e_p, (const char *)file->d_name, length); *(e_p + length) = '\0'; - FILE *f = fopen((const char *)expected, "r"); + FILE *f = fopen((const char *)expected, "rb"); if (f) { SourceFile *sf = ohcount_sourcefile_new((const char *)src); diff --git a/test/unit/python/python_test.py b/test/unit/python/python_test.py new file mode 100644 index 0000000..6fbe254 --- /dev/null +++ b/test/unit/python/python_test.py @@ -0,0 +1,68 @@ +import unittest +import ohcount + +class TestSourceFileList(unittest.TestCase): + + def setUp(self): + # must not raise + self.sf_list = ohcount.SourceFileList(paths=['../../gestalt_files']) + + def assertStrOp(self, obj, not_equals): + s = str(obj) + if not_equals: + for v in not_equals: + self.assertTrue(s is not v) + + def assertHasAttr(self, obj, name, not_equals=None): + self.assertTrue(hasattr(obj, name)) + if not_equals: + val = getattr(obj, name) + for v in not_equals: + self.assertTrue(val is not v) + + def assertHasItem(self, obj, name, not_equals=None): + self.assertTrue(name in obj) + if not_equals: + val = obj[name] + for v in not_equals: + self.assertTrue(val is not v) + + def assertHasItemAttr(self, obj, name, not_equals=None): + self.assertHasAttr(obj, name, not_equals) + self.assertHasItem(obj, name, not_equals) + + def assertHasKeys(self, obj, keylist): + for k in keylist: + self.assertTrue(k in obj) + + def assertListIsInstance(self, list, type): + for o in list: + self.assertTrue(isinstance(o, type)) + + def assertHasItemAttrs(self, obj, list, not_equals=None): + for name in list: + self.assertHasItemAttr(obj, name, not_equals) + + def testList(self): + self.assertTrue(len(self.sf_list) > 0) + self.assertListIsInstance(self.sf_list, ohcount.SourceFile) + + def testStr(self): + self.assertStrOp(self.sf_list, [None, ""]) + + def testAnalyzeLanguages(self): + locs = self.sf_list.analyze_languages() + self.assertTrue(isinstance(locs, ohcount.LocList)) + names = ['code','comments','blanks','filecount','total'] + self.assertHasKeys(locs, names) + self.assertHasItemAttrs(locs, names, [None, 0]) + self.assertListIsInstance(locs, ohcount.Loc) + + def testAddDirectory(self): + self.sf_list.add_directory('../../detect_files') # must not raise + + def testAddFile(self): + self.sf_list.add_file('../../src_licenses/academic_t1.c') # must not raise + +if __name__ == '__main__': + unittest.main() From edf2d305e3f6e6b8c3aab325e7cf3ec45f01ab51 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 8 Jan 2010 16:35:31 +0000 Subject: [PATCH 267/387] Change README to mention build process for ruby and python --- README | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README b/README index dfea440..0fd22fa 100644 --- a/README +++ b/README @@ -84,6 +84,11 @@ Once you've building ohcount, the executable program will be at bin/ohcount. The Particularly, for instructions on adding a new language, follow the instructions at doc/html/detector_doc.html Read http://labs.ohloh.net/ohcount/wiki/HowToSubmitPatches for information about having your patch accepted. +== Building language wrappers to use ohcount from Ruby or Python == + +To build the ruby wrapper, run "bash build ruby". +To build the python wrapper, run "python python/setup.py build; python python/setup.py install". The python wrapper is new and has only been tested on Gentoo and CentOS. Feedback on it is particularly welcome. + DEPENDENCIES ============ From 1e2cf61b8d043dbcf6d3372e861e6eb65155dc4c Mon Sep 17 00:00:00 2001 From: root Date: Fri, 8 Jan 2010 16:35:46 +0000 Subject: [PATCH 268/387] MOVE setup.py and mingw_setup.py to python/ dir --- mingw_setup.py => python/mingw_setup.py | 0 setup.py => python/setup.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename mingw_setup.py => python/mingw_setup.py (100%) rename setup.py => python/setup.py (100%) diff --git a/mingw_setup.py b/python/mingw_setup.py similarity index 100% rename from mingw_setup.py rename to python/mingw_setup.py diff --git a/setup.py b/python/setup.py similarity index 100% rename from setup.py rename to python/setup.py From edd1e370fb2cfa02d3be808b5cc25d33171bf941 Mon Sep 17 00:00:00 2001 From: Kovarththanan Rajaratnam Date: Tue, 26 Jan 2010 08:38:12 +0100 Subject: [PATCH 269/387] Doxygen: Point to SourceForge --- src/ohcount.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ohcount.h b/src/ohcount.h index f9f1182..6401bfd 100644 --- a/src/ohcount.h +++ b/src/ohcount.h @@ -124,7 +124,7 @@ * * @section contact Contact Ohloh * - * For more information visit the Ohloh website: http://labs.ohloh.net + * For more information visit the Ohloh website: https://sourceforge.net/projects/ohcount * * You can reach Ohloh via email at: info@ohloh.net */ From 9277558423e63161db7b2929493958be44feb2ca Mon Sep 17 00:00:00 2001 From: Kovarththanan Rajaratnam Date: Tue, 26 Jan 2010 08:43:08 +0100 Subject: [PATCH 270/387] Doxygen: document dependency to Bash --- src/ohcount.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ohcount.h b/src/ohcount.h index 6401bfd..27d0e92 100644 --- a/src/ohcount.h +++ b/src/ohcount.h @@ -64,6 +64,7 @@ * @li Ragel 6.3 or later - http://research.cs.queensu.ca/~thurston/ragel/ * @li GNU gperf - http://www.gnu.org/software/gperf/ * @li PCRE - http://pcre.sourceforge.net/ + * @li Bash - http://www.gnu.org/software/bash/ * * Run the 'build' script to build Ohcount. * From 60169ae7d987a0addc8530843744515061c0127c Mon Sep 17 00:00:00 2001 From: Kovarththanan Rajaratnam Date: Tue, 26 Jan 2010 08:51:28 +0100 Subject: [PATCH 271/387] Doxygen: document how to build the Doxygen docs --- src/ohcount.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/ohcount.h b/src/ohcount.h index 27d0e92..3024ec1 100644 --- a/src/ohcount.h +++ b/src/ohcount.h @@ -86,6 +86,15 @@ * You may then link or copy 'ruby/ohcount.{rb,so}' and 'ruby/gestalt{/,.rb}' * to the appropriate places in your Ruby installation. * + * Building the Doxygen docs requires: + * + * @li Doxygen - http://www.doxygen.org/ + * + * @code + * $ cd doc + * $ Doxygen Doxyfile + * @endcode + * * @section start First Steps * * To measure lines of code, simply pass file or directory names to the From 203649ac909d7849b25959f930cf9369d54f2fdd Mon Sep 17 00:00:00 2001 From: Kovarththanan Rajaratnam Date: Tue, 26 Jan 2010 09:03:32 +0100 Subject: [PATCH 272/387] build: remove workaround (preprocessor define) for bug on centos/SF servers This is no longer needed due to commit a2903082b8e57657b37d636d18afb5ad8de296c7 --- build | 1 - 1 file changed, 1 deletion(-) diff --git a/build b/build index 67cb333..e69c420 100755 --- a/build +++ b/build @@ -18,7 +18,6 @@ then # You shouldn't have to change the following. CFLAGS=-O3 - CFLAGS="$CFLAGS -DTMP_FILES_ARE_DT_UNKNOWN" # workaround bug on centos/SF servers WARN="-Wall -Wno-pointer-to-int-cast -Wno-parentheses" SHARED=-shared SHARED_NAME=libohcount.so From 199c8d896dd0e82f4f1a98795cb9da7da20a791a Mon Sep 17 00:00:00 2001 From: Pat Downey Date: Fri, 29 Jan 2010 14:42:02 -0800 Subject: [PATCH 273/387] [PATCH] Use pe pointer in disambiguate_st instead of p to prevent ohcount from segfaulting when processing a .st file that doesn't end in a new line. --- src/detector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detector.c b/src/detector.c index 1963bd4..e9e1e50 100644 --- a/src/detector.c +++ b/src/detector.c @@ -671,7 +671,7 @@ const char *disambiguate_st(SourceFile *sourcefile) { char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); while (pe < eof) { // Get a line at a time. - while (p < eof && *pe != '\r' && *pe != '\n') pe++; + while (pe < eof && *pe != '\r' && *pe != '\n') pe++; length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); strncpy(line, p, length); line[length] = '\0'; From 0abd7fd7b29f5732a3e967909a1a2228242837c7 Mon Sep 17 00:00:00 2001 From: abscondment Date: Mon, 8 Mar 2010 11:32:48 -0800 Subject: [PATCH 274/387] Add support and tests for the Clojure language, a dialect of LISP. --- src/hash/extensions.gperf | 1 + src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 1 + src/languages.h | 1 + src/parser.h | 2 +- src/parsers/lisp.rl | 11 +++++++++++ test/expected_dir/clj1.clj | 16 ++++++++++++++++ test/src_dir/clj1.clj | 16 ++++++++++++++++ test/unit/parser_test.h | 2 ++ test/unit/parsers/test_clojure.h | 19 +++++++++++++++++++ 10 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 test/expected_dir/clj1.clj create mode 100644 test/src_dir/clj1.clj create mode 100644 test/unit/parsers/test_clojure.h diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index f89cb4e..a805ab9 100644 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -32,6 +32,7 @@ c, LANG_C c++, LANG_CPP cache, BINARY cc, LANG_CPP +clj, LANG_CLOJURE cmake, LANG_CMAKE com, LANG_DCL cpp, LANG_CPP diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index b051cfb..cbae928 100644 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -18,6 +18,7 @@ c, LANG_C, "C", 0 classic_basic, LANG_CLASSIC_BASIC, "Classic Basic", 0 clearsilver, LANG_CLEARSILVER, "ClearSilver", 0 clearsilver_template, LANG_CLEARSILVER_TEMPLATE, "ClearSilver", 0 +clojure, LANG_CLOJURE, "Clojure", 0 cmake, LANG_CMAKE, "Cmake script", 2 cpp, LANG_CPP, "C++", 0 cs_aspx, LANG_CS_ASPX, "", 0 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index 4dfddf6..89cb60d 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -97,6 +97,7 @@ cmake, parse_cmake classic_basic, parse_classic_basic clearsilver, parse_clearsilver clearsilver_template, parse_cshtml +clojure, parse_clojure cpp, parse_cpp cs_aspx, parse_cs_aspx csharp, parse_csharp diff --git a/src/languages.h b/src/languages.h index 3b3decd..a1f7985 100644 --- a/src/languages.h +++ b/src/languages.h @@ -21,6 +21,7 @@ #define LANG_CLASSIC_BASIC "classic_basic" #define LANG_CLEARSILVER "clearsilver" #define LANG_CLEARSILVER_TEMPLATE "clearsilver_template" +#define LANG_CLOJURE "clojure" #define LANG_CMAKE "cmake" #define LANG_CPP "cpp" #define LANG_CS_ASPX "cs_aspx" diff --git a/src/parser.h b/src/parser.h index 370fbe5..3daa675 100644 --- a/src/parser.h +++ b/src/parser.h @@ -275,7 +275,7 @@ * input source file that goes in the 'test/src_dir/' and an expected output * file that goes in the 'test/expected_dir/' directory. * - * The header file will need to be "#include"ed in 'test/unit/test_parsers.h'. + * The header file will need to be "#include"ed in 'test/unit/parser_test.h'. * Then add the "all_[lang]_tests()" function to the "all_parser_tests()" * function. * diff --git a/src/parsers/lisp.rl b/src/parsers/lisp.rl index 8276699..d115f3e 100644 --- a/src/parsers/lisp.rl +++ b/src/parsers/lisp.rl @@ -148,4 +148,15 @@ void parse_scheme(char *buffer, int length, int count, LISP_LANG = ORIG_LISP_LANG; } +const char *CLOJURE_LANG = LANG_CLOJURE; +void parse_clojure(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + LISP_LANG = CLOJURE_LANG; + parse_lisp(buffer, length, count, callback, userdata); + LISP_LANG = ORIG_LISP_LANG; +} + #endif diff --git a/test/expected_dir/clj1.clj b/test/expected_dir/clj1.clj new file mode 100644 index 0000000..89c7966 --- /dev/null +++ b/test/expected_dir/clj1.clj @@ -0,0 +1,16 @@ +clojure comment ;;; Copyright (C) 2009 Brendan Ribera. All rights reserved. +clojure comment ;;; Distributed under the MIT License; see the file LICENSE +clojure comment ;;; at the root of this distribution. +clojure code (ns kdtree) +clojure blank +clojure code (defn dist-squared [a b] +clojure code "Compute the K-dimensional distance between two points" +clojure code (reduce + (for [i (range (count a))] +clojure code (let [v (- (nth a i) +clojure code (nth b i))] +clojure code (* v v))))) +clojure blank +clojure comment ;;; Simple accessors +clojure code (defn- node-value [n] (first n)) +clojure code (defn- node-left [n] (first (rest n))) +clojure code (defn- node-right [n] (first (rest (rest n)))) diff --git a/test/src_dir/clj1.clj b/test/src_dir/clj1.clj new file mode 100644 index 0000000..4e6a9af --- /dev/null +++ b/test/src_dir/clj1.clj @@ -0,0 +1,16 @@ +;;; Copyright (C) 2009 Brendan Ribera. All rights reserved. +;;; Distributed under the MIT License; see the file LICENSE +;;; at the root of this distribution. +(ns kdtree) + +(defn dist-squared [a b] + "Compute the K-dimensional distance between two points" + (reduce + (for [i (range (count a))] + (let [v (- (nth a i) + (nth b i))] + (* v v))))) + +;;; Simple accessors +(defn- node-value [n] (first n)) +(defn- node-left [n] (first (rest n))) +(defn- node-right [n] (first (rest (rest n)))) diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index 62bcffa..1161ab8 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -88,6 +88,7 @@ void test_parser_verify_entity(SourceFile *sf, const char *entity, #include "parsers/test_c.h" #include "parsers/test_clearsilvertemplate.h" #include "parsers/test_clearsilver.h" +#include "parsers/test_clojure.h" #include "parsers/test_cs_aspx.h" #include "parsers/test_csharp.h" #include "parsers/test_css.h" @@ -262,6 +263,7 @@ void all_parser_tests() { all_c_tests(); all_clearsilver_template_tests(); all_clearsilver_tests(); + all_clojure_tests(); all_cs_aspx_tests(); all_csharp_tests(); all_css_tests(); diff --git a/test/unit/parsers/test_clojure.h b/test/unit/parsers/test_clojure.h new file mode 100644 index 0000000..bcb75f2 --- /dev/null +++ b/test/unit/parsers/test_clojure.h @@ -0,0 +1,19 @@ + +void test_clojure_comments() { + test_parser_verify_parse( + test_parser_sourcefile("clojure", " ;;; comment"), + "clojure", "", ";;; comment", 0 + ); +} + +void test_clojure_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("clojure", " ;comment"), + "comment", ";comment" + ); +} + +void all_clojure_tests() { + test_clojure_comments(); + test_clojure_comment_entities(); +} From cbba965effbce38012f52df7d38ac4e26f9ad893 Mon Sep 17 00:00:00 2001 From: Peter Simons Date: Sun, 7 Mar 2010 14:53:43 +0100 Subject: [PATCH 275/387] src/parser.c: declare ohcount_hash_parser_from_language() to fix build error with modern gcc versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function ohcount_hash_parser_from_language() was not declared, resulting in the following compiler error with gcc 4.4.3: src/parser.c: In function ‘ohcount_parse’: src/parser.c:17: warning: implicit declaration of function ‘ohcount_hash_parser_from_language’ src/parser.c:17: warning: initialization makes pointer from integer without a cast src/parser.c:22: error: dereferencing pointer to incomplete type --- src/parser.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/parser.c b/src/parser.c index cb28935..d362acf 100644 --- a/src/parser.c +++ b/src/parser.c @@ -7,6 +7,8 @@ #include "log.h" #include "hash/parser_hash.h" +struct ParserMap * ohcount_hash_parser_from_language (register const char *str, register unsigned int len); + int ohcount_parse(SourceFile *sourcefile, int count, void (*callback) (const char *, const char *, int, int, void *), From ff780f954758b2c3c7aa0ff5a670a9e2303f3cdd Mon Sep 17 00:00:00 2001 From: Peter Simons Date: Sun, 7 Mar 2010 15:25:28 +0100 Subject: [PATCH 276/387] src/hash/extensions.gperf: recognize *.m4 files as containing GNU Autoconf code The detection could be made more sophisticated, because there are other uses of m4 than Autoconf, but for the vast majority of real-world cases using the suffix to guess the language is going to be good enough. --- src/hash/extensions.gperf | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index a805ab9..73584a9 100644 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -96,6 +96,7 @@ lsp, LANG_LISP ltx, LANG_TEX lua, LANG_LUA m, DISAMBIGUATE("m") +m4, LANG_AUTOCONF m4a, BINARY mf, LANG_METAFONT mk, LANG_MAKE From 1e4969e2c489e54e239dea816f2ca1946cab0f44 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Mon, 15 Mar 2010 11:11:56 -0700 Subject: [PATCH 277/387] Ticket #59: Add unit test for *.m4 detection --- test/detect_files/m4.m4 | 6 ++++++ test/unit/detector_test.h | 1 + 2 files changed, 7 insertions(+) create mode 100644 test/detect_files/m4.m4 diff --git a/test/detect_files/m4.m4 b/test/detect_files/m4.m4 new file mode 100644 index 0000000..2962d6d --- /dev/null +++ b/test/detect_files/m4.m4 @@ -0,0 +1,6 @@ +# Sample M4 file + +AC_DEFUN([SAMPLE],[ +AC_REQUIRE([ANOTHER_SAMPLE]) +printf "$2" >> "$1" +]) diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index 030c86a..d05c329 100644 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -113,6 +113,7 @@ void test_detector_detect_polyglot() { ASSERT_DETECT(LANG_ASSEMBLER, "foo.z80"); ASSERT_DETECT(LANG_PHP, "php.inc"); ASSERT_DETECT(LANG_FSHARP, "fs1.fs"); + ASSERT_DETECT(LANG_AUTOCONF, "m4.m4"); ASSERT_NODETECT("empty.inc"); } From a3530cefffa9ed17ab813b40eedb626284cc97d6 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Mon, 15 Mar 2010 12:16:08 -0700 Subject: [PATCH 278/387] Ticket #60 - "build all" should build all --- build | 1 + 1 file changed, 1 insertion(+) diff --git a/build b/build index e69c420..3ca7853 100755 --- a/build +++ b/build @@ -130,6 +130,7 @@ then build_ohcount build_test_suite run_test_suite + build_ruby_bindings echo $success elif [ $1 == "shared" ] then From 845f593133a2e3a2aa508e0c6ce9e268dd63a842 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Fri, 26 Mar 2010 14:52:03 -0700 Subject: [PATCH 279/387] [FIX] Emacs mode "C" improperly detected as C++ detector.c uses the file extenstion map to convert emacs modes to languages. Because the upper-case "C" file extension maps to C++, this means that emacs mode "C" also mapped to C++, which was incorrect. I've added a special check in the code for this case. Emacs modes "c" and "C" now correctly map to straight C code. --- src/detector.c | 6 ++++++ test/detect_files/emacs_mode.c | 2 ++ test/unit/detector_test.h | 5 +++++ 3 files changed, 13 insertions(+) create mode 100644 test/detect_files/emacs_mode.c diff --git a/src/detector.c b/src/detector.c index e9e1e50..171ab7e 100644 --- a/src/detector.c +++ b/src/detector.c @@ -61,6 +61,12 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { length = pe - p; strncpy(buf, p, length); buf[length] = '\0'; + + // Special case for "c" or "C" emacs mode header: always means C, not C++ + if (strcasecmp(buf, "c") == 0) { + return LANG_C; + } + // First try it with the language name. struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); if (rl) language = rl->name; diff --git a/test/detect_files/emacs_mode.c b/test/detect_files/emacs_mode.c new file mode 100644 index 0000000..f55d1f5 --- /dev/null +++ b/test/detect_files/emacs_mode.c @@ -0,0 +1,2 @@ +/* -*- mode: C; -*- + * The upper-case "C" mode should be interpreted as straight C, not C++ */ diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index d05c329..c8f952f 100644 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -158,6 +158,10 @@ void test_detector_brainfuck() { ASSERT_DETECT(LANG_BFPP, "foo.bfpp"); } +void test_detector_emacs_mode() { + ASSERT_DETECT(LANG_C, "emacs_mode.c"); +} + void all_detector_tests() { test_detector_smalltalk(); test_detector_disambiguate_m(); @@ -171,4 +175,5 @@ void all_detector_tests() { test_detector_basic(); test_detector_xml_with_custom_extension(); test_detector_brainfuck(); + test_detector_emacs_mode(); } From 1831488c5fc9ed25ef4ee5fe31ad1695e0215935 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Mon, 29 Mar 2010 14:27:39 -0700 Subject: [PATCH 280/387] FIX: Buffer overrun in emacs mode header logic If the emacs mode header is not well-formed (for example, if it is missing a terminating "-*-"), then we run off the end of our buffer. The emacs mode header parsing is a little complicated, and the best answer is probably to clean up the parser. As an easier, quicker, fix, I simply added a maximum string length check. --- src/detector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detector.c b/src/detector.c index 171ab7e..38f2abb 100644 --- a/src/detector.c +++ b/src/detector.c @@ -58,7 +58,7 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { } pe = p; while (!isspace(*pe) && *pe != ';' && pe != strstr(pe, "-*-")) pe++; - length = pe - p; + length = (pe - p <= sizeof(buf)) ? pe - p : sizeof(buf); strncpy(buf, p, length); buf[length] = '\0'; From d57f92270769f58ef18235749cfbd85c309f1160 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 30 Mar 2010 10:49:38 -0700 Subject: [PATCH 281/387] Implements Modula-2, Modula-3, Oberon We recognize extensions m3, i3, mod, ob2, obn, def. Ticket #30 requests that we also recognize extenions `m` and `d`. That is not implemented here, because that requires disambiguation from other languages, so ticket #30 remains open. --- src/hash/extensions.gperf | 8 +- src/hash/languages.gperf | 3 + src/hash/parsers.gperf | 6 ++ src/languages.h | 201 ++++++++++++++++++++-------------------- src/parsers/modula2.rl | 147 +++++++++++++++++++++++++++++ src/parsers/modula3.rl | 165 +++++++++++++++++++++++++++++++++ src/parsers/oberon.rl | 147 +++++++++++++++++++++++++++++ test/expected_dir/sample.i3 | 12 +++ test/expected_dir/sample.m3 | 12 +++ test/expected_dir/sample.mod | 12 +++ test/expected_dir/sample.ob2 | 12 +++ test/expected_dir/sample.obn | 12 +++ test/expected_dir/sampleDef.def | 12 +++ test/expected_dir/sampleImp.mod | 12 +++ test/src_dir/sample.i3 | 12 +++ test/src_dir/sample.m3 | 12 +++ test/src_dir/sample.mod | 12 +++ test/src_dir/sample.ob2 | 12 +++ test/src_dir/sample.obn | 12 +++ test/src_dir/sampleDef.def | 12 +++ test/src_dir/sampleImp.mod | 12 +++ test/unit/parser_test.h | 7 +- 22 files changed, 747 insertions(+), 105 deletions(-) create mode 100644 src/parsers/modula2.rl create mode 100644 src/parsers/modula3.rl create mode 100644 src/parsers/oberon.rl create mode 100644 test/expected_dir/sample.i3 create mode 100644 test/expected_dir/sample.m3 create mode 100644 test/expected_dir/sample.mod create mode 100644 test/expected_dir/sample.ob2 create mode 100644 test/expected_dir/sample.obn create mode 100644 test/expected_dir/sampleDef.def create mode 100644 test/expected_dir/sampleImp.mod create mode 100644 test/src_dir/sample.i3 create mode 100644 test/src_dir/sample.m3 create mode 100644 test/src_dir/sample.mod create mode 100644 test/src_dir/sample.ob2 create mode 100644 test/src_dir/sample.obn create mode 100644 test/src_dir/sampleDef.def create mode 100644 test/src_dir/sampleImp.mod diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index 73584a9..b8f4db6 100644 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -43,6 +43,7 @@ ctp, LANG_PHP cxx, LANG_CPP d, LANG_DMD dat, BINARY +def, LANG_MODULA2 di, LANG_DMD doc, BINARY dylan, LANG_DYLAN @@ -79,6 +80,7 @@ htm, LANG_HTML html, LANG_HTML hx, LANG_HAXE hxx, LANG_CPP +i3, LANG_MODULA3 icns, BINARY in, DISAMBIGUATE("in") inc, DISAMBIGUATE("inc") @@ -96,6 +98,7 @@ lsp, LANG_LISP ltx, LANG_TEX lua, LANG_LUA m, DISAMBIGUATE("m") +m3, LANG_MODULA3 m4, LANG_AUTOCONF m4a, BINARY mf, LANG_METAFONT @@ -104,6 +107,7 @@ ml, LANG_OCAML ml4, LANG_OCAML mli, LANG_OCAML mm, LANG_OBJECTIVE_C +mod, LANG_MODULA2 mov, BINARY mp, LANG_METAPOST_WITH_TEX mp3, BINARY @@ -111,6 +115,8 @@ mpg, BINARY mxml, LANG_MXML nix, LANG_NIX nse, LANG_LUA +ob2, LANG_OBERON +obn, LANG_OBERON ogg, BINARY p6, LANG_PERL pas, LANG_PASCAL @@ -182,4 +188,4 @@ xs, LANG_C xsd, LANG_XMLSCHEMA xsl, LANG_XSLT z80, LANG_ASSEMBLER -zip, BINARY +zip, BINARY \ No newline at end of file diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index cbae928..2c33084 100644 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -54,8 +54,11 @@ matlab, LANG_MATLAB, "Matlab", 0 metafont, LANG_METAFONT, "MetaFont", 1 metapost, LANG_METAPOST, "MetaPost", 1 metapost_with_tex, LANG_METAPOST_WITH_TEX, "", 0 +modula2, LANG_MODULA2, "Modula-2", 0 +modula3, LANG_MODULA3, "Modula-3", 0 mxml, LANG_MXML, "MXML", 1 nix, LANG_NIX, "Nix", 0 +oberon, LANG_OBERON, "Oberon", 0 objective_c, LANG_OBJECTIVE_C, "Objective-C", 0 objective_j, LANG_OBJECTIVE_J, "Objective-J", 0 ocaml, LANG_OCAML, "Objective Caml", 0 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index 89cb60d..898abe1 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -46,8 +46,11 @@ #include "../parsers/metafont.h" #include "../parsers/metapost.h" #include "../parsers/metapost_with_tex.h" +#include "../parsers/modula2.h" +#include "../parsers/modula3.h" #include "../parsers/mxml.h" #include "../parsers/nix.h" +#include "../parsers/oberon.h" #include "../parsers/objective_c.h" #include "../parsers/objective_j.h" #include "../parsers/ocaml.h" @@ -132,8 +135,11 @@ matlab, parse_matlab metafont, parse_metafont metapost, parse_metapost metapost_with_tex, parse_mptex +modula2, parse_modula2 +modula3, parse_modula3 mxml, parse_mxml nix, parse_nix +oberon, parse_oberon objective_c, parse_objective_c objective_j, parse_objective_j ocaml, parse_ocaml diff --git a/src/languages.h b/src/languages.h index a1f7985..d2b93b5 100644 --- a/src/languages.h +++ b/src/languages.h @@ -1,99 +1,102 @@ -// languages.h written by Mitchell Foral. mitchellcaladbolg.net. -// See COPYING for license information. - -#ifndef OHCOUNT_LANGUAGES_H -#define OHCOUNT_LANGUAGES_H - -#include - -#define LANG_ACTIONSCRIPT "actionscript" -#define LANG_ADA "ada" -#define LANG_ASSEMBLER "assembler" -#define LANG_AUTOCONF "autoconf" -#define LANG_AUTOMAKE "automake" -#define LANG_AWK "awk" -#define LANG_BRAINFUCK "brainfuck" -#define LANG_BFPP "bfpp" -#define LANG_BAT "bat" -#define LANG_BLITZMAX "blitzmax" -#define LANG_BOO "boo" -#define LANG_C "c" -#define LANG_CLASSIC_BASIC "classic_basic" -#define LANG_CLEARSILVER "clearsilver" -#define LANG_CLEARSILVER_TEMPLATE "clearsilver_template" -#define LANG_CLOJURE "clojure" -#define LANG_CMAKE "cmake" -#define LANG_CPP "cpp" -#define LANG_CS_ASPX "cs_aspx" -#define LANG_CSHARP "csharp" -#define LANG_CSS "css" -#define LANG_DCL "dcl" -#define LANG_DMD "dmd" -#define LANG_DYLAN "dylan" -#define LANG_EBUILD "ebuild" -#define LANG_EIFFEL "eiffel" -#define LANG_ERLANG "erlang" -#define LANG_EXHERES "exheres" -#define LANG_EMACSLISP "emacslisp" -#define LANG_FACTOR "factor" -#define LANG_FORTRANFIXED "fortranfixed" -#define LANG_FORTRANFREE "fortranfree" -#define LANG_FSHARP "fsharp" -#define LANG_GLSL "glsl" -#define LANG_GROOVY "groovy" -#define LANG_HASKELL "haskell" -#define LANG_HAML "haml" -#define LANG_HAXE "haxe" -#define LANG_HTML "html" -#define LANG_IDL_PVWAVE "idl_pvwave" -#define LANG_JAVA "java" -#define LANG_JAVASCRIPT "javascript" -#define LANG_JSP "jsp" -#define LANG_LIMBO "limbo" -#define LANG_LISP "lisp" -#define LANG_LUA "lua" -#define LANG_MAKE "make" -#define LANG_MATLAB "matlab" -#define LANG_METAFONT "metafont" -#define LANG_METAPOST "metapost" -#define LANG_METAPOST_WITH_TEX "metapost_with_tex" -#define LANG_MXML "mxml" -#define LANG_NIX "nix" -#define LANG_OBJECTIVE_C "objective_c" -#define LANG_OBJECTIVE_J "objective_j" -#define LANG_OCAML "ocaml" -#define LANG_OCTAVE "octave" -#define LANG_PASCAL "pascal" -#define LANG_PERL "perl" -#define LANG_PHP "php" -#define LANG_PIKE "pike" -#define LANG_PYTHON "python" -#define LANG_R "r" -#define LANG_REXX "rexx" -#define LANG_RHTML "rhtml" -#define LANG_RUBY "ruby" -#define LANG_SCALA "scala" -#define LANG_SCHEME "scheme" -#define LANG_SCILAB "scilab" -#define LANG_SHELL "shell" -#define LANG_SMALLTALK "smalltalk" -#define LANG_STRATEGO "stratego" -#define LANG_STRUCTURED_BASIC "structured_basic" -#define LANG_SQL "sql" -#define LANG_TCL "tcl" -#define LANG_TEX "tex" -#define LANG_VALA "vala" -#define LANG_VB_ASPX "vb_aspx" -#define LANG_VHDL "vhdl" -#define LANG_VIM "vim" -#define LANG_VISUALBASIC "visualbasic" -#define LANG_XAML "xaml" -#define LANG_XML "xml" -#define LANG_XSLT "xslt" -#define LANG_XMLSCHEMA "xmlschema" - -// For gperf. -struct LanguageMap { const char *key; const char *name; const char *nice_name; int category; }; -struct LanguageMap *ohcount_hash_language_from_name(register const char *str, register unsigned int len); - -#endif +// languages.h written by Mitchell Foral. mitchellcaladbolg.net. +// See COPYING for license information. + +#ifndef OHCOUNT_LANGUAGES_H +#define OHCOUNT_LANGUAGES_H + +#include + +#define LANG_ACTIONSCRIPT "actionscript" +#define LANG_ADA "ada" +#define LANG_ASSEMBLER "assembler" +#define LANG_AUTOCONF "autoconf" +#define LANG_AUTOMAKE "automake" +#define LANG_AWK "awk" +#define LANG_BRAINFUCK "brainfuck" +#define LANG_BFPP "bfpp" +#define LANG_BAT "bat" +#define LANG_BLITZMAX "blitzmax" +#define LANG_BOO "boo" +#define LANG_C "c" +#define LANG_CLASSIC_BASIC "classic_basic" +#define LANG_CLEARSILVER "clearsilver" +#define LANG_CLEARSILVER_TEMPLATE "clearsilver_template" +#define LANG_CLOJURE "clojure" +#define LANG_CMAKE "cmake" +#define LANG_CPP "cpp" +#define LANG_CS_ASPX "cs_aspx" +#define LANG_CSHARP "csharp" +#define LANG_CSS "css" +#define LANG_DCL "dcl" +#define LANG_DMD "dmd" +#define LANG_DYLAN "dylan" +#define LANG_EBUILD "ebuild" +#define LANG_EIFFEL "eiffel" +#define LANG_ERLANG "erlang" +#define LANG_EXHERES "exheres" +#define LANG_EMACSLISP "emacslisp" +#define LANG_FACTOR "factor" +#define LANG_FORTRANFIXED "fortranfixed" +#define LANG_FORTRANFREE "fortranfree" +#define LANG_FSHARP "fsharp" +#define LANG_GLSL "glsl" +#define LANG_GROOVY "groovy" +#define LANG_HASKELL "haskell" +#define LANG_HAML "haml" +#define LANG_HAXE "haxe" +#define LANG_HTML "html" +#define LANG_IDL_PVWAVE "idl_pvwave" +#define LANG_JAVA "java" +#define LANG_JAVASCRIPT "javascript" +#define LANG_JSP "jsp" +#define LANG_LIMBO "limbo" +#define LANG_LISP "lisp" +#define LANG_LUA "lua" +#define LANG_MAKE "make" +#define LANG_MATLAB "matlab" +#define LANG_METAFONT "metafont" +#define LANG_METAPOST "metapost" +#define LANG_METAPOST_WITH_TEX "metapost_with_tex" +#define LANG_MODULA2 "modula2" +#define LANG_MODULA3 "modula3" +#define LANG_MXML "mxml" +#define LANG_NIX "nix" +#define LANG_OBERON "oberon" +#define LANG_OBJECTIVE_C "objective_c" +#define LANG_OBJECTIVE_J "objective_j" +#define LANG_OCAML "ocaml" +#define LANG_OCTAVE "octave" +#define LANG_PASCAL "pascal" +#define LANG_PERL "perl" +#define LANG_PHP "php" +#define LANG_PIKE "pike" +#define LANG_PYTHON "python" +#define LANG_R "r" +#define LANG_REXX "rexx" +#define LANG_RHTML "rhtml" +#define LANG_RUBY "ruby" +#define LANG_SCALA "scala" +#define LANG_SCHEME "scheme" +#define LANG_SCILAB "scilab" +#define LANG_SHELL "shell" +#define LANG_SMALLTALK "smalltalk" +#define LANG_STRATEGO "stratego" +#define LANG_STRUCTURED_BASIC "structured_basic" +#define LANG_SQL "sql" +#define LANG_TCL "tcl" +#define LANG_TEX "tex" +#define LANG_VALA "vala" +#define LANG_VB_ASPX "vb_aspx" +#define LANG_VHDL "vhdl" +#define LANG_VIM "vim" +#define LANG_VISUALBASIC "visualbasic" +#define LANG_XAML "xaml" +#define LANG_XML "xml" +#define LANG_XSLT "xslt" +#define LANG_XMLSCHEMA "xmlschema" + +// For gperf. +struct LanguageMap { const char *key; const char *name; const char *nice_name; int category; }; +struct LanguageMap *ohcount_hash_language_from_name(register const char *str, register unsigned int len); + +#endif \ No newline at end of file diff --git a/src/parsers/modula2.rl b/src/parsers/modula2.rl new file mode 100644 index 0000000..27d6156 --- /dev/null +++ b/src/parsers/modula2.rl @@ -0,0 +1,147 @@ +// modula2.rl, +// derived from code written by Mitchell Foral. mitchellcaladbolgnet + + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_MODULA2_PARSER_H +#define OHCOUNT_MODULA2_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *MODULA2_LANG = LANG_MODULA2; + +// the languages entities +const char *modula2_entities[] = { + "space", "comment", "string", "any" +}; + +// constants associated with the entities +enum { + MODULA2_SPACE = 0, MODULA2_COMMENT, MODULA2_STRING, MODULA2_ANY +}; + +/*****************************************************************************/ + +%%{ + machine modula2; + write data; + include common "common.rl"; + + # Line counting machine + + action modula2_ccallback { + switch(entity) { + case MODULA2_SPACE: + ls + break; + case MODULA2_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(MODULA2_LANG) + break; + case NEWLINE: + std_newline(MODULA2_LANG) + } + } + + + # Modula-2 comments + + action modula2_comment_nc_res { nest_count = 0; } + action modula2_comment_nc_inc { nest_count++; } + action modula2_comment_nc_dec { nest_count--; } + + modula2_comment = + '(*' >modula2_comment_nc_res @comment ( + newline %{ entity = INTERNAL_NL; } %modula2_ccallback + | + ws + | + '(*' @modula2_comment_nc_inc @comment + | + '*)' @modula2_comment_nc_dec @comment + | + ^space @comment + )* :>> ('*)' when { nest_count == 0 }) @comment; + + + # Modula-2 string literals + + modula2_singlequoted_string = '\'' @code [^\r\n\f"]* '\''; + modula2_doublequoted_string = '"' @code [^\r\n\f"]* '"'; + + modula2_string = modula2_singlequoted_string | modula2_doublequoted_string; + + + # Line counter + + modula2_line := |* + spaces ${ entity = MODULA2_SPACE; } => modula2_ccallback; + modula2_comment; + modula2_string; + newline ${ entity = NEWLINE; } => modula2_ccallback; + ^space ${ entity = MODULA2_ANY; } => modula2_ccallback; + *|; + + + # Entity machine + + action modula2_ecallback { + callback(MODULA2_LANG, modula2_entities[entity], cint(ts), cint(te), + userdata); + } + + modula2_comment_entity = '(*' >modula2_comment_nc_res ( + '(*' @modula2_comment_nc_inc + | + '*)' @modula2_comment_nc_dec + | + any + )* :>> ('*)' when { nest_count == 0 }); + + modula2_string_entity = sq_str | dq_str; + + modula2_entity := |* + space+ ${ entity = MODULA2_SPACE; } => modula2_ecallback; + modula2_comment_entity ${ entity = MODULA2_COMMENT; } => modula2_ecallback; + modula2_string_entity ${ entity = MODULA2_STRING; } => modula2_ecallback; + # TODO: detecting other entities may be useful to differentiate dialects + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with Modula-2 code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_modula2(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + int nest_count = 0; + + %% write init; + cs = (count) ? modula2_en_modula2_line : modula2_en_modula2_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(MODULA2_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/src/parsers/modula3.rl b/src/parsers/modula3.rl new file mode 100644 index 0000000..2166f0f --- /dev/null +++ b/src/parsers/modula3.rl @@ -0,0 +1,165 @@ +// modula3.rl, +// derived from code written by Mitchell Foral. mitchellcaladbolgnet + + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_MODULA3_PARSER_H +#define OHCOUNT_MODULA3_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *MODULA3_LANG = LANG_MODULA3; + +// the languages entities +const char *modula3_entities[] = { + "space", "comment", "string", "any" +}; + +// constants associated with the entities +enum { + MODULA3_SPACE = 0, MODULA3_COMMENT, MODULA3_STRING, MODULA3_ANY +}; + +/*****************************************************************************/ + +%%{ + machine modula3; + write data; + include common "common.rl"; + + # Line counting machine + + action modula3_ccallback { + switch(entity) { + case MODULA3_SPACE: + ls + break; + case MODULA3_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(MODULA3_LANG) + break; + case NEWLINE: + std_newline(MODULA3_LANG) + } + } + + + # Modula-3 comments + + action modula3_comment_nc_res { nest_count = 0; } + action modula3_comment_nc_inc { nest_count++; } + action modula3_comment_nc_dec { nest_count--; } + + modula3_comment = + '(*' >modula3_comment_nc_res @comment ( + newline %{ entity = INTERNAL_NL; } %modula3_ccallback + | + ws + | + '(*' @modula3_comment_nc_inc @comment + | + '*)' @modula3_comment_nc_dec @comment + | + ^space @comment + )* :>> ('*)' when { nest_count == 0 }) @comment; + + + # Modula-3 string literals + + modula3_singlequoted_string = + '\'' @code ( + escaped_newline %{ entity = INTERNAL_NL; } %modula3_ccallback + | + ws + | + [^\t '\\] @code + | + '\\' nonnewline @code + )* '\''; + modula3_doublequoted_string = + '"' @code ( + escaped_newline %{ entity = INTERNAL_NL; } %modula3_ccallback + | + ws + | + [^\t "\\] @code + | + '\\' nonnewline @code + )* '"'; + modula3_string = modula3_singlequoted_string | modula3_doublequoted_string; + + + # Line counter + + modula3_line := |* + spaces ${ entity = MODULA3_SPACE; } => modula3_ccallback; + modula3_comment; + modula3_string; + newline ${ entity = NEWLINE; } => modula3_ccallback; + ^space ${ entity = MODULA3_ANY; } => modula3_ccallback; + *|; + + + # Entity machine + + action modula3_ecallback { + callback(MODULA3_LANG, modula3_entities[entity], cint(ts), cint(te), + userdata); + } + + modula3_comment_entity = '(*' >modula3_comment_nc_res ( + '(*' @modula3_comment_nc_inc + | + '*)' @modula3_comment_nc_dec + | + any + )* :>> ('*)' when { nest_count == 0 }); + + modula3_string_entity = sq_str_with_escapes | + dq_str_with_escapes; + + modula3_entity := |* + space+ ${ entity = MODULA3_SPACE; } => modula3_ecallback; + modula3_comment_entity ${ entity = MODULA3_COMMENT; } => modula3_ecallback; + modula3_string_entity ${ entity = MODULA3_STRING; } => modula3_ecallback; + # TODO: detecting other entities may be useful to differentiate dialects + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with Modula-3 code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_modula3(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + int nest_count = 0; + + %% write init; + cs = (count) ? modula3_en_modula3_line : modula3_en_modula3_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(MODULA3_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/src/parsers/oberon.rl b/src/parsers/oberon.rl new file mode 100644 index 0000000..ee0e30e --- /dev/null +++ b/src/parsers/oberon.rl @@ -0,0 +1,147 @@ +// oberon.rl, +// derived from code written by Mitchell Foral. mitchellcaladbolgnet + + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_OBERON_PARSER_H +#define OHCOUNT_OBERON_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *OBERON_LANG = LANG_OBERON; + +// the languages entities +const char *oberon_entities[] = { + "space", "comment", "string", "any" +}; + +// constants associated with the entities +enum { + OBERON_SPACE = 0, OBERON_COMMENT, OBERON_STRING, OBERON_ANY +}; + +/*****************************************************************************/ + +%%{ + machine oberon; + write data; + include common "common.rl"; + + # Line counting machine + + action oberon_ccallback { + switch(entity) { + case OBERON_SPACE: + ls + break; + case OBERON_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(OBERON_LANG) + break; + case NEWLINE: + std_newline(OBERON_LANG) + } + } + + + # Oberon comments + + action oberon_comment_nc_res { nest_count = 0; } + action oberon_comment_nc_inc { nest_count++; } + action oberon_comment_nc_dec { nest_count--; } + + oberon_comment = + '(*' >oberon_comment_nc_res @comment ( + newline %{ entity = INTERNAL_NL; } %oberon_ccallback + | + ws + | + '(*' @oberon_comment_nc_inc @comment + | + '*)' @oberon_comment_nc_dec @comment + | + ^space @comment + )* :>> ('*)' when { nest_count == 0 }) @comment; + + + # Oberon string literals + + oberon_singlequoted_string = '\'' @code [^\r\n\f"]* '\''; + oberon_doublequoted_string = '"' @code [^\r\n\f"]* '"'; + + oberon_string = oberon_singlequoted_string | oberon_doublequoted_string; + + + # Line counter + + oberon_line := |* + spaces ${ entity = OBERON_SPACE; } => oberon_ccallback; + oberon_comment; + oberon_string; + newline ${ entity = NEWLINE; } => oberon_ccallback; + ^space ${ entity = OBERON_ANY; } => oberon_ccallback; + *|; + + + # Entity machine + + action oberon_ecallback { + callback(OBERON_LANG, oberon_entities[entity], cint(ts), cint(te), + userdata); + } + + oberon_comment_entity = '(*' >oberon_comment_nc_res ( + '(*' @oberon_comment_nc_inc + | + '*)' @oberon_comment_nc_dec + | + any + )* :>> ('*)' when { nest_count == 0 }); + + oberon_string_entity = sq_str | dq_str; + + oberon_entity := |* + space+ ${ entity = OBERON_SPACE; } => oberon_ecallback; + oberon_comment_entity ${ entity = OBERON_COMMENT; } => oberon_ecallback; + oberon_string_entity ${ entity = OBERON_STRING; } => oberon_ecallback; + # TODO: detecting other entities may be useful to differentiate dialects + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with Oberon code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_oberon(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + int nest_count = 0; + + %% write init; + cs = (count) ? oberon_en_oberon_line : oberon_en_oberon_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(OBERON_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/test/expected_dir/sample.i3 b/test/expected_dir/sample.i3 new file mode 100644 index 0000000..43b051b --- /dev/null +++ b/test/expected_dir/sample.i3 @@ -0,0 +1,12 @@ +modula3 code (* Modula-3 *) INTERFACE M3Sample; (* file extension ".i3" *) +modula3 blank +modula3 comment (* This is a comment *) +modula3 blank +modula3 comment (* This is a comment ... +modula3 comment ... spanning more than one line *) +modula3 blank +modula3 code CONST +modula3 code sqString = 'this is a string within "a string" ...\n'; +modula3 code dqString = "this is a string within 'a string' ...\n"; +modula3 blank +modula3 code END M3Sample. diff --git a/test/expected_dir/sample.m3 b/test/expected_dir/sample.m3 new file mode 100644 index 0000000..f525d0b --- /dev/null +++ b/test/expected_dir/sample.m3 @@ -0,0 +1,12 @@ +modula3 code (* Modula-3 *) MODULE M3Sample; (* file extension ".m3" *) +modula3 blank +modula3 comment (* This is a comment *) +modula3 blank +modula3 comment (* This is a comment ... +modula3 comment ... spanning more than one line *) +modula3 blank +modula3 code CONST +modula3 code sqString = 'this is a string within "a string" ...\n'; +modula3 code dqString = "this is a string within 'a string' ...\n"; +modula3 blank +modula3 code END M3Sample. diff --git a/test/expected_dir/sample.mod b/test/expected_dir/sample.mod new file mode 100644 index 0000000..cd40648 --- /dev/null +++ b/test/expected_dir/sample.mod @@ -0,0 +1,12 @@ +modula2 code MODULE Sample; (* in Modula-2 *) +modula2 blank +modula2 comment (* This is a comment *) +modula2 blank +modula2 comment (* This is a comment ... +modula2 comment ... spanning more than one line *) +modula2 blank +modula2 code CONST +modula2 code sqString = 'this is a string within "a string" ...'; +modula2 code dqString = "this is a string within 'a string' ..."; +modula2 blank +modula2 code END Sample. diff --git a/test/expected_dir/sample.ob2 b/test/expected_dir/sample.ob2 new file mode 100644 index 0000000..4561fee --- /dev/null +++ b/test/expected_dir/sample.ob2 @@ -0,0 +1,12 @@ +oberon code (* Oberon-2 *) MODULE OberonSample; (* file extension ".ob2" *) +oberon blank +oberon comment (* This is a comment *) +oberon blank +oberon comment (* This is a comment ... +oberon comment ... spanning more than one line *) +oberon blank +oberon code CONST +oberon code sqString* = 'this is a string within "a string" ...'; +oberon code dqString* = "this is a string within 'a string' ..."; +oberon blank +oberon code END OberonSample. diff --git a/test/expected_dir/sample.obn b/test/expected_dir/sample.obn new file mode 100644 index 0000000..faa5ca7 --- /dev/null +++ b/test/expected_dir/sample.obn @@ -0,0 +1,12 @@ +oberon code (* Oberon *) MODULE OberonSample; (* file extension ".obn" *) +oberon blank +oberon comment (* This is a comment *) +oberon blank +oberon comment (* This is a comment ... +oberon comment ... spanning more than one line *) +oberon blank +oberon code CONST +oberon code sqString* = 'this is a string within "a string" ...'; +oberon code dqString* = "this is a string within 'a string' ..."; +oberon blank +oberon code END OberonSample. diff --git a/test/expected_dir/sampleDef.def b/test/expected_dir/sampleDef.def new file mode 100644 index 0000000..11842b4 --- /dev/null +++ b/test/expected_dir/sampleDef.def @@ -0,0 +1,12 @@ +modula2 code DEFINITION MODULE Sample; (* in Modula-2 *) +modula2 blank +modula2 comment (* This is a comment *) +modula2 blank +modula2 comment (* This is a comment ... +modula2 comment ... spanning more than one line *) +modula2 blank +modula2 code CONST +modula2 code sqString = 'this is a string within "a string" ...'; +modula2 code dqString = "this is a string within 'a string' ..."; +modula2 blank +modula2 code END Sample. diff --git a/test/expected_dir/sampleImp.mod b/test/expected_dir/sampleImp.mod new file mode 100644 index 0000000..04f19ce --- /dev/null +++ b/test/expected_dir/sampleImp.mod @@ -0,0 +1,12 @@ +modula2 code IMPLEMENTATION MODULE Sample; (* in Modula-2 *) +modula2 blank +modula2 comment (* This is a comment *) +modula2 blank +modula2 comment (* This is a comment ... +modula2 comment ... spanning more than one line *) +modula2 blank +modula2 code CONST +modula2 code sqString = 'this is a string within "a string" ...'; +modula2 code dqString = "this is a string within 'a string' ..."; +modula2 blank +modula2 code END Sample. diff --git a/test/src_dir/sample.i3 b/test/src_dir/sample.i3 new file mode 100644 index 0000000..8a0b394 --- /dev/null +++ b/test/src_dir/sample.i3 @@ -0,0 +1,12 @@ +(* Modula-3 *) INTERFACE M3Sample; (* file extension ".i3" *) + +(* This is a comment *) + +(* This is a comment ... + ... spanning more than one line *) + +CONST + sqString = 'this is a string within "a string" ...\n'; + dqString = "this is a string within 'a string' ...\n"; + +END M3Sample. diff --git a/test/src_dir/sample.m3 b/test/src_dir/sample.m3 new file mode 100644 index 0000000..7640dea --- /dev/null +++ b/test/src_dir/sample.m3 @@ -0,0 +1,12 @@ +(* Modula-3 *) MODULE M3Sample; (* file extension ".m3" *) + +(* This is a comment *) + +(* This is a comment ... + ... spanning more than one line *) + +CONST + sqString = 'this is a string within "a string" ...\n'; + dqString = "this is a string within 'a string' ...\n"; + +END M3Sample. diff --git a/test/src_dir/sample.mod b/test/src_dir/sample.mod new file mode 100644 index 0000000..4f8debe --- /dev/null +++ b/test/src_dir/sample.mod @@ -0,0 +1,12 @@ +MODULE Sample; (* in Modula-2 *) + +(* This is a comment *) + +(* This is a comment ... + ... spanning more than one line *) + +CONST + sqString = 'this is a string within "a string" ...'; + dqString = "this is a string within 'a string' ..."; + +END Sample. diff --git a/test/src_dir/sample.ob2 b/test/src_dir/sample.ob2 new file mode 100644 index 0000000..6355698 --- /dev/null +++ b/test/src_dir/sample.ob2 @@ -0,0 +1,12 @@ +(* Oberon-2 *) MODULE OberonSample; (* file extension ".ob2" *) + +(* This is a comment *) + +(* This is a comment ... + ... spanning more than one line *) + +CONST + sqString* = 'this is a string within "a string" ...'; + dqString* = "this is a string within 'a string' ..."; + +END OberonSample. diff --git a/test/src_dir/sample.obn b/test/src_dir/sample.obn new file mode 100644 index 0000000..9ad1e2b --- /dev/null +++ b/test/src_dir/sample.obn @@ -0,0 +1,12 @@ +(* Oberon *) MODULE OberonSample; (* file extension ".obn" *) + +(* This is a comment *) + +(* This is a comment ... + ... spanning more than one line *) + +CONST + sqString* = 'this is a string within "a string" ...'; + dqString* = "this is a string within 'a string' ..."; + +END OberonSample. diff --git a/test/src_dir/sampleDef.def b/test/src_dir/sampleDef.def new file mode 100644 index 0000000..cd7c9ed --- /dev/null +++ b/test/src_dir/sampleDef.def @@ -0,0 +1,12 @@ +DEFINITION MODULE Sample; (* in Modula-2 *) + +(* This is a comment *) + +(* This is a comment ... + ... spanning more than one line *) + +CONST + sqString = 'this is a string within "a string" ...'; + dqString = "this is a string within 'a string' ..."; + +END Sample. diff --git a/test/src_dir/sampleImp.mod b/test/src_dir/sampleImp.mod new file mode 100644 index 0000000..cd5189e --- /dev/null +++ b/test/src_dir/sampleImp.mod @@ -0,0 +1,12 @@ +IMPLEMENTATION MODULE Sample; (* in Modula-2 *) + +(* This is a comment *) + +(* This is a comment ... + ... spanning more than one line *) + +CONST + sqString = 'this is a string within "a string" ...'; + dqString = "this is a string within 'a string' ..."; + +END Sample. diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index 1161ab8..c7ed573 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -172,11 +172,8 @@ void test_parser_callback(const char *language, const char *entity, end - start); line2[strlen(language) + strlen(entity) + 2 + (end - start)] = '\0'; if (strcmp(line, line2) != 0) { - fprintf(stderr, "lines didn't match:\n1: '%s'\n2: '%s'\n", line, line2); - if (strcmp(line, line2) != 0) { - fprintf(stderr, "lines didn't match:\n1: '%s'\n2: '%s'\n", line, line2); - assert(strcmp(line, line2) == 0); - } + fprintf(stderr, "FAIL: Parser test failure in %s:\nExpected: %sGot: %s", udata->sf->filename, line, line2); + assert(strcmp(line, line2) == 0); } } From b89de37c9083c20f2728d11799ce1b0c53dac6f1 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 30 Mar 2010 11:30:26 -0700 Subject: [PATCH 282/387] FIX - missing newline at end of languages.h --- src/languages.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages.h b/src/languages.h index d2b93b5..4497bd8 100644 --- a/src/languages.h +++ b/src/languages.h @@ -99,4 +99,4 @@ struct LanguageMap { const char *key; const char *name; const char *nice_name; int category; }; struct LanguageMap *ohcount_hash_language_from_name(register const char *str, register unsigned int len); -#endif \ No newline at end of file +#endif From 467bd308a2217faf7a7a7a62cd7c32ae4dad8eb2 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 31 Mar 2010 12:01:38 -0600 Subject: [PATCH 283/387] Add support for parsing/counting of ChaiScript. ChaiScript is based on closely on support for JavaScript, as the langauges are similar in structure. All ChaiScript unit tests pass, but 1 or 2 (appears to be random) of the ruby diff tests fail. --- src/parsers/chaiscript.rl | 138 ++++++++++++++++++++++++++++++++++++ test/detect_files/foo.chai | 4 ++ test/expected_dir/chaiscript.chai | 17 +++++ test/src_dir/chaiscript.chai | 17 +++++ test/unit/parsers/test_chaiscript.h | 23 ++++++ 5 files changed, 199 insertions(+) create mode 100644 src/parsers/chaiscript.rl create mode 100644 test/detect_files/foo.chai create mode 100644 test/expected_dir/chaiscript.chai create mode 100644 test/src_dir/chaiscript.chai create mode 100644 test/unit/parsers/test_chaiscript.h diff --git a/src/parsers/chaiscript.rl b/src/parsers/chaiscript.rl new file mode 100644 index 0000000..5491e36 --- /dev/null +++ b/src/parsers/chaiscript.rl @@ -0,0 +1,138 @@ +// Chaiscript.rl written by Jason Turner. lefticusgmailcom +// based on Javascript.rl written by Mitchell Foral. mitchellcaladbolgnet. + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_CHAISCRIPT_PARSER_H +#define OHCOUNT_CHAISCRIPT_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *CHAI_LANG = LANG_CHAISCRIPT; + +// the languages entities +const char *chai_entities[] = { + "space", "comment", "string", "number", "keyword", + "identifier", "operator", "any" +}; + +// constants associated with the entities +enum { + CHAI_SPACE = 0, CHAI_COMMENT, CHAI_STRING, CHAI_NUMBER, CHAI_KEYWORD, + CHAI_IDENTIFIER, CHAI_OPERATOR, CHAI_ANY +}; + +/*****************************************************************************/ + +%%{ + machine chaiscript; + write data; + include common "common.rl"; + + # Line counting machine + + action chai_ccallback { + switch(entity) { + case CHAI_SPACE: + ls + break; + case CHAI_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(CHAI_LANG) + break; + case NEWLINE: + std_newline(CHAI_LANG) + } + } + + chai_line_comment = '//' @comment nonnewline*; + chai_block_comment = + '/*' @comment ( + newline %{ entity = INTERNAL_NL; } %chai_ccallback + | + ws + | + (nonnewline - ws) @comment + )* :>> '*/'; + chai_comment = chai_line_comment | chai_block_comment; + + # Does Javascript allow newlines inside strings? + # I can't find a definitive answer. + chai_sq_str = + '\'' @code ( + escaped_newline %{ entity = INTERNAL_NL; } %chai_ccallback + | + ws + | + [^\t '\\] @code + | + '\\' nonnewline @code + )* '\''; + chai_dq_str = + '"' @code ( + escaped_newline %{ entity = INTERNAL_NL; } %chai_ccallback + | + ws + | + [^\t "\\] @code + | + '\\' nonnewline @code + )* '"'; + chai_regex_str = '/' [^/*] ([^\r\n\f/\\] | '\\' nonnewline)* '/' @code; + chai_string = chai_sq_str | chai_dq_str | chai_regex_str; + + chai_line := |* + spaces ${ entity = CHAI_SPACE; } => chai_ccallback; + chai_comment; + chai_string; + newline ${ entity = NEWLINE; } => chai_ccallback; + ^space ${ entity = CHAI_ANY; } => chai_ccallback; + *|; + + # Entity machine + + action chai_ecallback { + callback(CHAI_LANG, chai_entities[entity], cint(ts), cint(te), userdata); + } + + chai_line_comment_entity = '//' nonnewline*; + chai_block_comment_entity = '/*' any* :>> '*/'; + chai_comment_entity = chai_line_comment_entity | chai_block_comment_entity; + + chai_entity := |* + space+ ${ entity = CHAI_SPACE; } => chai_ecallback; + chai_comment_entity ${ entity = CHAI_COMMENT; } => chai_ecallback; + # TODO: + ^space; + *|; +}%% + +/* Parses a string buffer with Chaiscript code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_chaiscript(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, + int s, int e, void *udata), + void *userdata + ) { + init + + %% write init; + cs = (count) ? chaiscript_en_chai_line : chaiscript_en_chai_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(CHAI_LANG) } +} + +#endif diff --git a/test/detect_files/foo.chai b/test/detect_files/foo.chai new file mode 100644 index 0000000..f8dc571 --- /dev/null +++ b/test/detect_files/foo.chai @@ -0,0 +1,4 @@ +//ChaiScript file +def dosomething() +{ +} diff --git a/test/expected_dir/chaiscript.chai b/test/expected_dir/chaiscript.chai new file mode 100644 index 0000000..c92ee13 --- /dev/null +++ b/test/expected_dir/chaiscript.chai @@ -0,0 +1,17 @@ +chaiscript comment /* +chaiscript comment Random Comments +chaiscript comment Foo Foo Foo +chaiscript comment */ +chaiscript code var submenu=1; +chaiscript comment // comment +chaiscript comment // another comment +chaiscript code submenu += 10 +chaiscript code var f = fun() { 5 }; +chaiscript code def myFun(i) : i > 0 { +chaiscript code return i + 10; +chaiscript code } +chaiscript blank +chaiscript blank +chaiscript comment // some comment +chaiscript code var delay_hide=500 +chaiscript code b=0 diff --git a/test/src_dir/chaiscript.chai b/test/src_dir/chaiscript.chai new file mode 100644 index 0000000..208a933 --- /dev/null +++ b/test/src_dir/chaiscript.chai @@ -0,0 +1,17 @@ +/* +Random Comments +Foo Foo Foo +*/ +var submenu=1; +// comment +// another comment +submenu += 10 +var f = fun() { 5 }; +def myFun(i) : i > 0 { + return i + 10; +} + + +// some comment +var delay_hide=500 +b=0 diff --git a/test/unit/parsers/test_chaiscript.h b/test/unit/parsers/test_chaiscript.h new file mode 100644 index 0000000..6688011 --- /dev/null +++ b/test/unit/parsers/test_chaiscript.h @@ -0,0 +1,23 @@ + +void test_chaiscript_comments() { + test_parser_verify_parse( + test_parser_sourcefile("chaiscript", " //comment"), + "chaiscript", "", "//comment", 0 + ); +} + +void test_chaiscript_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("chaiscript", " //comment"), + "comment", "//comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("chaiscript", " /*comment*/"), + "comment", "/*comment*/" + ); +} + +void all_chaiscript_tests() { + test_chaiscript_comments(); + test_chaiscript_comment_entities(); +} From 8816402cc745429a677e1ad01ad4d5f6541437b0 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 31 Mar 2010 12:10:29 -0600 Subject: [PATCH 284/387] Add support for ChaiScript - adding missing files from last commit --- src/hash/extensions.gperf | 3 ++- src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 2 ++ src/languages.h | 1 + test/unit/parser_test.h | 2 ++ 5 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index b8f4db6..dd0ef3b 100644 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -32,6 +32,7 @@ c, LANG_C c++, LANG_CPP cache, BINARY cc, LANG_CPP +chai, LANG_CHAISCRIPT clj, LANG_CLOJURE cmake, LANG_CMAKE com, LANG_DCL @@ -188,4 +189,4 @@ xs, LANG_C xsd, LANG_XMLSCHEMA xsl, LANG_XSLT z80, LANG_ASSEMBLER -zip, BINARY \ No newline at end of file +zip, BINARY diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index 2c33084..564750a 100644 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -15,6 +15,7 @@ boo, LANG_BOO, "Boo", 0 brainfuck, LANG_BRAINFUCK, "Brainfuck", 0 bfpp, LANG_BFPP, "Brainfuck++", 0 c, LANG_C, "C", 0 +chaiscript, LANG_CHAISCRIPT, "ChaiScript", 0 classic_basic, LANG_CLASSIC_BASIC, "Classic Basic", 0 clearsilver, LANG_CLEARSILVER, "ClearSilver", 0 clearsilver_template, LANG_CLEARSILVER_TEMPLATE, "ClearSilver", 0 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index 898abe1..d128573 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -11,6 +11,7 @@ #include "../parsers/brainfuck.h" #include "../parsers/bfpp.h" #include "../parsers/c.h" +#include "../parsers/chaiscript.h" #include "../parsers/classic_basic.h" #include "../parsers/clearsilver.h" #include "../parsers/clearsilverhtml.h" @@ -96,6 +97,7 @@ boo, parse_boo brainfuck, parse_brainfuck bfpp, parse_bfpp c, parse_c +chaiscript, parse_chaiscript cmake, parse_cmake classic_basic, parse_classic_basic clearsilver, parse_clearsilver diff --git a/src/languages.h b/src/languages.h index 4497bd8..b24d10a 100644 --- a/src/languages.h +++ b/src/languages.h @@ -18,6 +18,7 @@ #define LANG_BLITZMAX "blitzmax" #define LANG_BOO "boo" #define LANG_C "c" +#define LANG_CHAISCRIPT "chaiscript" #define LANG_CLASSIC_BASIC "classic_basic" #define LANG_CLEARSILVER "clearsilver" #define LANG_CLEARSILVER_TEMPLATE "clearsilver_template" diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index c7ed573..3602553 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -86,6 +86,7 @@ void test_parser_verify_entity(SourceFile *sf, const char *entity, #include "parsers/test_brainfuck.h" #include "parsers/test_bfpp.h" #include "parsers/test_c.h" +#include "parsers/test_chaiscript.h" #include "parsers/test_clearsilvertemplate.h" #include "parsers/test_clearsilver.h" #include "parsers/test_clojure.h" @@ -258,6 +259,7 @@ void all_parser_tests() { all_brainfuck_tests(); all_bfpp_tests(); all_c_tests(); + all_chaiscript_tests(); all_clearsilver_template_tests(); all_clearsilver_tests(); all_clojure_tests(); From 34a63c29dfb262591ab595a8b08351c49bd2a06f Mon Sep 17 00:00:00 2001 From: Jiri Matela Date: Thu, 15 Apr 2010 09:35:28 -0700 Subject: [PATCH 285/387] Recognize .cu files as CUDA code; C parser for cuda files used --- src/hash/extensions.gperf | 1 + src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 1 + src/languages.h | 1 + src/parsers/c.rl | 11 +++ test/expected_dir/components.cu | 163 ++++++++++++++++++++++++++++++++++++++++ test/src_dir/components.cu | 27 +++++++ 7 files changed, 205 insertions(+) create mode 100644 test/expected_dir/components.cu create mode 100644 test/src_dir/components.cu diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index dd0ef3b..314663c 100644 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -41,6 +41,7 @@ cs, DISAMBIGUATE("cs") csproj, LANG_XML css, LANG_CSS ctp, LANG_PHP +cu, LANG_CUDA cxx, LANG_CPP d, LANG_DMD dat, BINARY diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index 564750a..27a312d 100644 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -25,6 +25,7 @@ cpp, LANG_CPP, "C++", 0 cs_aspx, LANG_CS_ASPX, "", 0 csharp, LANG_CSHARP, "C#", 0 css, LANG_CSS, "CSS", 1 +cuda, LANG_CUDA, "CUDA", 0 dcl, LANG_DCL, "DCL", 0 dmd, LANG_DMD, "D", 0 dylan, LANG_DYLAN, "Dylan", 0 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index d128573..d5aff72 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -107,6 +107,7 @@ cpp, parse_cpp cs_aspx, parse_cs_aspx csharp, parse_csharp css, parse_css +cuda, parse_cuda dcl, parse_dcl dmd, parse_d dylan, parse_dylan diff --git a/src/languages.h b/src/languages.h index b24d10a..a89408d 100644 --- a/src/languages.h +++ b/src/languages.h @@ -28,6 +28,7 @@ #define LANG_CS_ASPX "cs_aspx" #define LANG_CSHARP "csharp" #define LANG_CSS "css" +#define LANG_CUDA "cuda" #define LANG_DCL "dcl" #define LANG_DMD "dmd" #define LANG_DYLAN "dylan" diff --git a/src/parsers/c.rl b/src/parsers/c.rl index c887e83..c2bd571 100644 --- a/src/parsers/c.rl +++ b/src/parsers/c.rl @@ -211,6 +211,17 @@ void parse_vala(char *buffer, int length, int count, C_LANG = ORIG_C_LANG; } +const char *CUDA_LANG = LANG_CUDA; +void parse_cuda(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + C_LANG = CUDA_LANG; + parse_c(buffer, length, count, callback, userdata); + C_LANG = ORIG_C_LANG; +} + #endif /*****************************************************************************/ diff --git a/test/expected_dir/components.cu b/test/expected_dir/components.cu new file mode 100644 index 0000000..689200b --- /dev/null +++ b/test/expected_dir/components.cu @@ -0,0 +1,163 @@ +cuda code #include +cuda code #include +cuda code #include +cuda code #include +cuda code #include +cuda code #include +cuda blank +cuda code #include "components.h" +cuda code #include "common.h" +cuda blank +cuda code #define THREADS 256 +cuda blank +cuda comment /* Store 3 RGB float components */ +cuda code __device__ void storeComponents(float *d_r, float *d_g, float *d_b, float r, float g, float b, int pos) +cuda code { +cuda code d_r[pos] = (r/255.0f) - 0.5f; +cuda code d_g[pos] = (g/255.0f) - 0.5f; +cuda code d_b[pos] = (b/255.0f) - 0.5f; +cuda code } +cuda blank +cuda comment /* Store 3 RGB intege components */ +cuda code __device__ void storeComponents(int *d_r, int *d_g, int *d_b, int r, int g, int b, int pos) +cuda code { +cuda code d_r[pos] = r - 128; +cuda code d_g[pos] = g - 128; +cuda code d_b[pos] = b - 128; +cuda code } +cuda blank +cuda comment /* Store float component */ +cuda code __device__ void storeComponent(float *d_c, float c, int pos) +cuda code { +cuda code d_c[pos] = (c/255.0f) - 0.5f; +cuda code } +cuda blank +cuda comment /* Store integer component */ +cuda code __device__ void storeComponent(int *d_c, int c, int pos) +cuda code { +cuda code d_c[pos] = c - 128; +cuda code } +cuda blank +cuda comment /* Copy img src data into three separated component buffers */ +cuda code template +cuda code __global__ void c_CopySrcToComponents(T *d_r, T *d_g, T *d_b, +cuda code unsigned char * d_src, +cuda code int pixels) +cuda code { +cuda code int x = threadIdx.x; +cuda code int gX = blockDim.x*blockIdx.x; +cuda blank +cuda code __shared__ unsigned char sData[THREADS*3]; +cuda blank +cuda comment /* Copy data to shared mem by 4bytes other checks are not necessary, since d_src buffer is aligned to sharedDataSize */ +cuda code if ( (x*4) < THREADS*3 ) { +cuda code float *s = (float *)d_src; +cuda code float *d = (float *)sData; +cuda code d[x] = s[((gX*3)>>2) + x]; +cuda code } +cuda code __syncthreads(); +cuda blank +cuda code T r, g, b; +cuda blank +cuda code int offset = x*3; +cuda code r = (T)(sData[offset]); +cuda code g = (T)(sData[offset+1]); +cuda code b = (T)(sData[offset+2]); +cuda blank +cuda code int globalOutputPosition = gX + x; +cuda code if (globalOutputPosition < pixels) { +cuda code storeComponents(d_r, d_g, d_b, r, g, b, globalOutputPosition); +cuda code } +cuda code } +cuda blank +cuda comment /* Copy img src data into three separated component buffers */ +cuda code template +cuda code __global__ void c_CopySrcToComponent(T *d_c, unsigned char * d_src, int pixels) +cuda code { +cuda code int x = threadIdx.x; +cuda code int gX = blockDim.x*blockIdx.x; +cuda blank +cuda code __shared__ unsigned char sData[THREADS]; +cuda blank +cuda comment /* Copy data to shared mem by 4bytes other checks are not necessary, since d_src buffer is aligned to sharedDataSize */ +cuda code if ( (x*4) < THREADS) { +cuda code float *s = (float *)d_src; +cuda code float *d = (float *)sData; +cuda code d[x] = s[(gX>>2) + x]; +cuda code } +cuda code __syncthreads(); +cuda blank +cuda code T c; +cuda blank +cuda code c = (T)(sData[x]); +cuda blank +cuda code int globalOutputPosition = gX + x; +cuda code if (globalOutputPosition < pixels) { +cuda code storeComponent(d_c, c, globalOutputPosition); +cuda code } +cuda code } +cuda blank +cuda blank +cuda comment /* Separate compoents of 8bit RGB source image */ +cuda code template +cuda code void rgbToComponents(T *d_r, T *d_g, T *d_b, unsigned char * src, int width, int height) +cuda code { +cuda code unsigned char * d_src; +cuda code int pixels = width*height; +cuda code int alignedSize = DIVANDRND(width*height, THREADS) * THREADS * 3; //aligned to thread block size -- THREADS +cuda blank +cuda comment /* Alloc d_src buffer */ +cuda code cudaMalloc((void **)&d_src, alignedSize); +cuda code cudaCheckAsyncError("Cuda malloc") +cuda code cudaMemset(d_src, 0, alignedSize); +cuda blank +cuda comment /* Copy data to device */ +cuda code cudaMemcpy(d_src, src, pixels*3, cudaMemcpyHostToDevice); +cuda code cudaCheckError("Copy data to device") +cuda blank +cuda comment /* Kernel */ +cuda code dim3 threads(THREADS); +cuda code dim3 grid(alignedSize/(THREADS*3)); +cuda code assert(alignedSize%(THREADS*3) == 0); +cuda code c_CopySrcToComponents<<>>(d_r, d_g, d_b, d_src, pixels); +cuda code cudaCheckAsyncError("CopySrcToComponents kernel") +cuda blank +cuda comment /* Free Memory */ +cuda code cudaFree(d_src); +cuda code cudaCheckAsyncError("Free memory") +cuda code } +cuda code template void rgbToComponents(float *d_r, float *d_g, float *d_b, unsigned char * src, int width, int height); +cuda code template void rgbToComponents(int *d_r, int *d_g, int *d_b, unsigned char * src, int width, int height); +cuda blank +cuda blank +cuda comment /* Copy a 8bit source image data into a color compoment of type T */ +cuda code template +cuda code void bwToComponent(T *d_c, unsigned char * src, int width, int height) +cuda code { +cuda code unsigned char * d_src; +cuda code int pixels = width*height; +cuda code int alignedSize = DIVANDRND(pixels, THREADS) * THREADS; //aligned to thread block size -- THREADS +cuda blank +cuda comment /* Alloc d_src buffer */ +cuda code cudaMalloc((void **)&d_src, alignedSize); +cuda code cudaCheckAsyncError("Cuda malloc") +cuda code cudaMemset(d_src, 0, alignedSize); +cuda blank +cuda comment /* Copy data to device */ +cuda code cudaMemcpy(d_src, src, pixels, cudaMemcpyHostToDevice); +cuda code cudaCheckError("Copy data to device") +cuda blank +cuda comment /* Kernel */ +cuda code dim3 threads(THREADS); +cuda code dim3 grid(alignedSize/(THREADS)); +cuda code assert(alignedSize%(THREADS) == 0); +cuda code c_CopySrcToComponent<<>>(d_c, d_src, pixels); +cuda code cudaCheckAsyncError("CopySrcToComponent kernel") +cuda blank +cuda comment /* Free Memory */ +cuda code cudaFree(d_src); +cuda code cudaCheckAsyncError("Free memory") +cuda code } +cuda blank +cuda code template void bwToComponent(float *d_c, unsigned char *src, int width, int height); +cuda code template void bwToComponent(int *d_c, unsigned char *src, int width, int height); diff --git a/test/src_dir/components.cu b/test/src_dir/components.cu new file mode 100644 index 0000000..e357e82 --- /dev/null +++ b/test/src_dir/components.cu @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include +#include + +#include "components.h" +#include "common.h" + +#define THREADS 256 + +/* Store 3 RGB float components */ +__device__ void storeComponents(float *d_r, float *d_g, float *d_b, float r, float g, float b, int pos) +{ + d_r[pos] = (r/255.0f) - 0.5f; + d_g[pos] = (g/255.0f) - 0.5f; + d_b[pos] = (b/255.0f) - 0.5f; +} + +/* Store 3 RGB intege components */ +__device__ void storeComponents(int *d_r, int *d_g, int *d_b, int r, int g, int b, int pos) +{ + d_r[pos] = r - 128; + d_g[pos] = g - 128; + d_b[pos] = b - 128; +} From 452d902d8f69afc10eecb2e382b0f39cc2342e92 Mon Sep 17 00:00:00 2001 From: Ken Barber Date: Tue, 4 May 2010 03:12:26 +0100 Subject: [PATCH 286/387] Added support for the Puppet DSL from Puppetlabs. --- src/detector.c | 37 ++++++++++ src/hash/disambiguatefuncs.gperf | 2 + src/hash/extensions.gperf | 2 +- src/hash/filenames.gperf | 1 + src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 2 + src/languages.h | 1 + src/parsers/puppet.rl | 128 ++++++++++++++++++++++++++++++++++ test/expected_dir/puppet1.pp | 145 +++++++++++++++++++++++++++++++++++++++ test/src_dir/puppet1.pp | 145 +++++++++++++++++++++++++++++++++++++++ test/unit/parser_test.h | 1 + test/unit/parsers/test_puppet.h | 23 +++++++ 12 files changed, 487 insertions(+), 1 deletion(-) create mode 100644 src/parsers/puppet.rl create mode 100644 test/expected_dir/puppet1.pp create mode 100644 test/src_dir/puppet1.pp create mode 100644 test/unit/parsers/test_puppet.h diff --git a/src/detector.c b/src/detector.c index 38f2abb..f687dc9 100644 --- a/src/detector.c +++ b/src/detector.c @@ -646,6 +646,43 @@ const char *disambiguate_m(SourceFile *sourcefile) { return octave_syntax_detected ? LANG_OCTAVE : LANG_MATLAB; } +#include + +const char *disambiguate_pp(SourceFile *sourcefile) { + char *p = ohcount_sourcefile_get_contents(sourcefile); + char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); + + /* prepare regular expressions */ + pcre *re; + const char *error; + int erroffset; + re = pcre_compile("(define\\s+\\w+\\s*\\(|class \\s+\\w+\\s*{)", 0, &error, &erroffset, NULL); + + for (; p < eof; p++) { + if (strncmp(p, "$include", 8) == 0 || + strncmp(p, "$INCLUDE", 8) == 0 || + strncmp(p, "end.", 4) == 0) + return LANG_PASCAL; + if (strncmp(p, "enable =>", 9) == 0 || + strncmp(p, "ensure =>", 9) == 0 || + strncmp(p, "content =>", 10) == 0 || + strncmp(p, "source =>", 9) == 0 || + strncmp(p, "include ", 8) == 0) + return LANG_PUPPET; + + /* regexp for checking for define and class declarations */ + + int rc; + int ovector[30]; + rc = pcre_exec(re, NULL, p, strlen(p), 0, 0, ovector, 30); + if(rc > 0) { + return LANG_PUPPET; + } + + } + return LANG_PASCAL; +} + #define QMAKE_SOURCES_SPACE "SOURCES +=" #define QMAKE_SOURCES "SOURCES+=" #define QMAKE_CONFIG_SPACE "CONFIG +=" diff --git a/src/hash/disambiguatefuncs.gperf b/src/hash/disambiguatefuncs.gperf index 1390d08..d48989d 100644 --- a/src/hash/disambiguatefuncs.gperf +++ b/src/hash/disambiguatefuncs.gperf @@ -11,6 +11,7 @@ const char *disambiguate_h(SourceFile *sourcefile); const char *disambiguate_in(SourceFile *sourcefile); const char *disambiguate_inc(SourceFile *sourcefile); const char *disambiguate_m(SourceFile *sourcefile); +const char *disambiguate_pp(SourceFile *sourcefile); const char *disambiguate_pro(SourceFile *sourcefile); const char *disambiguate_st(SourceFile *sourcefile); %} @@ -25,5 +26,6 @@ h, disambiguate_h in, disambiguate_in inc, disambiguate_inc m, disambiguate_m +pp, disambiguate_pp pro, disambiguate_pro st, disambiguate_st diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index 314663c..5be05d8 100644 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -137,7 +137,7 @@ pmod, LANG_PIKE png, BINARY pnt, BINARY pod, LANG_PERL -pp, LANG_PASCAL +pp, DISAMBIGUATE("pp") ppt, BINARY pro, DISAMBIGUATE("pro") py, LANG_PYTHON diff --git a/src/hash/filenames.gperf b/src/hash/filenames.gperf index 54b1685..765b5a0 100644 --- a/src/hash/filenames.gperf +++ b/src/hash/filenames.gperf @@ -10,4 +10,5 @@ Makefile.am, LANG_AUTOMAKE configure, LANG_AUTOCONF configure.ac, LANG_AUTOCONF configure.in, LANG_AUTOCONF +init.pp, LANG_PUPPET makefile, LANG_MAKE diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index 27a312d..2acd17e 100644 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -69,6 +69,7 @@ pascal, LANG_PASCAL, "Pascal", 0 perl, LANG_PERL, "Perl", 0 php, LANG_PHP, "PHP", 0 pike, LANG_PIKE, "Pike", 0 +puppet, LANG_PUPPET, "Puppet", 0 python, LANG_PYTHON, "Python", 0 r, LANG_R, "R", 0 rexx, LANG_REXX, "rexx", 0 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index d5aff72..447cd0f 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -60,6 +60,7 @@ #include "../parsers/perl.h" #include "../parsers/phphtml.h" #include "../parsers/pike.h" +#include "../parsers/puppet.h" #include "../parsers/python.h" #include "../parsers/r.h" #include "../parsers/rexx.h" @@ -151,6 +152,7 @@ pascal, parse_pascal perl, parse_perl php, parse_phtml pike, parse_pike +puppet, parse_puppet python, parse_python r, parse_r rexx, parse_rexx diff --git a/src/languages.h b/src/languages.h index a89408d..0390b78 100644 --- a/src/languages.h +++ b/src/languages.h @@ -72,6 +72,7 @@ #define LANG_PERL "perl" #define LANG_PHP "php" #define LANG_PIKE "pike" +#define LANG_PUPPET "puppet" #define LANG_PYTHON "python" #define LANG_R "r" #define LANG_REXX "rexx" diff --git a/src/parsers/puppet.rl b/src/parsers/puppet.rl new file mode 100644 index 0000000..d862f7f --- /dev/null +++ b/src/parsers/puppet.rl @@ -0,0 +1,128 @@ +// puppet.rl written by Ken Barber +// Based on pascal.rl by Mitchell Foral. mitchellcaladbolgnet + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_PUPPET_PARSER_H +#define OHCOUNT_PUPPET_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *PUPPET_LANG = LANG_PUPPET; + +// the languages entities +const char *puppet_entities[] = { + "space", "comment", "string", "any" +}; + +// constants associated with the entities +enum { + PUPPET_SPACE = 0, PUPPET_COMMENT, PUPPET_STRING, PUPPET_ANY +}; + +/*****************************************************************************/ + +%%{ + machine puppet; + write data; + include common "common.rl"; + + # Line counting machine + + action puppet_ccallback { + switch(entity) { + case PUPPET_SPACE: + ls + break; + case PUPPET_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(PUPPET_LANG) + break; + case NEWLINE: + std_newline(PUPPET_LANG) + } + } + + puppet_line_comment = '#' @comment nonnewline*; + puppet_block_comment = + '/*' @comment ( + newline %{ entity = INTERNAL_NL; } %puppet_ccallback + | + ws + | + (nonnewline - ws) @code + )* :>> '*/'; + puppet_comment = puppet_line_comment | puppet_block_comment; + + puppet_string = + '\'' @code ( + newline %{ entity = INTERNAL_NL; } %puppet_ccallback + | + ws + | + [^\r\n\f\t '\\] @code + | + '\\' nonnewline @code + )* '\''; + + puppet_line := |* + spaces ${ entity = PUPPET_SPACE; } => puppet_ccallback; + puppet_comment; + puppet_string; + newline ${ entity = NEWLINE; } => puppet_ccallback; + ^space ${ entity = PUPPET_ANY; } => puppet_ccallback; + *|; + + # Entity machine + + action puppet_ecallback { + callback(PUPPET_LANG, puppet_entities[entity], cint(ts), cint(te), + userdata); + } + + puppet_line_comment_entity = '#' nonnewline*; + puppet_block_comment_entity = '/*' any* :>> '*/'; + puppet_comment_entity = puppet_line_comment_entity | + puppet_block_comment_entity; + + puppet_entity := |* + space+ ${ entity = PUPPET_SPACE; } => puppet_ecallback; + puppet_comment_entity ${ entity = PUPPET_COMMENT; } => puppet_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with Puppet DSL code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_puppet(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + %% write init; + cs = (count) ? puppet_en_puppet_line : puppet_en_puppet_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(PUPPET_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/test/expected_dir/puppet1.pp b/test/expected_dir/puppet1.pp new file mode 100644 index 0000000..e5e6c89 --- /dev/null +++ b/test/expected_dir/puppet1.pp @@ -0,0 +1,145 @@ +puppet code class bob_openldap { +puppet blank +puppet code define server ( +puppet code $argsfile = undef, +puppet code $bdb_cachesize = '', +puppet code $bdb_checkpoint = '', +puppet code $bdb_directory = undef, +puppet code $bdb_idlcachesize = '', +puppet code $bdb_rootdn, +puppet code $bdb_rootpw, +puppet code $bdb_shm_key = '', +puppet code $bdb_suffix, +puppet code $conf_path = undef, +puppet code $conf_dir = undef, +puppet code $enable = false, +puppet code $include = [], +puppet code $includepath = undef, +puppet code $modulepath = '', +puppet code $modules = [], +puppet code $package = undef, +puppet code $pidfile = undef, +puppet code $sysconf_path = undef +puppet code ) { +puppet blank +puppet code $resource_name = "bob_openldap_server" +puppet blank +puppet code if($name != "params") { +puppet code fail("${resource_name}: This function is a singleton. Make sure the resource name is 'params'.") +puppet code } +puppet blank +puppet code case $operatingsystem { +puppet code Fedora: { +puppet code case $operatingsystemrelease { +puppet code /^(12|13)$/: { +puppet code if(!$argsfile) { $_argsfile = "/var/run/openldap/slapd.args" } +puppet code if(!$bdb_directory) { $_bdb_directory = "/var/lib/ldap" } +puppet code if(!$conf_path) { $_conf_path = "/etc/openldap/slapd.conf" } +puppet code if(!$conf_dir) { $_conf_dir = "/etc/openldap/slapd.d" } +puppet code if(!$package) { $_package = ["openldap-servers"] } +puppet code if(!$pidfile) { $_pidfile = "/var/run/openldap/slapd.pid" } +puppet code if(!$service) { $_service = "slapd" } +puppet code if(!$sysconf_path) { $_sysconf_path = "/etc/sysconfig/ldap" } +puppet code } +puppet code } +puppet code } +puppet code } +puppet blank +puppet comment # Presume the OS did not match and because these args are necessary, just +puppet comment # bail with an error. +puppet code if(!($_argsfile and $_bdb_directory and $_pidfile and $_conf_path and +puppet code $_package and $_service and $_sysconf_path and $_conf_dir)) { +puppet code fail("${resource_name}: Unsupported operating system: ${operatingsystem} version ${operatingsystemrelease} and you have not setup the args for: argsfile, bdb_directory, conf_dir, conf_path, package, pidfile, sysconf_path and service.") +puppet code } +puppet blank +puppet comment # Fix paths - add forward slashes at the end of strings without them +puppet code $_includepath = regsubst($includepath, '([^/])$', '\1/') +puppet code $_dbconf_path = "${_bdb_directory}/DB_CONFIG" +puppet blank +puppet comment # ... +puppet code file { +puppet code $_conf_path: +puppet code content => template("bob_openldap/slapd.conf"), +puppet code require => Package[$_package], +puppet code owner => "ldap", +puppet code group => "root", +puppet code mode => "0440", +puppet code notify => Service[$_service]; +puppet code $_sysconf_path: +puppet code content => template("bob_openldap/ldap.sysconf"), +puppet code require => Package[$_package], +puppet code owner => "root", +puppet code group => "root", +puppet code mode => "0644"; +puppet code $_conf_dir: +puppet code force => true, +puppet code ensure => absent, +puppet code before => Service[$_service]; +puppet code $_dbconf_path: +puppet code content => "", +puppet code notify => Service[$_service]; +puppet code } +puppet code package { +puppet code $_package: +puppet code ensure => installed; +puppet code } +puppet code service { +puppet code $_service: +puppet code ensure => $enable ? { +puppet code true => "running", +puppet code false => "stopped" +puppet code }, +puppet code enable => $enable, +puppet code hasstatus => true, +puppet code require => [ Package[$_package], File[$_conf_path] ]; +puppet code } +puppet code } +puppet blank +puppet code define client ( +puppet code $base, +puppet code $network_timeout = '', +puppet code $path = undef, +puppet code $timeout = '', +puppet code $binddn = '', +puppet code $tls_cacertdir = undef, +puppet code $uri +puppet code ) { +puppet blank +puppet code $resource_name = "bob_openldap_client" +puppet blank +puppet code if($name != "params") { +puppet code fail("${resource_name}: This function is a singleton. Make sure the resource name is 'params'.") +puppet code } +puppet blank +puppet code case $operatingsystem { +puppet code Fedora: { +puppet code case $operatingsystemrelease { +puppet code /^(12|13)$/: { +puppet code if(!$tls_cacertdir) { $_tls_cacertdir = "/etc/openldap/cacerts" } +puppet code if(!$path) { $_path = "/etc/openldap/ldap.conf" } +puppet code } +puppet code } +puppet code } +puppet code } +puppet blank +puppet comment # Presume the OS did not match and because these args are necessary, just +puppet comment # bail with an error. +puppet code if(!($_tls_cacertdir and $_path)) { +puppet code fail("${resource_name}: Unsupported operating system: ${operatingsystem} version ${operatingsystemrelease} and you have not setup the args for: tls_cacertdir, path.") +puppet code } +puppet blank +puppet comment # Fix some vars, ready for templating +puppet code $_base = $base +puppet code $_binddn = $binddn +puppet code $_network_timeout = $network_timeout +puppet code $_timeout = $timeout +puppet code $_uri = $uri +puppet blank +puppet code file { +puppet code $_path: +puppet code content => template("bob_openldap/ldap.conf") +puppet code } +puppet blank +puppet code } +puppet blank +puppet code } diff --git a/test/src_dir/puppet1.pp b/test/src_dir/puppet1.pp new file mode 100644 index 0000000..f30389d --- /dev/null +++ b/test/src_dir/puppet1.pp @@ -0,0 +1,145 @@ +class bob_openldap { + + define server ( + $argsfile = undef, + $bdb_cachesize = '', + $bdb_checkpoint = '', + $bdb_directory = undef, + $bdb_idlcachesize = '', + $bdb_rootdn, + $bdb_rootpw, + $bdb_shm_key = '', + $bdb_suffix, + $conf_path = undef, + $conf_dir = undef, + $enable = false, + $include = [], + $includepath = undef, + $modulepath = '', + $modules = [], + $package = undef, + $pidfile = undef, + $sysconf_path = undef + ) { + + $resource_name = "bob_openldap_server" + + if($name != "params") { + fail("${resource_name}: This function is a singleton. Make sure the resource name is 'params'.") + } + + case $operatingsystem { + Fedora: { + case $operatingsystemrelease { + /^(12|13)$/: { + if(!$argsfile) { $_argsfile = "/var/run/openldap/slapd.args" } + if(!$bdb_directory) { $_bdb_directory = "/var/lib/ldap" } + if(!$conf_path) { $_conf_path = "/etc/openldap/slapd.conf" } + if(!$conf_dir) { $_conf_dir = "/etc/openldap/slapd.d" } + if(!$package) { $_package = ["openldap-servers"] } + if(!$pidfile) { $_pidfile = "/var/run/openldap/slapd.pid" } + if(!$service) { $_service = "slapd" } + if(!$sysconf_path) { $_sysconf_path = "/etc/sysconfig/ldap" } + } + } + } + } + + # Presume the OS did not match and because these args are necessary, just + # bail with an error. + if(!($_argsfile and $_bdb_directory and $_pidfile and $_conf_path and + $_package and $_service and $_sysconf_path and $_conf_dir)) { + fail("${resource_name}: Unsupported operating system: ${operatingsystem} version ${operatingsystemrelease} and you have not setup the args for: argsfile, bdb_directory, conf_dir, conf_path, package, pidfile, sysconf_path and service.") + } + + # Fix paths - add forward slashes at the end of strings without them + $_includepath = regsubst($includepath, '([^/])$', '\1/') + $_dbconf_path = "${_bdb_directory}/DB_CONFIG" + + # ... + file { + $_conf_path: + content => template("bob_openldap/slapd.conf"), + require => Package[$_package], + owner => "ldap", + group => "root", + mode => "0440", + notify => Service[$_service]; + $_sysconf_path: + content => template("bob_openldap/ldap.sysconf"), + require => Package[$_package], + owner => "root", + group => "root", + mode => "0644"; + $_conf_dir: + force => true, + ensure => absent, + before => Service[$_service]; + $_dbconf_path: + content => "", + notify => Service[$_service]; + } + package { + $_package: + ensure => installed; + } + service { + $_service: + ensure => $enable ? { + true => "running", + false => "stopped" + }, + enable => $enable, + hasstatus => true, + require => [ Package[$_package], File[$_conf_path] ]; + } + } + + define client ( + $base, + $network_timeout = '', + $path = undef, + $timeout = '', + $binddn = '', + $tls_cacertdir = undef, + $uri + ) { + + $resource_name = "bob_openldap_client" + + if($name != "params") { + fail("${resource_name}: This function is a singleton. Make sure the resource name is 'params'.") + } + + case $operatingsystem { + Fedora: { + case $operatingsystemrelease { + /^(12|13)$/: { + if(!$tls_cacertdir) { $_tls_cacertdir = "/etc/openldap/cacerts" } + if(!$path) { $_path = "/etc/openldap/ldap.conf" } + } + } + } + } + + # Presume the OS did not match and because these args are necessary, just + # bail with an error. + if(!($_tls_cacertdir and $_path)) { + fail("${resource_name}: Unsupported operating system: ${operatingsystem} version ${operatingsystemrelease} and you have not setup the args for: tls_cacertdir, path.") + } + + # Fix some vars, ready for templating + $_base = $base + $_binddn = $binddn + $_network_timeout = $network_timeout + $_timeout = $timeout + $_uri = $uri + + file { + $_path: + content => template("bob_openldap/ldap.conf") + } + + } + +} diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index 3602553..aae6bca 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -128,6 +128,7 @@ void test_parser_verify_entity(SourceFile *sf, const char *entity, #include "parsers/test_pascal.h" #include "parsers/test_perl.h" #include "parsers/test_pike.h" +#include "parsers/test_puppet.h" #include "parsers/test_python.h" #include "parsers/test_r.h" #include "parsers/test_rexx.h" diff --git a/test/unit/parsers/test_puppet.h b/test/unit/parsers/test_puppet.h new file mode 100644 index 0000000..8d55b09 --- /dev/null +++ b/test/unit/parsers/test_puppet.h @@ -0,0 +1,23 @@ + +void test_puppet_comments() { + test_parser_verify_parse( + test_parser_sourcefile("puppet", " #comment"), + "puppet", "", "#comment", 0 + ); +} + +void test_puppet_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("puppet", " #comment"), + "comment", "#comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("puppet", " /*comment*/"), + "comment", "/*comment*/" + ); +} + +void all_puppet_tests() { + test_puppet_comments(); + test_puppet_comment_entities(); +} From df7d2f4aac77f15eaae3b22447d3f9da3b0c19c7 Mon Sep 17 00:00:00 2001 From: Scott Lawrence Date: Fri, 23 Jul 2010 14:37:01 -0400 Subject: [PATCH 287/387] added check for ragel --- src/parsers/compile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/parsers/compile b/src/parsers/compile index 1327c59..e23527a 100755 --- a/src/parsers/compile +++ b/src/parsers/compile @@ -2,6 +2,15 @@ # Compiles all .rl files for Ohcount. # Written by Mitchell Foral. mitchellcaladbolgnet. +# check to make sure we have ragel +if `type ragel > /dev/null 2> /dev/null` +then + echo "Found ragel, compiling..." +else + echo "ragel not found, aborting" >&2 + exit 1 +fi + for file in *.rl do echo "Compiling $file" From 9c40942e01581a8e57539fa256d72fdc978a4a03 Mon Sep 17 00:00:00 2001 From: Scott Lawrence Date: Fri, 23 Jul 2010 14:38:57 -0400 Subject: [PATCH 288/387] added checks for gperf, erroring out if not found --- src/hash/generate_headers | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/hash/generate_headers b/src/hash/generate_headers index 679a8b3..07af20a 100755 --- a/src/hash/generate_headers +++ b/src/hash/generate_headers @@ -1,5 +1,14 @@ #!/bin/sh +# Check for gperf +if `type gperf > /dev/null 2> /dev/null` +then + echo "Found gperf, making headers..." +else + echo "gperf not found, aborting" >&2 + exit 1 +fi + gperf -L ANSI-C -E -D -K key -H ohcount_hash_language -N ohcount_hash_language_from_name -t languages.gperf > language_hash.c gperf -L ANSI-C -E -D -K key -H ohcount_hash_extension -N ohcount_hash_language_from_ext -t extensions.gperf > extension_hash.h gperf -L ANSI-C -E -D -K key -H ohcount_hash_filename -N ohcount_hash_language_from_filename -t filenames.gperf > filename_hash.h From 02f4c4c3e94fcca794f11e6c649d0d68cf822866 Mon Sep 17 00:00:00 2001 From: Scott Lawrence Date: Fri, 23 Jul 2010 16:09:18 -0400 Subject: [PATCH 289/387] added golang detection and parsing, based on C --- src/hash/extensions.gperf | 1 + src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 2 + src/languages.h | 1 + src/parsers/golang.rl | 184 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 189 insertions(+) create mode 100644 src/parsers/golang.rl diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index 5be05d8..13bbfc5 100644 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -69,6 +69,7 @@ fs, LANG_FSHARP ftn, DISAMBIGUATE("fortran") gif, BINARY glsl, LANG_GLSL +go, LANG_GOLANG groovy, LANG_GROOVY gz, BINARY h, DISAMBIGUATE("h") diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index 2acd17e..e729689 100644 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -39,6 +39,7 @@ fortranfixed, LANG_FORTRANFIXED, "Fortan (Fixed-format)", 0 fortranfree, LANG_FORTRANFREE, "Fortan (Free-format)", 0 fsharp, LANG_FSHARP, "F#", 0 glsl, LANG_GLSL, "OpenGL Shading Language", 0 +golang, LANG_GOLANG, "Golang", 0 groovy, LANG_GROOVY, "Groovy", 0 haml, LANG_HAML, "Haml", 1 haskell, LANG_HASKELL, "Haskell", 0 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index 447cd0f..b8aeb96 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -30,6 +30,7 @@ #include "../parsers/fortranfree.h" #include "../parsers/fsharp.h" #include "../parsers/glsl.h" +#include "../parsers/golang.h" #include "../parsers/groovy.h" #include "../parsers/haml.h" #include "../parsers/haskell.h" @@ -122,6 +123,7 @@ fortranfixed, parse_fortranfixed fortranfree, parse_fortranfree fsharp, parse_fsharp glsl, parse_glsl +golang, parse_golang groovy, parse_groovy haskell, parse_haskell haml, parse_haml diff --git a/src/languages.h b/src/languages.h index 0390b78..a3e2e83 100644 --- a/src/languages.h +++ b/src/languages.h @@ -42,6 +42,7 @@ #define LANG_FORTRANFREE "fortranfree" #define LANG_FSHARP "fsharp" #define LANG_GLSL "glsl" +#define LANG_GOLANG "golang" #define LANG_GROOVY "groovy" #define LANG_HASKELL "haskell" #define LANG_HAML "haml" diff --git a/src/parsers/golang.rl b/src/parsers/golang.rl new file mode 100644 index 0000000..60ae814 --- /dev/null +++ b/src/parsers/golang.rl @@ -0,0 +1,184 @@ +// c.rl written by Mitchell Foral. mitchellcaladbolgnet. + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_GOLANG_PARSER_H +#define OHCOUNT_GOLANG_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *GOLANG_LANG = LANG_GOLANG; + +// the languages entities +const char *golang_entities[] = { + "space", "comment", "string", "number", "preproc", + "keyword", "identifier", "operator", "any" +}; + +// constants associated with the entities +enum { + GOLANG_SPACE = 0, GOLANG_COMMENT, GOLANG_STRING, GOLANG_NUMBER, GOLANG_PREPROC, + GOLANG_KEYWORD, GOLANG_IDENTIFIER, GOLANG_OPERATOR, GOLANG_ANY +}; + +/*****************************************************************************/ + +%%{ + machine golang; + write data; + include common "common.rl"; + + # Line counting machine + + action golang_ccallback { + switch(entity) { + case GOLANG_SPACE: + ls + break; + case GOLANG_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(GOLANG_LANG) + break; + case NEWLINE: + std_newline(GOLANG_LANG) + } + } + + golang_line_comment = + '//' @comment ( + escaped_newline %{ entity = INTERNAL_NL; } %golang_ccallback + | + ws + | + (nonnewline - ws) @comment + )*; + golang_block_comment = + '/*' @comment ( + newline %{ entity = INTERNAL_NL; } %golang_ccallback + | + ws + | + (nonnewline - ws) @comment + )* :>> '*/'; + golang_comment = golang_line_comment | golang_block_comment; + + golang_sq_str = + '\'' @code ( + escaped_newline %{ entity = INTERNAL_NL; } %golang_ccallback + | + ws + | + [^\t '\\] @code + | + '\\' nonnewline @code + )* '\''; + golang_dq_str = + '"' @code ( + escaped_newline %{ entity = INTERNAL_NL; } %golang_ccallback + | + ws + | + [^\t "\\] @code + | + '\\' nonnewline @code + )* '"'; + golang_string = golang_sq_str | golang_dq_str; + + golang_line := |* + spaces ${ entity = GOLANG_SPACE; } => golang_ccallback; + golang_comment; + golang_string; + newline ${ entity = NEWLINE; } => golang_ccallback; + ^space ${ entity = GOLANG_ANY; } => golang_ccallback; + *|; + + # Entity machine + + action golang_ecallback { + callback(GOLANG_LANG, golang_entities[entity], cint(ts), cint(te), userdata); + } + + golang_line_comment_entity = '//' (escaped_newline | nonnewline)*; + golang_block_comment_entity = '/*' any* :>> '*/'; + golang_comment_entity = golang_line_comment_entity | golang_block_comment_entity; + + golang_string_entity = sq_str_with_escapes | dq_str_with_escapes; + + golang_number_entity = float | integer; + + golang_preprogolang_word = + 'define' | 'elif' | 'else' | 'endif' | 'error' | 'if' | 'ifdef' | + 'ifndef' | 'import' | 'include' | 'line' | 'pragma' | 'undef' | + 'using' | 'warning'; + # TODO: find some way of making preproc match the beginning of a line. + # Putting a 'when starts_line' conditional throws an assertion error. + golang_preprogolang_entity = + '#' space* (golang_block_comment_entity space*)? + golang_preprogolang_word (escaped_newline | nonnewline)*; + + golang_identifier_entity = (alpha | '_') (alnum | '_')*; + + golang_keyword_entity = + 'and' | 'and_eq' | 'asm' | 'auto' | 'bitand' | 'bitor' | 'bool' | + 'break' | 'case' | 'catch' | 'char' | 'class' | 'compl' | 'const' | + 'const_cast' | 'continue' | 'default' | 'delete' | 'do' | 'double' | + 'dynamigolang_cast' | 'else' | 'enum' | 'explicit' | 'export' | 'extern' | + 'false' | 'float' | 'for' | 'friend' | 'goto' | 'if' | 'inline' | 'int' | + 'long' | 'mutable' | 'namespace' | 'new' | 'not' | 'not_eq' | + 'operator' | 'or' | 'or_eq' | 'private' | 'protected' | 'public' | + 'register' | 'reinterpret_cast' | 'return' | 'short' | 'signed' | + 'sizeof' | 'static' | 'statigolang_cast' | 'struct' | 'switch' | + 'template' | 'this' | 'throw' | 'true' | 'try' | 'typedef' | 'typeid' | + 'typename' | 'union' | 'unsigned' | 'using' | 'virtual' | 'void' | + 'volatile' | 'wchar_t' | 'while' | 'xor' | 'xor_eq'; + + golang_operator_entity = [+\-/*%<>!=^&|?~:;.,()\[\]{}]; + + golang_entity := |* + space+ ${ entity = GOLANG_SPACE; } => golang_ecallback; + golang_comment_entity ${ entity = GOLANG_COMMENT; } => golang_ecallback; + golang_string_entity ${ entity = GOLANG_STRING; } => golang_ecallback; + golang_number_entity ${ entity = GOLANG_NUMBER; } => golang_ecallback; + golang_preprogolang_entity ${ entity = GOLANG_PREPROC; } => golang_ecallback; + golang_identifier_entity ${ entity = GOLANG_IDENTIFIER; } => golang_ecallback; + golang_keyword_entity ${ entity = GOLANG_KEYWORD; } => golang_ecallback; + golang_operator_entity ${ entity = GOLANG_OPERATOR; } => golang_ecallback; + ^(space | digit) ${ entity = GOLANG_ANY; } => golang_ecallback; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with C/C++ code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_golang(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + %% write init; + cs = (count) ? golang_en_golang_line : golang_en_golang_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(GOLANG_LANG) } +} + +const char *ORIG_GOLANG_LANG = LANG_GOLANG; + +#endif + +/*****************************************************************************/ From f5c1829b961353751be67ff0faea65cf77b5b73f Mon Sep 17 00:00:00 2001 From: Scott Lawrence Date: Fri, 23 Jul 2010 16:20:08 -0400 Subject: [PATCH 290/387] added golang unit tests --- test/unit/parser_test.h | 1 + test/unit/parsers/test_golang.h | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 test/unit/parsers/test_golang.h diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index aae6bca..411013b 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -105,6 +105,7 @@ void test_parser_verify_entity(SourceFile *sf, const char *entity, #include "parsers/test_fortran.h" #include "parsers/test_fsharp.h" #include "parsers/test_glsl.h" +#include "parsers/test_golang.h" #include "parsers/test_groovy.h" #include "parsers/test_haml.h" #include "parsers/test_haskell.h" diff --git a/test/unit/parsers/test_golang.h b/test/unit/parsers/test_golang.h new file mode 100644 index 0000000..7463d4b --- /dev/null +++ b/test/unit/parsers/test_golang.h @@ -0,0 +1,39 @@ + +void test_golang_comments() { + test_parser_verify_parse( + test_parser_sourcefile("go", " //comment"), + "go", "", "//comment", 0 + ); +} + +void test_golang_empty_comments() { + test_parser_verify_parse( + test_parser_sourcefile("go", " //\n"), + "go", "", "//\n", 0 + ); +} + +void test_golang_block_comment() { + test_parser_verify_parse( + test_parser_sourcefile("go", "/*c*/"), + "go", "", "/*c*/", 0 + ); +} + +void test_golang_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("go", " //comment"), + "comment", "//comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("go", " /*comment*/"), + "comment", "/*comment*/" + ); +} + +void all_golang_tests() { + test_golang_comments(); + test_golang_empty_comments(); + test_golang_block_comment(); + test_golang_comment_entities(); +} From 79c779a5ae3e7c55e308f04ec034d0b7b09291ab Mon Sep 17 00:00:00 2001 From: Scott Lawrence Date: Fri, 23 Jul 2010 16:23:55 -0400 Subject: [PATCH 291/387] made README formatting consistent --- README | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README b/README index c7c2b00..cfdfb17 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -== Ohcount +== Ohcount == NOTE: THE PRIMARY DOCUMENTATION FOR OHCOUNT IS EXTRACTED FROM SOURCE CODE BY DOXYGEN. FOR THE MOST UP-TO-DATE DOCS, PLEASE SEE BELOW FOR INFO @@ -20,7 +20,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . -== Overview +== Overview == Ohcount is a library for counting lines of source code. It was originally developed at Ohloh, and is used to generate @@ -41,7 +41,7 @@ individual source file. Ohcount includes a Ruby binding which allows you to directly access its language detection features from a Ruby application. -== System Requirements +== System Requirements == Ohcount is supported on Mac OS X 10.4 and 10.5 and Ubuntu 8.04 LTS. Other Linux environments should also work, but your mileage may vary. @@ -90,6 +90,6 @@ To build the ruby wrapper, run "bash build ruby". To build the python wrapper, run "python python/setup.py build; python python/setup.py install". The python wrapper is new and has only been tested on Gentoo and CentOS. Feedback on it is particularly welcome. -DEPENDENCIES -============ -SWIG, pcre, ragel, gperf, bash +== Dependencies == + +To build ohcount, your system will need: SWIG, pcre, ragel, gperf, bash From 5c8961ab3161ad151384d823eb24b723e7b886f8 Mon Sep 17 00:00:00 2001 From: Scott Lawrence Date: Fri, 23 Jul 2010 16:27:07 -0400 Subject: [PATCH 292/387] updated author information --- src/parsers/golang.rl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parsers/golang.rl b/src/parsers/golang.rl index 60ae814..13fb105 100644 --- a/src/parsers/golang.rl +++ b/src/parsers/golang.rl @@ -1,4 +1,4 @@ -// c.rl written by Mitchell Foral. mitchellcaladbolgnet. +// c.rl written by Scott Lawrence /************************* Required for every parser *************************/ #ifndef OHCOUNT_GOLANG_PARSER_H From ec95ee6a11c8a1b9753b5460f3c6d7c57092547c Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Thu, 9 Sep 2010 13:33:11 +1000 Subject: [PATCH 293/387] Added a parser for NSIS files (.nsi, .nsh). --- src/hash/extensions.gperf | 2 + src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 2 + src/languages.h | 1 + src/parsers/nsis.rl | 119 ++++++++++++++++++++++++++++++++++++++++++ test/detect_files/foo.nsh | 1 + test/detect_files/foo.nsi | 1 + test/expected_dir/foo.nsh | 17 ++++++ test/expected_dir/foo.nsi | 15 ++++++ test/src_dir/foo.nsh | 17 ++++++ test/src_dir/foo.nsi | 15 ++++++ test/unit/detector_test.h | 2 + test/unit/parser_test.h | 2 + test/unit/parsers/test_nsis.h | 51 ++++++++++++++++++ 14 files changed, 246 insertions(+) create mode 100644 src/parsers/nsis.rl create mode 100644 test/detect_files/foo.nsh create mode 100644 test/detect_files/foo.nsi create mode 100644 test/expected_dir/foo.nsh create mode 100644 test/expected_dir/foo.nsi create mode 100644 test/src_dir/foo.nsh create mode 100644 test/src_dir/foo.nsi create mode 100644 test/unit/parsers/test_nsis.h diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index 5be05d8..128cede 100644 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -117,6 +117,8 @@ mpg, BINARY mxml, LANG_MXML nix, LANG_NIX nse, LANG_LUA +nsi, LANG_NSIS +nsh, LANG_NSIS ob2, LANG_OBERON obn, LANG_OBERON ogg, BINARY diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index 2acd17e..32da80b 100644 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -60,6 +60,7 @@ modula2, LANG_MODULA2, "Modula-2", 0 modula3, LANG_MODULA3, "Modula-3", 0 mxml, LANG_MXML, "MXML", 1 nix, LANG_NIX, "Nix", 0 +nsis, LANG_NSIS, "NSIS", 0 oberon, LANG_OBERON, "Oberon", 0 objective_c, LANG_OBJECTIVE_C, "Objective-C", 0 objective_j, LANG_OBJECTIVE_J, "Objective-J", 0 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index 447cd0f..929637b 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -51,6 +51,7 @@ #include "../parsers/modula3.h" #include "../parsers/mxml.h" #include "../parsers/nix.h" +#include "../parsers/nsis.h" #include "../parsers/oberon.h" #include "../parsers/objective_c.h" #include "../parsers/objective_j.h" @@ -143,6 +144,7 @@ modula2, parse_modula2 modula3, parse_modula3 mxml, parse_mxml nix, parse_nix +nsis, parse_nsis oberon, parse_oberon objective_c, parse_objective_c objective_j, parse_objective_j diff --git a/src/languages.h b/src/languages.h index 0390b78..a92ddc6 100644 --- a/src/languages.h +++ b/src/languages.h @@ -63,6 +63,7 @@ #define LANG_MODULA3 "modula3" #define LANG_MXML "mxml" #define LANG_NIX "nix" +#define LANG_NSIS "nsis" #define LANG_OBERON "oberon" #define LANG_OBJECTIVE_C "objective_c" #define LANG_OBJECTIVE_J "objective_j" diff --git a/src/parsers/nsis.rl b/src/parsers/nsis.rl new file mode 100644 index 0000000..8b21586 --- /dev/null +++ b/src/parsers/nsis.rl @@ -0,0 +1,119 @@ +// nsis.rl written by Chris Morgan. + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_NSIS_PARSER_H +#define OHCOUNT_NSIS_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *NSIS_LANG = LANG_NSIS; + +// the languages entities +const char *nsis_entities[] = { + "space", "comment", "string", "any" +}; + +// constants associated with the entities +enum { + NSIS_SPACE = 0, NSIS_COMMENT, NSIS_STRING, NSIS_ANY +}; + +/*****************************************************************************/ + +%%{ + machine nsis; + write data; + include common "common.rl"; + + # Line counting machine + + action nsis_ccallback { + switch(entity) { + case NSIS_SPACE: + ls + break; + case NSIS_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(NSIS_LANG) + break; + case NEWLINE: + std_newline(NSIS_LANG) + } + } + + nsis_line_comment = ('#' | ';') @comment nonnewline*; + nsis_block_comment = + '/*' @comment ( + newline %{ entity = INTERNAL_NL; } %nsis_ccallback + | + ws + | + (nonnewline - ws) @comment + )* :>> '*/'; + nsis_comment = nsis_line_comment | nsis_block_comment; + + nsis_bt_str = '`' @code ([^\r\n\f`\\] | '\\' nonnewline)* '`'; + nsis_sq_str = '\'' @code ([^\r\n\f'\\] | '\\' nonnewline)* '\''; + nsis_dq_str = '"' @code ([^\r\n\f"\\] | '\\' nonnewline)* '"'; + nsis_string = nsis_bt_str | nsis_sq_str | nsis_dq_str; + + nsis_line := |* + spaces ${ entity = NSIS_SPACE; } => nsis_ccallback; + nsis_comment; + nsis_string; + newline ${ entity = NEWLINE; } => nsis_ccallback; + ^space ${ entity = NSIS_ANY; } => nsis_ccallback; + *|; + + # Entity machine + + action nsis_ecallback { + callback(NSIS_LANG, nsis_entities[entity], cint(ts), cint(te), userdata); + } + + nsis_line_comment_entity = ('#' | '//') nonnewline*; + nsis_block_comment_entity = '/*' any* :>> '*/'; + nsis_comment_entity = nsis_line_comment_entity | nsis_block_comment_entity; + + nsis_entity := |* + space+ ${ entity = NSIS_SPACE; } => nsis_ecallback; + nsis_comment_entity ${ entity = NSIS_COMMENT; } => nsis_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with NSIS code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_nsis(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + %% write init; + cs = (count) ? nsis_en_nsis_line : nsis_en_nsis_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(NSIS_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/test/detect_files/foo.nsh b/test/detect_files/foo.nsh new file mode 100644 index 0000000..f5faef9 --- /dev/null +++ b/test/detect_files/foo.nsh @@ -0,0 +1 @@ +; No need for special content in here, detected by extension diff --git a/test/detect_files/foo.nsi b/test/detect_files/foo.nsi new file mode 100644 index 0000000..f5faef9 --- /dev/null +++ b/test/detect_files/foo.nsi @@ -0,0 +1 @@ +; No need for special content in here, detected by extension diff --git a/test/expected_dir/foo.nsh b/test/expected_dir/foo.nsh new file mode 100644 index 0000000..0eddb8b --- /dev/null +++ b/test/expected_dir/foo.nsh @@ -0,0 +1,17 @@ +nsis comment ; NSIS "header" libraries can be in .nsh files. +nsis comment /* Copyright some time +nsis comment * never +nsis comment * and not much of that either +nsis comment "still a comment" +nsis comment */ +nsis blank +nsis code !macro SillyMacro Param1 +nsis comment ; ... Because we can ;-) +nsis code !error "Why did you call this macro, ${Param1}? That was silly." +nsis code !macroend +nsis blank +nsis code Function Die +nsis comment # Likewise, because we can. +nsis code DetailPrint "Aarrrrggghh! I died." +nsis code Quit +nsis code FunctionEnd diff --git a/test/expected_dir/foo.nsi b/test/expected_dir/foo.nsi new file mode 100644 index 0000000..243329e --- /dev/null +++ b/test/expected_dir/foo.nsi @@ -0,0 +1,15 @@ +nsis comment ; some nsis code +nsis comment /* +nsis comment * lorem +nsis comment ipsum +nsis comment dolor sit amet etcetera +nsis comment */ +nsis blank +nsis code !include LogicLib.nsh +nsis code OutFile foo.exe +nsis blank +nsis code Section +nsis code IfFileExists ${__FILE__} 0 +2 ; comments can be inline +nsis comment # Use of ; in a string on the next line +nsis code MessageBox MB_OK "You moved this installer file; you shouldn't do that ;-)" +nsis code SectionEnd diff --git a/test/src_dir/foo.nsh b/test/src_dir/foo.nsh new file mode 100644 index 0000000..8638e86 --- /dev/null +++ b/test/src_dir/foo.nsh @@ -0,0 +1,17 @@ +; NSIS "header" libraries can be in .nsh files. +/* Copyright some time + * never + * and not much of that either +"still a comment" +*/ + +!macro SillyMacro Param1 + ; ... Because we can ;-) + !error "Why did you call this macro, ${Param1}? That was silly." +!macroend + +Function Die + # Likewise, because we can. + DetailPrint "Aarrrrggghh! I died." + Quit +FunctionEnd diff --git a/test/src_dir/foo.nsi b/test/src_dir/foo.nsi new file mode 100644 index 0000000..84ebfd8 --- /dev/null +++ b/test/src_dir/foo.nsi @@ -0,0 +1,15 @@ +; some nsis code +/* + * lorem +ipsum +dolor sit amet etcetera +*/ + +!include LogicLib.nsh +OutFile foo.exe + +Section + IfFileExists ${__FILE__} 0 +2 ; comments can be inline + # Use of ; in a string on the next line + MessageBox MB_OK "You moved this installer file; you shouldn't do that ;-)" +SectionEnd diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index c8f952f..56e39ff 100644 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -114,6 +114,8 @@ void test_detector_detect_polyglot() { ASSERT_DETECT(LANG_PHP, "php.inc"); ASSERT_DETECT(LANG_FSHARP, "fs1.fs"); ASSERT_DETECT(LANG_AUTOCONF, "m4.m4"); + ASSERT_DETECT(LANG_NSIS, "foo.nsi"); + ASSERT_DETECT(LANG_NSIS, "foo.nsh"); ASSERT_NODETECT("empty.inc"); } diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index aae6bca..df671f5 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -122,6 +122,7 @@ void test_parser_verify_entity(SourceFile *sf, const char *entity, #include "parsers/test_metapost.h" #include "parsers/test_mxml.h" #include "parsers/test_nix.h" +#include "parsers/test_nsis.h" #include "parsers/test_objective_j.h" #include "parsers/test_ocaml.h" #include "parsers/test_octave.h" @@ -296,6 +297,7 @@ void all_parser_tests() { all_metapost_tests(); all_mxml_tests(); all_nix_tests(); + all_nsis_tests(); all_objective_j_tests(); all_ocaml_tests(); all_octave_tests(); diff --git a/test/unit/parsers/test_nsis.h b/test/unit/parsers/test_nsis.h new file mode 100644 index 0000000..027ee5f --- /dev/null +++ b/test/unit/parsers/test_nsis.h @@ -0,0 +1,51 @@ + +void test_nsis_comments() { + test_parser_verify_parse( + test_parser_sourcefile("nsis", " ;comment"), + "nsis", "", ";comment", 0 + ); + test_parser_verify_parse( + test_parser_sourcefile("nsis", " #comment"), + "nsis", "", "#comment", 0 + ); + test_parser_verify_parse( + test_parser_sourcefile("nsis", " /*comment*/"), + "nsis", "", "/*comment*/", 0 + ); +} + +void test_nsis_strings() { + test_parser_verify_parse( + test_parser_sourcefile("nsis", "\"abc;not a 'comment\""), + "nsis", "\"abc;not a 'comment\"", "", 0 + ); + test_parser_verify_parse( + test_parser_sourcefile("nsis", "'abc;not a \"comment'"), + "nsis", "'abc;not a \"comment'", "", 0 + ); + test_parser_verify_parse( + test_parser_sourcefile("nsis", "`abc;not a 'comment`"), + "nsis", "`abc;not a 'comment`", "", 0 + ); +} + +void test_nsis_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("nsis", " ;comment"), + "comment", ";comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("nsis", " #comment"), + "comment", "#comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("nsis", " /*comment*/"), + "comment", "/*comment*/" + ); +} + +void all_nsis_tests() { + test_nsis_comments(); + test_nsis_strings(); + test_nsis_comment_entities(); +} From fdda0917274ac2cef2dd34ae5585446187314fb0 Mon Sep 17 00:00:00 2001 From: Robert Schultz Date: Wed, 27 Oct 2010 14:50:15 -0400 Subject: [PATCH 294/387] Added support for detecting certain bash scripts as shell scripts --- src/hash/languages.gperf | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index 2acd17e..5e9eec3 100644 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -10,6 +10,7 @@ autoconf, LANG_AUTOCONF, "Autoconf", 2 automake, LANG_AUTOMAKE, "Automake", 2 awk, LANG_AWK, "AWK", 0 bat, LANG_BAT, "DOS batch script", 0 +bash, LANG_SHELL, "shell script", 0 blitzmax, LANG_BLITZMAX, "BlitzMax", 0 boo, LANG_BOO, "Boo", 0 brainfuck, LANG_BRAINFUCK, "Brainfuck", 0 From ae5acfebe8670a5f076e06d881643992110896ce Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Fri, 21 Jan 2011 07:44:28 -0800 Subject: [PATCH 295/387] Fixes compiler warnings. We were failing to check the return result on several system calls. I've added the appropriate checks, with simple aborts in the case of failure. --- src/detector.c | 10 ++++++++-- src/diff.c | 7 +++++-- test/unit/detector_test.h | 4 ++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/detector.c b/src/detector.c index f687dc9..041a053 100644 --- a/src/detector.c +++ b/src/detector.c @@ -129,7 +129,10 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { log_it("contents:"); log_it(contents); length = contents ? strlen(contents) : 0; - write(fd, contents, length); + if (write(fd, contents, length) != length) { + fprintf(stderr, "src/detector.c: Could not write temporary file %s.\n", path); + exit(1); + } close(fd); tmpfile = 1; } @@ -137,7 +140,10 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { sprintf(command, "file -b '%s'", path); FILE *f = popen(command, "r"); if (f) { - fgets(line, sizeof(line), f); + if (fgets(line, sizeof(line), f) == NULL) { + fprintf(stderr, "src/detector.c: fgets() failed\n"); + exit(1); + } char *eol = line + strlen(line); for (p = line; p < eol; p++) *p = tolower(*p); p = strstr(line, "script text"); diff --git a/src/diff.c b/src/diff.c index 5465c9d..019a119 100644 --- a/src/diff.c +++ b/src/diff.c @@ -624,9 +624,12 @@ static void output(int *added, int *removed) { char *tmp_file_from_buf(const char *buf) { char *template = "/tmp/ohcount_diff_XXXXXXX"; char *path = strdup(template); - + int fd = mkstemp(path); - write(fd, buf, strlen(buf)); + if (write(fd, buf, strlen(buf)) != strlen(buf)) { + fprintf(stderr, "src/diff.c: Could not write temporary file %s.\n", path); + exit(1); + } close(fd); return path; } diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index c8f952f..3c87692 100644 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -143,10 +143,10 @@ void test_detector_csharp_or_clearsilver() { void test_detector_basic() { ASSERT_DETECT(LANG_VISUALBASIC, "visual_basic.bas"); ASSERT_DETECT(LANG_CLASSIC_BASIC, "classic_basic.b"); - system("mv ../detect_files/frx1.frx ../detect_files/frx1.frx2"); + assert(system("mv ../detect_files/frx1.frx ../detect_files/frx1.frx2") == 0); ASSERT_DETECT(LANG_STRUCTURED_BASIC, "visual_basic.bas"); ASSERT_DETECT(LANG_STRUCTURED_BASIC, "structured_basic.b"); - system("mv ../detect_files/frx1.frx2 ../detect_files/frx1.frx"); + assert(system("mv ../detect_files/frx1.frx2 ../detect_files/frx1.frx") == 0); } void test_detector_xml_with_custom_extension() { From d9ceacdeebbd3d603518fc67af164637f8dd608c Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Fri, 21 Jan 2011 07:46:45 -0800 Subject: [PATCH 296/387] Fixes uninitialized data in tmp filename The filename string used for the detector's temporary file had an uninitialized byte at its end. Usually this byte is 0, so it has no ill effect. Occasionally it can be a garbage byte, which can cause the temporary file write() to fail. Because Ohcount had been failing to check write()'s return value, these errors went unnoticed, and incorrect line counts were silently returned. I have fixed the uninitialized byte, and the previous commit adds the appropriate error checks. All code counted prior to this fix should be recounted. --- src/detector.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/detector.c b/src/detector.c index 041a053..1febcf0 100644 --- a/src/detector.c +++ b/src/detector.c @@ -122,8 +122,7 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { path = sourcefile->diskpath; if (access(path, F_OK) != 0) { // create temporary file path = malloc(21); - strncpy(path, "/tmp/ohcount_XXXXXXX", 20); - *(path + 21) = '\0'; + strncpy(path, "/tmp/ohcount_XXXXXXX\0", 21); int fd = mkstemp(path); char *contents = ohcount_sourcefile_get_contents(sourcefile); log_it("contents:"); From 634623dd3a2ad91d0ba3066d29a412e871a11b57 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Mon, 7 Feb 2011 13:55:54 -0800 Subject: [PATCH 297/387] 'build clean' should remove swig-generated file --- build | 1 + 1 file changed, 1 insertion(+) diff --git a/build b/build index 3ca7853..8a20208 100755 --- a/build +++ b/build @@ -159,6 +159,7 @@ then rm -f src/$SHARED_NAME rm -f ruby/$RB_SHARED_NAME rm -rf ruby/$arch/* + rm -f ruby/ohcount_wrap.c else echo "Usage: build [all|ohcount|shared|tests|ruby|clean]" fi From 16a0a5cce3e9891e73b7841ef5f6f773b6e727c6 Mon Sep 17 00:00:00 2001 From: Robert Schultz Date: Mon, 4 Apr 2011 12:32:44 -0400 Subject: [PATCH 298/387] OTWO-571 Fixed a bug where ohcount would follow symbolically linked directories, causing problems/security concerns --- src/sourcefile.c | 5 ++++- test/symlink_test_dir/symlink_test_dir_target | 1 + test/symlink_test_dir_target/from_symlink_foo.c | 4 ++++ test/unit/sourcefile_test.h | 10 ++++++++++ 4 files changed, 19 insertions(+), 1 deletion(-) create mode 120000 test/symlink_test_dir/symlink_test_dir_target create mode 100644 test/symlink_test_dir_target/from_symlink_foo.c diff --git a/src/sourcefile.c b/src/sourcefile.c index 1112e12..2f23cd4 100644 --- a/src/sourcefile.c +++ b/src/sourcefile.c @@ -383,7 +383,10 @@ void ohcount_sourcefile_list_add_directory(SourceFileList *list, strncpy(f_p, (const char *)file->d_name, length); *(f_p + length) = '\0'; - stat(filepath, &st); + lstat(filepath, &st); + if(S_ISLNK(st.st_mode)) + continue; + if (S_ISDIR(st.st_mode) && *file->d_name != '.') // no hidden dirs ohcount_sourcefile_list_add_directory(list, filepath); else if (S_ISREG(st.st_mode)) diff --git a/test/symlink_test_dir/symlink_test_dir_target b/test/symlink_test_dir/symlink_test_dir_target new file mode 120000 index 0000000..733a6fa --- /dev/null +++ b/test/symlink_test_dir/symlink_test_dir_target @@ -0,0 +1 @@ +../symlink_test_dir_target/ \ No newline at end of file diff --git a/test/symlink_test_dir_target/from_symlink_foo.c b/test/symlink_test_dir_target/from_symlink_foo.c new file mode 100644 index 0000000..5c2fd48 --- /dev/null +++ b/test/symlink_test_dir_target/from_symlink_foo.c @@ -0,0 +1,4 @@ +// c file +int function_a(void) { + int x; +} diff --git a/test/unit/sourcefile_test.h b/test/unit/sourcefile_test.h index 98df899..1e6241a 100644 --- a/test/unit/sourcefile_test.h +++ b/test/unit/sourcefile_test.h @@ -214,6 +214,15 @@ void test_sourcefile_list_language_facts() { ohcount_loc_list_free(list); } +void test_sourcefile_list_no_symlink_dir() { + SourceFileList *sfl = ohcount_sourcefile_list_new(); + ohcount_sourcefile_list_add_directory(sfl, "../symlink_test_dir"); + LocList *list = ohcount_sourcefile_list_analyze_languages(sfl); + assert(ohcount_loc_list_filecount(list) == 0); + ohcount_sourcefile_list_free(sfl); + ohcount_loc_list_free(list); +} + #define FALSE 0 #define TRUE 1 char *tmp_file_from_buf(const char *buf); @@ -247,5 +256,6 @@ void all_sourcefile_tests() { test_sourcefile_calc_diff(); test_sourcefile_list_language_facts(); + test_sourcefile_list_no_symlink_dir(); test_tmp_dir(); } From 7adf54ded5fcdefcf78503a0ac5d505768ea60de Mon Sep 17 00:00:00 2001 From: Scott Lawrence Date: Mon, 18 Apr 2011 11:28:26 -0400 Subject: [PATCH 299/387] Adding recognition and parser for perforce Jam (Jamfile/Jamrules), based on the parser for shell --- src/hash/filenames.gperf | 2 + src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 2 + src/languages.h | 1 + src/parsers/jam.rl | 126 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 132 insertions(+) create mode 100644 src/parsers/jam.rl diff --git a/src/hash/filenames.gperf b/src/hash/filenames.gperf index 765b5a0..c4b5083 100644 --- a/src/hash/filenames.gperf +++ b/src/hash/filenames.gperf @@ -4,6 +4,8 @@ struct FilenameMap { const char *key; const char *value; }; %% CMakeLists.txt, LANG_CMAKE +Jamfile, LANG_JAM +Jamrules, LANG_JAM GNUmakefile, LANG_MAKE Makefile, LANG_MAKE Makefile.am, LANG_AUTOMAKE diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index b322815..57acc53 100644 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -47,6 +47,7 @@ haskell, LANG_HASKELL, "Haskell", 0 haxe, LANG_HAXE, "HaXe", 0 html, LANG_HTML, "HTML", 1 idl_pvwave, LANG_IDL_PVWAVE, "IDL/PV-WAVE/GDL", 0 +jam, LANG_JAM, "Jam", 2 java, LANG_JAVA, "Java", 0 javascript, LANG_JAVASCRIPT, "JavaScript", 0 jsp, LANG_JSP, "", 0 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index 04ec084..b40f2de 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -37,6 +37,7 @@ #include "../parsers/haxe.h" #include "../parsers/html.h" #include "../parsers/idl_pvwave.h" +#include "../parsers/jam.h" #include "../parsers/java.h" #include "../parsers/javascript.h" #include "../parsers/jsp.h" @@ -131,6 +132,7 @@ haml, parse_haml haxe, parse_haxe html, parse_html idl_pvwave, parse_idl_pvwave +jam, parse_jam java, parse_java javascript, parse_javascript jsp, parse_jsp diff --git a/src/languages.h b/src/languages.h index 107c7a5..26f46b8 100644 --- a/src/languages.h +++ b/src/languages.h @@ -49,6 +49,7 @@ #define LANG_HAXE "haxe" #define LANG_HTML "html" #define LANG_IDL_PVWAVE "idl_pvwave" +#define LANG_JAM "jam" #define LANG_JAVA "java" #define LANG_JAVASCRIPT "javascript" #define LANG_JSP "jsp" diff --git a/src/parsers/jam.rl b/src/parsers/jam.rl new file mode 100644 index 0000000..3b4ccc7 --- /dev/null +++ b/src/parsers/jam.rl @@ -0,0 +1,126 @@ +// jam.rl written by Scott Lawrence. bytbox@gmail.com + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_JAM_PARSER_H +#define OHCOUNT_JAM_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *JAM_LANG = LANG_JAM; + +// the languages entities +const char *jam_entities[] = { + "space", "comment", "string", "any" +}; + +// constants associated with the entities +enum { + JAM_SPACE = 0, JAM_COMMENT, JAM_STRING, JAM_ANY +}; + +/*****************************************************************************/ + +%%{ + machine jam; + write data; + include common "common.rl"; + + # Line counting machine + + action jam_ccallback { + switch(entity) { + case JAM_SPACE: + ls + break; + case JAM_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(JAM_LANG) + break; + case NEWLINE: + std_newline(JAM_LANG) + } + } + + jam_comment = '#' @comment nonnewline*; + + jam_sq_str = + '\'' @enqueue @code ( + newline %{ entity = INTERNAL_NL; } %jam_ccallback + | + ws + | + [^\r\n\f\t '\\] @code + | + '\\' nonnewline @code + )* '\'' @commit; + jam_dq_str = + '"' @enqueue @code ( + newline %{ entity = INTERNAL_NL; } %jam_ccallback + | + ws + | + [^\r\n\f\t "\\] @code + | + '\\' nonnewline @code + )* '"' @commit; + # TODO: heredocs; see ruby.rl for details + jam_string = jam_sq_str | jam_dq_str; + + jam_line := |* + spaces ${ entity = JAM_SPACE; } => jam_ccallback; + jam_comment; + jam_string; + newline ${ entity = NEWLINE; } => jam_ccallback; + ^space ${ entity = JAM_ANY; } => jam_ccallback; + *|; + + # Entity machine + + action jam_ecallback { + callback(JAM_LANG, jam_entities[entity], cint(ts), cint(te), userdata); + } + + jam_comment_entity = '#' nonnewline*; + + jam_entity := |* + space+ ${ entity = JAM_SPACE; } => jam_ecallback; + jam_comment_entity ${ entity = JAM_COMMENT; } => jam_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with Jam code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_jam(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + %% write init; + cs = (count) ? jam_en_jam_line : jam_en_jam_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(JAM_LANG) } +} + +#endif + +/*****************************************************************************/ From a6916f0ec7d1cc86204731efdd5a0b08d2cbc81e Mon Sep 17 00:00:00 2001 From: Scott Lawrence Date: Mon, 18 Apr 2011 11:30:53 -0400 Subject: [PATCH 300/387] add test cases for jam --- test/unit/parser_test.h | 2 ++ test/unit/parsers/test_jam.h | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 test/unit/parsers/test_jam.h diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index 2831972..dd46137 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -112,6 +112,7 @@ void test_parser_verify_entity(SourceFile *sf, const char *entity, #include "parsers/test_haxe.h" #include "parsers/test_html.h" #include "parsers/test_idl_pvwave.h" +#include "parsers/test_jam.h" #include "parsers/test_java.h" #include "parsers/test_javascript.h" #include "parsers/test_jsp.h" @@ -287,6 +288,7 @@ void all_parser_tests() { all_haxe_tests(); all_html_tests(); all_idl_pvwave_tests(); + all_jam_tests(); all_java_tests(); all_javascript_tests(); all_jsp_tests(); diff --git a/test/unit/parsers/test_jam.h b/test/unit/parsers/test_jam.h new file mode 100644 index 0000000..373a6be --- /dev/null +++ b/test/unit/parsers/test_jam.h @@ -0,0 +1,19 @@ + +void test_jam_comments() { + test_parser_verify_parse( + test_parser_sourcefile("jam", " #comment"), + "jam", "", "#comment", 0 + ); +} + +void test_jam_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("jam", " #comment"), + "comment", "#comment" + ); +} + +void all_jam_tests() { + test_jam_comments(); + test_jam_comment_entities(); +} From 2453a16ab08c4c7b2f9f95ab91026aa1061656d7 Mon Sep 17 00:00:00 2001 From: Jerome St-Louis Date: Sat, 21 May 2011 04:00:54 -0400 Subject: [PATCH 301/387] Added support for the eC language (www.ecere.com) --- src/hash/extensions.gperf | 2 ++ src/hash/languages.gperf | 1 + src/languages.h | 1 + src/parsers/c.rl | 11 +++++++++++ test/unit/detector_test.h | 2 ++ 5 files changed, 17 insertions(+) mode change 100644 => 100755 src/hash/extensions.gperf mode change 100644 => 100755 src/hash/languages.gperf mode change 100644 => 100755 src/languages.h mode change 100644 => 100755 src/parsers/c.rl mode change 100644 => 100755 test/unit/detector_test.h diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf old mode 100644 new mode 100755 index ccc5972..1eb4b2c --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -51,7 +51,9 @@ doc, BINARY dylan, LANG_DYLAN e, LANG_EIFFEL ebuild, LANG_EBUILD +ec, LANG_EC eclass, LANG_EBUILD +eh, LANG_EC el, LANG_EMACSLISP erl, LANG_ERLANG exheres-0, LANG_EXHERES diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf old mode 100644 new mode 100755 index b322815..1f1c505 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -31,6 +31,7 @@ dcl, LANG_DCL, "DCL", 0 dmd, LANG_DMD, "D", 0 dylan, LANG_DYLAN, "Dylan", 0 ebuild, LANG_EBUILD, "Ebuild", 0 +ec, LANG_EC, "eC", 0 eiffel, LANG_EIFFEL, "Eiffel", 0 emacslisp, LANG_EMACSLISP, "Emacs lisp", 0 erlang, LANG_ERLANG, "Erlang", 0 diff --git a/src/languages.h b/src/languages.h old mode 100644 new mode 100755 index 107c7a5..ce188fd --- a/src/languages.h +++ b/src/languages.h @@ -33,6 +33,7 @@ #define LANG_DMD "dmd" #define LANG_DYLAN "dylan" #define LANG_EBUILD "ebuild" +#define LANG_EC "ec" #define LANG_EIFFEL "eiffel" #define LANG_ERLANG "erlang" #define LANG_EXHERES "exheres" diff --git a/src/parsers/c.rl b/src/parsers/c.rl old mode 100644 new mode 100755 index c2bd571..fceba51 --- a/src/parsers/c.rl +++ b/src/parsers/c.rl @@ -222,6 +222,17 @@ void parse_cuda(char *buffer, int length, int count, C_LANG = ORIG_C_LANG; } +const char *EC_LANG = LANG_EC; +void parse_ec(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + C_LANG = EC_LANG; + parse_c(buffer, length, count, callback, userdata); + C_LANG = ORIG_C_LANG; +} + #endif /*****************************************************************************/ diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h old mode 100644 new mode 100755 index bbba1c2..f4b8217 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -98,6 +98,8 @@ void test_detector_detect_polyglot() { ASSERT_DETECT(LANG_LISP, "core.lisp"); ASSERT_DETECT(LANG_DMD, "foo.d"); ASSERT_DETECT(LANG_VIM, "foo.vim"); + ASSERT_DETECT(LANG_EC, "foo.ec"); + ASSERT_DETECT(LANG_EC, "foo.eh"); ASSERT_DETECT(LANG_EBUILD, "foo.ebuild"); ASSERT_DETECT(LANG_EBUILD, "foo.eclass"); ASSERT_DETECT(LANG_EXHERES, "foo.exheres-0"); From 9490c463a5fc37a4034692fd1584bd5722fcb91a Mon Sep 17 00:00:00 2001 From: Jerome St-Louis Date: Sat, 21 May 2011 04:15:39 -0400 Subject: [PATCH 302/387] Added missing detector test files --- test/detect_files/foo.ec | 17 +++ test/detect_files/foo.eh | 315 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 332 insertions(+) create mode 100755 test/detect_files/foo.ec create mode 100755 test/detect_files/foo.eh diff --git a/test/detect_files/foo.ec b/test/detect_files/foo.ec new file mode 100755 index 0000000..b169291 --- /dev/null +++ b/test/detect_files/foo.ec @@ -0,0 +1,17 @@ +import "ecere" + +class HelloForm : Window +{ + text = "My First eC Application"; + borderStyle = sizable; + size = { 280, 100 }; + hasClose = true; + + Label label + { + this, position = { 10, 10 }, font = { "Arial", 30 }, + text = "Hello, World!!" + }; +}; + +HelloForm hello { }; diff --git a/test/detect_files/foo.eh b/test/detect_files/foo.eh new file mode 100755 index 0000000..1ed173f --- /dev/null +++ b/test/detect_files/foo.eh @@ -0,0 +1,315 @@ +/* A Bison parser, made by GNU Bison 2.0. */ + +/* Skeleton parser for Yacc-like parsing with Bison, + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + IDENTIFIER = 258, + CONSTANT = 259, + STRING_LITERAL = 260, + SIZEOF = 261, + PTR_OP = 262, + INC_OP = 263, + DEC_OP = 264, + LEFT_OP = 265, + RIGHT_OP = 266, + LE_OP = 267, + GE_OP = 268, + EQ_OP = 269, + NE_OP = 270, + AND_OP = 271, + OR_OP = 272, + MUL_ASSIGN = 273, + DIV_ASSIGN = 274, + MOD_ASSIGN = 275, + ADD_ASSIGN = 276, + SUB_ASSIGN = 277, + LEFT_ASSIGN = 278, + RIGHT_ASSIGN = 279, + AND_ASSIGN = 280, + XOR_ASSIGN = 281, + OR_ASSIGN = 282, + TYPE_NAME = 283, + TYPEDEF = 284, + EXTERN = 285, + STATIC = 286, + AUTO = 287, + REGISTER = 288, + CHAR = 289, + SHORT = 290, + INT = 291, + UINT = 292, + INT64 = 293, + LONG = 294, + SIGNED = 295, + UNSIGNED = 296, + FLOAT = 297, + DOUBLE = 298, + CONST = 299, + VOLATILE = 300, + VOID = 301, + VALIST = 302, + STRUCT = 303, + UNION = 304, + ENUM = 305, + ELLIPSIS = 306, + CASE = 307, + DEFAULT = 308, + IF = 309, + SWITCH = 310, + WHILE = 311, + DO = 312, + FOR = 313, + GOTO = 314, + CONTINUE = 315, + BREAK = 316, + RETURN = 317, + IFX = 318, + ELSE = 319, + CLASS = 320, + THISCLASS = 321, + CLASS_NAME = 322, + PROPERTY = 323, + SETPROP = 324, + GETPROP = 325, + NEWOP = 326, + RENEW = 327, + DELETE = 328, + EXT_DECL = 329, + EXT_STORAGE = 330, + IMPORT = 331, + DEFINE = 332, + VIRTUAL = 333, + EXT_ATTRIB = 334, + PUBLIC = 335, + PRIVATE = 336, + TYPED_OBJECT = 337, + ANY_OBJECT = 338, + _INCREF = 339, + EXTENSION = 340, + ASM = 341, + TYPEOF = 342, + WATCH = 343, + STOPWATCHING = 344, + FIREWATCHERS = 345, + WATCHABLE = 346, + CLASS_DESIGNER = 347, + CLASS_NO_EXPANSION = 348, + CLASS_FIXED = 349, + ISPROPSET = 350, + CLASS_DEFAULT_PROPERTY = 351, + PROPERTY_CATEGORY = 352, + CLASS_DATA = 353, + CLASS_PROPERTY = 354, + SUBCLASS = 355, + NAMESPACE = 356, + NEW0OP = 357, + RENEW0 = 358, + VAARG = 359, + DBTABLE = 360, + DBFIELD = 361, + DBINDEX = 362, + DATABASE_OPEN = 363 + }; +#endif +#define IDENTIFIER 258 +#define CONSTANT 259 +#define STRING_LITERAL 260 +#define SIZEOF 261 +#define PTR_OP 262 +#define INC_OP 263 +#define DEC_OP 264 +#define LEFT_OP 265 +#define RIGHT_OP 266 +#define LE_OP 267 +#define GE_OP 268 +#define EQ_OP 269 +#define NE_OP 270 +#define AND_OP 271 +#define OR_OP 272 +#define MUL_ASSIGN 273 +#define DIV_ASSIGN 274 +#define MOD_ASSIGN 275 +#define ADD_ASSIGN 276 +#define SUB_ASSIGN 277 +#define LEFT_ASSIGN 278 +#define RIGHT_ASSIGN 279 +#define AND_ASSIGN 280 +#define XOR_ASSIGN 281 +#define OR_ASSIGN 282 +#define TYPE_NAME 283 +#define TYPEDEF 284 +#define EXTERN 285 +#define STATIC 286 +#define AUTO 287 +#define REGISTER 288 +#define CHAR 289 +#define SHORT 290 +#define INT 291 +#define UINT 292 +#define INT64 293 +#define LONG 294 +#define SIGNED 295 +#define UNSIGNED 296 +#define FLOAT 297 +#define DOUBLE 298 +#define CONST 299 +#define VOLATILE 300 +#define VOID 301 +#define VALIST 302 +#define STRUCT 303 +#define UNION 304 +#define ENUM 305 +#define ELLIPSIS 306 +#define CASE 307 +#define DEFAULT 308 +#define IF 309 +#define SWITCH 310 +#define WHILE 311 +#define DO 312 +#define FOR 313 +#define GOTO 314 +#define CONTINUE 315 +#define BREAK 316 +#define RETURN 317 +#define IFX 318 +#define ELSE 319 +#define CLASS 320 +#define THISCLASS 321 +#define CLASS_NAME 322 +#define PROPERTY 323 +#define SETPROP 324 +#define GETPROP 325 +#define NEWOP 326 +#define RENEW 327 +#define DELETE 328 +#define EXT_DECL 329 +#define EXT_STORAGE 330 +#define IMPORT 331 +#define DEFINE 332 +#define VIRTUAL 333 +#define EXT_ATTRIB 334 +#define PUBLIC 335 +#define PRIVATE 336 +#define TYPED_OBJECT 337 +#define ANY_OBJECT 338 +#define _INCREF 339 +#define EXTENSION 340 +#define ASM 341 +#define TYPEOF 342 +#define WATCH 343 +#define STOPWATCHING 344 +#define FIREWATCHERS 345 +#define WATCHABLE 346 +#define CLASS_DESIGNER 347 +#define CLASS_NO_EXPANSION 348 +#define CLASS_FIXED 349 +#define ISPROPSET 350 +#define CLASS_DEFAULT_PROPERTY 351 +#define PROPERTY_CATEGORY 352 +#define CLASS_DATA 353 +#define CLASS_PROPERTY 354 +#define SUBCLASS 355 +#define NAMESPACE 356 +#define NEW0OP 357 +#define RENEW0 358 +#define VAARG 359 +#define DBTABLE 360 +#define DBFIELD 361 +#define DBINDEX 362 +#define DATABASE_OPEN 363 + + + + +#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) +#line 42 "grammar.y" +typedef union YYSTYPE { + SpecifierType specifierType; + int i; + AccessMode declMode; + Identifier id; + Expression exp; + Specifier specifier; + OldList * list; + Enumerator enumerator; + Declarator declarator; + Pointer pointer; + Initializer initializer; + InitDeclarator initDeclarator; + TypeName typeName; + Declaration declaration; + Statement stmt; + FunctionDefinition function; + External external; + Context context; + AsmField asmField; + + Instantiation instance; + MembersInit membersInit; + MemberInit memberInit; + ClassFunction classFunction; + ClassDefinition _class; + ClassDef classDef; + PropertyDef prop; + char * string; + Symbol symbol; + PropertyWatch propertyWatch; + TemplateParameter templateParameter; + TemplateArgument templateArgument; + TemplateDatatype templateDatatype; + + DBTableEntry dbtableEntry; + DBIndexItem dbindexItem; + DBTableDef dbtableDef; +} YYSTYPE; +/* Line 1318 of yacc.c. */ +#line 293 "grammar.eh" +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + +extern YYSTYPE yylval; + +#if ! defined (YYLTYPE) && ! defined (YYLTYPE_IS_DECLARED) +typedef struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +} YYLTYPE; +# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + +extern YYLTYPE yylloc; + + From 3aa5db4e644b4ce718530068ebf4be8c6f97e509 Mon Sep 17 00:00:00 2001 From: Andreas Bolka Date: Wed, 1 Jun 2011 23:21:23 +0200 Subject: [PATCH 303/387] Add REBOL detection and (basic) parsing Also adds a simple .r disambiguation to discern REBOL and R sources. R is the default, REBOL is used if "rebol" is found anywhere in the contents. The REBOL parser currently does not handle multi-line strings ({...}), which could (in rare cases) lead to string parts being classified as comments. Signed-off-by: Andreas Bolka --- src/detector.c | 17 ++++++ src/hash/disambiguatefuncs.gperf | 2 + src/hash/extensions.gperf | 5 +- src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 2 + src/languages.h | 1 + src/parsers/rebol.rl | 114 +++++++++++++++++++++++++++++++++++ test/detect_files/{foo.R => foo_r.R} | 0 test/detect_files/foo_rebol_lower.r | 7 +++ test/detect_files/foo_rebol_upper.r | 7 +++ test/expected_dir/rebol.r | 59 ++++++++++++++++++ test/src_dir/rebol.r | 59 ++++++++++++++++++ test/unit/detector_test.h | 8 ++- test/unit/parser_test.h | 2 + test/unit/parsers/test_rebol.h | 23 +++++++ 15 files changed, 305 insertions(+), 2 deletions(-) create mode 100644 src/parsers/rebol.rl rename test/detect_files/{foo.R => foo_r.R} (100%) create mode 100644 test/detect_files/foo_rebol_lower.r create mode 100644 test/detect_files/foo_rebol_upper.r create mode 100644 test/expected_dir/rebol.r create mode 100644 test/src_dir/rebol.r create mode 100644 test/unit/parsers/test_rebol.h diff --git a/src/detector.c b/src/detector.c index 1febcf0..08310fd 100644 --- a/src/detector.c +++ b/src/detector.c @@ -706,6 +706,23 @@ const char *disambiguate_pro(SourceFile *sourcefile) { return LANG_IDL_PVWAVE; } +const char *disambiguate_r(SourceFile *sourcefile) { + char *contents = ohcount_sourcefile_get_contents(sourcefile); + char *eof = contents + ohcount_sourcefile_get_contents_size(sourcefile); + + // Detect REBOL by looking for the occurence of "rebol" in the contents + // (case-insensitive). Correct REBOL scripts have a "REBOL [...]" header + // block. + char *needle = "rebol"; + int len = strlen(needle); + for (; contents < eof - len; ++contents) + if (tolower(*contents) == *needle && + !strncasecmp(contents, needle, len)) + return LANG_REBOL; + + return LANG_R; +} + const char *disambiguate_st(SourceFile *sourcefile) { char *p, *pe; int length; diff --git a/src/hash/disambiguatefuncs.gperf b/src/hash/disambiguatefuncs.gperf index d48989d..db133b7 100644 --- a/src/hash/disambiguatefuncs.gperf +++ b/src/hash/disambiguatefuncs.gperf @@ -13,6 +13,7 @@ const char *disambiguate_inc(SourceFile *sourcefile); const char *disambiguate_m(SourceFile *sourcefile); const char *disambiguate_pp(SourceFile *sourcefile); const char *disambiguate_pro(SourceFile *sourcefile); +const char *disambiguate_r(SourceFile *sourcefile); const char *disambiguate_st(SourceFile *sourcefile); %} struct DisambiguateFuncsMap { const char *key; const char* (*value)(SourceFile*); }; @@ -28,4 +29,5 @@ inc, disambiguate_inc m, disambiguate_m pp, disambiguate_pp pro, disambiguate_pro +r, disambiguate_r st, disambiguate_st diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index ccc5972..dc52b11 100644 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -145,9 +145,12 @@ ppt, BINARY pro, DISAMBIGUATE("pro") py, LANG_PYTHON qt, BINARY -r, LANG_R +r, DISAMBIGUATE("r") +r3, LANG_REBOL ra, BINARY rb, LANG_RUBY +reb, LANG_REBOL +rebol, LANG_REBOL rex, LANG_REXX rexx, LANG_REXX rhtml, LANG_RHTML diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index b322815..3f65178 100644 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -75,6 +75,7 @@ pike, LANG_PIKE, "Pike", 0 puppet, LANG_PUPPET, "Puppet", 0 python, LANG_PYTHON, "Python", 0 r, LANG_R, "R", 0 +rebol, LANG_REBOL, "REBOL", 0 rexx, LANG_REXX, "rexx", 0 rhtml, LANG_RHTML, "", 0 ruby, LANG_RUBY, "Ruby", 0 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index 04ec084..49c4f98 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -65,6 +65,7 @@ #include "../parsers/puppet.h" #include "../parsers/python.h" #include "../parsers/r.h" +#include "../parsers/rebol.h" #include "../parsers/rexx.h" #include "../parsers/ruby.h" #include "../parsers/rhtml.h" @@ -159,6 +160,7 @@ pike, parse_pike puppet, parse_puppet python, parse_python r, parse_r +rebol, parse_rebol rexx, parse_rexx rhtml, parse_rhtml ruby, parse_ruby diff --git a/src/languages.h b/src/languages.h index 107c7a5..c67d3f6 100644 --- a/src/languages.h +++ b/src/languages.h @@ -77,6 +77,7 @@ #define LANG_PUPPET "puppet" #define LANG_PYTHON "python" #define LANG_R "r" +#define LANG_REBOL "rebol" #define LANG_REXX "rexx" #define LANG_RHTML "rhtml" #define LANG_RUBY "ruby" diff --git a/src/parsers/rebol.rl b/src/parsers/rebol.rl new file mode 100644 index 0000000..1b8a7f7 --- /dev/null +++ b/src/parsers/rebol.rl @@ -0,0 +1,114 @@ +// rebol.rl written by Andreas Bolka. + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_REBOL_PARSER_H +#define OHCOUNT_REBOL_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *REBOL_LANG = LANG_REBOL; + +// the languages entities +const char *rebol_entities[] = { + "space", "comment", "string", "any" +}; + +// constants associated with the entities +enum { + REBOL_SPACE = 0, REBOL_COMMENT, REBOL_STRING, REBOL_ANY +}; + +/*****************************************************************************/ + +%%{ + machine rebol; + write data; + include common "common.rl"; + + # Line counting machine + + action rebol_ccallback { + switch(entity) { + case REBOL_SPACE: + ls + break; + case REBOL_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(REBOL_LANG) + break; + case NEWLINE: + std_newline(REBOL_LANG) + } + } + + rebol_line_comment = ';' @comment nonnewline*; + rebol_comment = rebol_line_comment; + + rebol_dq_str = '"' @code ([^\r\n\f"] | '^"')* [\r\n\f"]; + rebol_string = rebol_dq_str; + + rebol_line := |* + spaces ${ entity = REBOL_SPACE; } => rebol_ccallback; + rebol_comment; + rebol_string; + newline ${ entity = NEWLINE; } => rebol_ccallback; + ^space ${ entity = REBOL_ANY; } => rebol_ccallback; + *|; + + # Entity machine + + action rebol_ecallback { + callback(REBOL_LANG, rebol_entities[entity], cint(ts), cint(te), userdata); + } + + rebol_line_comment_entity = ';' nonnewline*; + rebol_comment_entity = rebol_line_comment_entity; + + rebol_dq_str_entity = '"' ([^\r\n\f"] | '^"')* [\r\n\f"]; + rebol_string_entiy = rebol_dq_str_entity; + + rebol_entity := |* + space+ ${ entity = REBOL_SPACE; } => rebol_ecallback; + rebol_comment_entity ${ entity = REBOL_COMMENT; } => rebol_ecallback; + rebol_string_entiy ${ entity = REBOL_STRING; } => rebol_ecallback; + ^space ${ entity = REBOL_ANY; } => rebol_ecallback; + *|; + +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with REBOL code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_rebol(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + %% write init; + cs = (count) ? rebol_en_rebol_line : rebol_en_rebol_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(REBOL_LANG) } +} + +#endif + +/*****************************************************************************/ + +// vim: set ts=2 syn=c: diff --git a/test/detect_files/foo.R b/test/detect_files/foo_r.R similarity index 100% rename from test/detect_files/foo.R rename to test/detect_files/foo_r.R diff --git a/test/detect_files/foo_rebol_lower.r b/test/detect_files/foo_rebol_lower.r new file mode 100644 index 0000000..22eda4b --- /dev/null +++ b/test/detect_files/foo_rebol_lower.r @@ -0,0 +1,7 @@ +; a rebol script +rebol [] + +; A dummy function to test the REBOL language parser. +dummy: func [] [ + read %blah +] diff --git a/test/detect_files/foo_rebol_upper.r b/test/detect_files/foo_rebol_upper.r new file mode 100644 index 0000000..a5ff223 --- /dev/null +++ b/test/detect_files/foo_rebol_upper.r @@ -0,0 +1,7 @@ +; a rebol script +REBOL [] + +; A dummy function to test the REBOL language parser. +dummy: func [] [ + read %blah +] diff --git a/test/expected_dir/rebol.r b/test/expected_dir/rebol.r new file mode 100644 index 0000000..17baf19 --- /dev/null +++ b/test/expected_dir/rebol.r @@ -0,0 +1,59 @@ +rebol comment ;; ================================================= +rebol comment ;; Script: new-suffix.r +rebol comment ;; downloaded from: www.REBOL.org +rebol comment ;; on: 1-Jun-2011 +rebol comment ;; at: 21:19:08.38986 UTC +rebol comment ;; owner: carl [script library member who can update +rebol comment ;; this script] +rebol comment ;; ================================================= +rebol code REBOL [ +rebol code Title: "Change File Extensions (Suffix)" +rebol code File: %new-suffix.r +rebol code Author: "Carl Sassenrath" +rebol code Date: 25-Jan-2005 +rebol code Purpose: { +rebol code Change the file extension (suffix) for files with a specific extension. +rebol code For example, change all .txt files to .r files in the current directory. +rebol code Displays a list of changes before it makes them. +rebol code } +rebol code Warning: "Back up your files first, just in case!" +rebol code License: "BSD - Use at your own risk." +rebol code Library: [ +rebol code level: 'beginner +rebol code platform: 'all +rebol code type: [tool] +rebol code domain: [files] +rebol code tested-under: none +rebol code support: none +rebol code license: 'bsd +rebol code see-also: none +rebol code ] +rebol code ] +rebol blank +rebol code from-suffix: %.txt +rebol code to-suffix: %.r +rebol blank +rebol code bulk-rename: func [confirmed] [ +rebol code foreach file load %./ [ +rebol code if all [ +rebol code not find file #"/" ; (ignore directories) +rebol code from-suffix = find/last file #"." +rebol code ][ +rebol code new-file: copy file +rebol code append clear find/last new-file #"." to-suffix +rebol code either confirmed [ +rebol code print ["Renaming" file "to" new-file] +rebol code rename file new-file +rebol code ][ +rebol code print ["Will rename" file "to" new-file] +rebol code ] +rebol code ] +rebol code ] +rebol code ] +rebol blank +rebol code bulk-rename false +rebol code if not confirm "Are you sure you want to rename all those files?" [ +rebol code quit +rebol code ] +rebol code bulk-rename true +rebol code ask "Done. Press enter." diff --git a/test/src_dir/rebol.r b/test/src_dir/rebol.r new file mode 100644 index 0000000..8e0b6ff --- /dev/null +++ b/test/src_dir/rebol.r @@ -0,0 +1,59 @@ +;; ================================================= +;; Script: new-suffix.r +;; downloaded from: www.REBOL.org +;; on: 1-Jun-2011 +;; at: 21:19:08.38986 UTC +;; owner: carl [script library member who can update +;; this script] +;; ================================================= +REBOL [ + Title: "Change File Extensions (Suffix)" + File: %new-suffix.r + Author: "Carl Sassenrath" + Date: 25-Jan-2005 + Purpose: { + Change the file extension (suffix) for files with a specific extension. + For example, change all .txt files to .r files in the current directory. + Displays a list of changes before it makes them. + } + Warning: "Back up your files first, just in case!" + License: "BSD - Use at your own risk." + Library: [ + level: 'beginner + platform: 'all + type: [tool] + domain: [files] + tested-under: none + support: none + license: 'bsd + see-also: none + ] +] + +from-suffix: %.txt +to-suffix: %.r + +bulk-rename: func [confirmed] [ + foreach file load %./ [ + if all [ + not find file #"/" ; (ignore directories) + from-suffix = find/last file #"." + ][ + new-file: copy file + append clear find/last new-file #"." to-suffix + either confirmed [ + print ["Renaming" file "to" new-file] + rename file new-file + ][ + print ["Will rename" file "to" new-file] + ] + ] + ] +] + +bulk-rename false +if not confirm "Are you sure you want to rename all those files?" [ + quit +] +bulk-rename true +ask "Done. Press enter." diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index bbba1c2..6fbd8d1 100644 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -76,6 +76,12 @@ void test_detector_disambiguate_pro() { ASSERT_DETECT(LANG_MAKE, "qmake.pro"); } +void test_detector_disambiguate_r() { + ASSERT_DETECT(LANG_R, "foo_r.R"); + ASSERT_DETECT(LANG_REBOL, "foo_rebol_lower.r"); + ASSERT_DETECT(LANG_REBOL, "foo_rebol_upper.r"); +} + void test_detector_fortran_fixedfree() { ASSERT_DETECT(LANG_FORTRANFIXED, "fortranfixed.f"); ASSERT_DETECT(LANG_FORTRANFREE, "fortranfree.f"); @@ -105,7 +111,6 @@ void test_detector_detect_polyglot() { ASSERT_DETECT(LANG_EIFFEL, "eiffel.e"); ASSERT_DETECT(LANG_OCAML, "ocaml.ml"); ASSERT_DETECT(LANG_STRATEGO, "stratego.str"); - ASSERT_DETECT(LANG_R, "foo.R"); ASSERT_DETECT(LANG_GLSL, "foo.glsl"); ASSERT_DETECT(LANG_GLSL, "foo_glsl.vert"); ASSERT_DETECT(LANG_GLSL, "foo_glsl.frag"); @@ -169,6 +174,7 @@ void all_detector_tests() { test_detector_disambiguate_m(); test_detector_disambiguate_in(); test_detector_disambiguate_pro(); + test_detector_disambiguate_r(); test_detector_fortran_fixedfree(); test_detector_detect_polyglot(); test_detector_upper_case_extensions(); diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index 2831972..298c92b 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -133,6 +133,7 @@ void test_parser_verify_entity(SourceFile *sf, const char *entity, #include "parsers/test_puppet.h" #include "parsers/test_python.h" #include "parsers/test_r.h" +#include "parsers/test_rebol.h" #include "parsers/test_rexx.h" #include "parsers/test_rhtml.h" #include "parsers/test_ruby.h" @@ -307,6 +308,7 @@ void all_parser_tests() { all_pike_tests(); all_python_tests(); all_r_tests(); + all_rebol_tests(); all_rexx_tests(); all_rhtml_tests(); all_ruby_tests(); diff --git a/test/unit/parsers/test_rebol.h b/test/unit/parsers/test_rebol.h new file mode 100644 index 0000000..7ddfbf3 --- /dev/null +++ b/test/unit/parsers/test_rebol.h @@ -0,0 +1,23 @@ + +void test_rebol_comments() { + test_parser_verify_parse( + test_parser_sourcefile("rebol", "REBOL []\n;comment"), + "rebol", "REBOL []\n", ";comment", 0 + ); +} + +void test_rebol_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("rebol", " ;comment"), + "comment", ";comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("rebol", " \";no comment\""), + "string", "\";no comment\"" + ); +} + +void all_rebol_tests() { + test_rebol_comments(); + test_rebol_comment_entities(); +} From 8d7c9325ec9b5bbe35d578d8270e5671d749fd4f Mon Sep 17 00:00:00 2001 From: Andreas Bolka Date: Thu, 2 Jun 2011 01:35:01 +0200 Subject: [PATCH 304/387] Implement parsing of REBOL multi-line strings Signed-off-by: Andreas Bolka --- src/parsers/rebol.rl | 18 ++++++++++++++++-- test/unit/parsers/test_rebol.h | 20 ++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/parsers/rebol.rl b/src/parsers/rebol.rl index 1b8a7f7..eb7fc59 100644 --- a/src/parsers/rebol.rl +++ b/src/parsers/rebol.rl @@ -26,6 +26,13 @@ enum { write data; include common "common.rl"; + action rebol_inc_string { ++rebol_string_level; } + action rebol_dec_string { --rebol_string_level; } + action rebol_is_nested { rebol_string_level > 0 } + + rebol_cb_str_nest = '{' %rebol_inc_string + | '}' when rebol_is_nested %rebol_dec_string; + # Line counting machine action rebol_ccallback { @@ -48,7 +55,11 @@ enum { rebol_comment = rebol_line_comment; rebol_dq_str = '"' @code ([^\r\n\f"] | '^"')* [\r\n\f"]; - rebol_string = rebol_dq_str; + rebol_cb_str_inner = [^{}] | '^{' | '^}' + | newline %{ entity = INTERNAL_NL; } %rebol_ccallback + | rebol_cb_str_nest; + rebol_cb_str = '{' @code rebol_cb_str_inner* @code '}' @code; + rebol_string = rebol_dq_str | rebol_cb_str; rebol_line := |* spaces ${ entity = REBOL_SPACE; } => rebol_ccallback; @@ -68,7 +79,8 @@ enum { rebol_comment_entity = rebol_line_comment_entity; rebol_dq_str_entity = '"' ([^\r\n\f"] | '^"')* [\r\n\f"]; - rebol_string_entiy = rebol_dq_str_entity; + rebol_cb_str_entity = '{' ([^{}] | '^{' | '^}' | rebol_cb_str_nest)* '}'; + rebol_string_entiy = rebol_dq_str_entity | rebol_cb_str_entity; rebol_entity := |* space+ ${ entity = REBOL_SPACE; } => rebol_ecallback; @@ -97,6 +109,8 @@ void parse_rebol(char *buffer, int length, int count, int e, void *udata), void *userdata ) { + // For {..} multi-line strings which require proper balancing of {}'s. + int rebol_string_level = 0; init %% write init; diff --git a/test/unit/parsers/test_rebol.h b/test/unit/parsers/test_rebol.h index 7ddfbf3..95bace9 100644 --- a/test/unit/parsers/test_rebol.h +++ b/test/unit/parsers/test_rebol.h @@ -4,6 +4,26 @@ void test_rebol_comments() { test_parser_sourcefile("rebol", "REBOL []\n;comment"), "rebol", "REBOL []\n", ";comment", 0 ); + test_parser_verify_parse( + test_parser_sourcefile("rebol", "{}"), + "rebol", "{}", "", 0 + ); + test_parser_verify_parse( + test_parser_sourcefile("rebol", "{{}}"), + "rebol", "{{}}", "", 0 + ); + test_parser_verify_parse( + test_parser_sourcefile("rebol", "{{\n}}"), + "rebol", "{{\n}}", "", 0 + ); + test_parser_verify_parse( + test_parser_sourcefile("rebol", "{\n;inside string\n}"), + "rebol", "{\n;inside string\n}", "", 0 + ); + test_parser_verify_parse( + test_parser_sourcefile("rebol", "{}\n;comment"), + "rebol", "{}\n", ";comment", 0 + ); } void test_rebol_comment_entities() { From 05e5eca5509ad6f0bea5ad8f4993f3e25c4c4a81 Mon Sep 17 00:00:00 2001 From: Andreas Bolka Date: Thu, 2 Jun 2011 01:39:25 +0200 Subject: [PATCH 305/387] Fix ragel include in parser example skeleton Signed-off-by: Andreas Bolka --- doc/examples/parser_doc_3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/examples/parser_doc_3 b/doc/examples/parser_doc_3 index f72667f..f6f4c17 100644 --- a/doc/examples/parser_doc_3 +++ b/doc/examples/parser_doc_3 @@ -1,7 +1,7 @@ %%{ machine c; write data; - include "common.rl"; + include common "common.rl"; ... }%% From 0ef7734b52d8d9abbf88c7fb2b6e60b210088cc8 Mon Sep 17 00:00:00 2001 From: Andreas Bolka Date: Thu, 2 Jun 2011 01:40:11 +0200 Subject: [PATCH 306/387] Fix filename in Go parser attribution line Signed-off-by: Andreas Bolka --- src/parsers/golang.rl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parsers/golang.rl b/src/parsers/golang.rl index 13fb105..f845ca0 100644 --- a/src/parsers/golang.rl +++ b/src/parsers/golang.rl @@ -1,4 +1,4 @@ -// c.rl written by Scott Lawrence +// golang.rl written by Scott Lawrence /************************* Required for every parser *************************/ #ifndef OHCOUNT_GOLANG_PARSER_H From f2559100209b85185467f9f0c5caca350df0d50f Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Mon, 20 Jun 2011 11:28:44 -0400 Subject: [PATCH 307/387] OTWO-803 Fixes disambiguate_pp() performance sink disambiguate_pp() failed to execute in a reasonable time for extremely large (1MB+) files. The reason is that a regular expression is evaluated for each line of the file, and this regular expression is scoped from the beginning of the line to the end of the file. When the file is extremely large, the regular expression evaluation runs away with the CPU. By limiting the scope of the regular expression evaluation to no more than 100 characters from its start point, we can avoid the runaway performance sink. This is a reasonable change since the expression we are looking to match should almost always fit within 100 chars anyway. --- src/detector.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/detector.c b/src/detector.c index 1febcf0..b0da12d 100644 --- a/src/detector.c +++ b/src/detector.c @@ -672,14 +672,14 @@ const char *disambiguate_pp(SourceFile *sourcefile) { strncmp(p, "ensure =>", 9) == 0 || strncmp(p, "content =>", 10) == 0 || strncmp(p, "source =>", 9) == 0 || - strncmp(p, "include ", 8) == 0) + strncmp(p, "include ", 8) == 0) return LANG_PUPPET; /* regexp for checking for define and class declarations */ - + int rc; int ovector[30]; - rc = pcre_exec(re, NULL, p, strlen(p), 0, 0, ovector, 30); + rc = pcre_exec(re, NULL, p, strnlen(p, 100), 0, 0, ovector, 30); if(rc > 0) { return LANG_PUPPET; } From 577b4821362afa417e0ede7b95464f0aa2f169c7 Mon Sep 17 00:00:00 2001 From: John Clements Date: Wed, 6 Jul 2011 12:01:20 -0700 Subject: [PATCH 308/387] adding racket, re-using lisp parser, following clojure's lead --- src/hash/extensions.gperf | 3 +++ src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 1 + src/languages.h | 1 + src/parsers/lisp.rl | 12 +++++++++ test/expected_dir/example.rkt | 12 +++++++++ test/src_dir/example.rkt | 12 +++++++++ test/unit/parser_test.h | 2 ++ test/unit/parsers/test_racket.h | 54 +++++++++++++++++++++++++++++++++++++++++ 9 files changed, 98 insertions(+) create mode 100644 test/expected_dir/example.rkt create mode 100644 test/src_dir/example.rkt create mode 100644 test/unit/parsers/test_racket.h diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index ccc5972..9e297f2 100644 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -151,6 +151,9 @@ rb, LANG_RUBY rex, LANG_REXX rexx, LANG_REXX rhtml, LANG_RHTML +rkt, LANG_RACKET +rktd, LANG_RACKET +rktl, LANG_RACKET s, LANG_ASSEMBLER sc, LANG_SCHEME scala, LANG_SCALA diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index b322815..e7f80e6 100644 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -75,6 +75,7 @@ pike, LANG_PIKE, "Pike", 0 puppet, LANG_PUPPET, "Puppet", 0 python, LANG_PYTHON, "Python", 0 r, LANG_R, "R", 0 +racket, LANG_RACKET, "Racket", 0 rexx, LANG_REXX, "rexx", 0 rhtml, LANG_RHTML, "", 0 ruby, LANG_RUBY, "Ruby", 0 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index 04ec084..318a07b 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -159,6 +159,7 @@ pike, parse_pike puppet, parse_puppet python, parse_python r, parse_r +racket, parse_racket rexx, parse_rexx rhtml, parse_rhtml ruby, parse_ruby diff --git a/src/languages.h b/src/languages.h index 107c7a5..5fe156a 100644 --- a/src/languages.h +++ b/src/languages.h @@ -77,6 +77,7 @@ #define LANG_PUPPET "puppet" #define LANG_PYTHON "python" #define LANG_R "r" +#define LANG_RACKET "racket" #define LANG_REXX "rexx" #define LANG_RHTML "rhtml" #define LANG_RUBY "ruby" diff --git a/src/parsers/lisp.rl b/src/parsers/lisp.rl index d115f3e..0698964 100644 --- a/src/parsers/lisp.rl +++ b/src/parsers/lisp.rl @@ -159,4 +159,16 @@ void parse_clojure(char *buffer, int length, int count, LISP_LANG = ORIG_LISP_LANG; } +const char *RACKET_LANG = LANG_RACKET; +void parse_racket(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + LISP_LANG = RACKET_LANG; + parse_lisp(buffer, length, count, callback, userdata); + LISP_LANG = ORIG_LISP_LANG; +} + + #endif diff --git a/test/expected_dir/example.rkt b/test/expected_dir/example.rkt new file mode 100644 index 0000000..9c3f2e4 --- /dev/null +++ b/test/expected_dir/example.rkt @@ -0,0 +1,12 @@ +racket comment ;; language declaration commented out until someone extends the +racket comment ;; parser to support it: +racket blank +racket comment ;; #lang racket +racket blank +racket comment ;; Report each unique line from stdin +racket code (let ([saw (make-hash)]) +racket code (for ([line (in-lines)]) +racket code (unless (hash-ref saw line #f) +racket code (displayln line)) +racket code (hash-set! saw line #t))) +racket blank diff --git a/test/src_dir/example.rkt b/test/src_dir/example.rkt new file mode 100644 index 0000000..502b961 --- /dev/null +++ b/test/src_dir/example.rkt @@ -0,0 +1,12 @@ +;; language declaration commented out until someone extends the +;; parser to support it: + +;; #lang racket + +;; Report each unique line from stdin +(let ([saw (make-hash)]) + (for ([line (in-lines)]) + (unless (hash-ref saw line #f) + (displayln line)) + (hash-set! saw line #t))) + diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index 2831972..8b39704 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -133,6 +133,7 @@ void test_parser_verify_entity(SourceFile *sf, const char *entity, #include "parsers/test_puppet.h" #include "parsers/test_python.h" #include "parsers/test_r.h" +#include "parsers/test_racket.h" #include "parsers/test_rexx.h" #include "parsers/test_rhtml.h" #include "parsers/test_ruby.h" @@ -307,6 +308,7 @@ void all_parser_tests() { all_pike_tests(); all_python_tests(); all_r_tests(); + all_racket_tests(); all_rexx_tests(); all_rhtml_tests(); all_ruby_tests(); diff --git a/test/unit/parsers/test_racket.h b/test/unit/parsers/test_racket.h new file mode 100644 index 0000000..9267a8f --- /dev/null +++ b/test/unit/parsers/test_racket.h @@ -0,0 +1,54 @@ +/* renamed from lisp unit tests... + * lots more possible here. + */ + +void test_racket_comment() { + test_parser_verify_parse( + test_parser_sourcefile("racket", " ;;; comment"), + "racket", "", ";;; comment", 0 + ); +} + +void test_racket_doc_string() { + test_parser_verify_parse( + test_parser_sourcefile("racket", " \"\"\" comment \"\"\""), + "racket", "", "\"\"\" comment \"\"\"", 0 + ); +} + +void test_racket_doc_string_blank() { + test_parser_verify_parse( + test_parser_sourcefile("racket", " \"\"\"\"\"\""), + "racket", "", "\"\"\"\"\"\"", 0 + ); +} + +void test_racket_empty_string() { + test_parser_verify_parse( + test_parser_sourcefile("racket", "\"\""), + "racket", "\"\"", "", 0 + ); +} + +void test_racket_char_string() { + test_parser_verify_parse( + test_parser_sourcefile("racket", " \"a\""), + "racket", "\"a\"", "", 0 + ); +} + +void test_racket_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("racket", " ;comment"), + "comment", ";comment" + ); +} + +void all_racket_tests() { + test_racket_comment(); + test_racket_doc_string(); + test_racket_doc_string_blank(); + test_racket_empty_string(); + test_racket_char_string(); + test_racket_comment_entities(); +} From 629ea7ca5be1c9aaa37dedae7ce865a8d42ff5f9 Mon Sep 17 00:00:00 2001 From: Paulo Moura Date: Sun, 7 Aug 2011 00:10:31 +0100 Subject: [PATCH 309/387] Added basic support for Logtalk and Prolog. --- src/detector.c | 11 +++++++++++ src/hash/disambiguatefuncs.gperf | 2 ++ src/hash/extensions.gperf | 3 ++- src/hash/languages.gperf | 2 ++ src/hash/parsers.gperf | 4 ++++ src/languages.h | 2 ++ 6 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/detector.c b/src/detector.c index b0da12d..87f634c 100644 --- a/src/detector.c +++ b/src/detector.c @@ -688,6 +688,17 @@ const char *disambiguate_pp(SourceFile *sourcefile) { return LANG_PASCAL; } +const char *disambiguate_pl(SourceFile *sourcefile) { + // Attempt to detect based on file contents. + char *contents = ohcount_sourcefile_get_contents(sourcefile); + if (contents && strstr(contents, "#!/usr/bin/perl")) + return LANG_PERL; + else if (contents && strstr(contents, ":-")) + return LANG_PROLOG; + else + return LANG_PERL; +} + #define QMAKE_SOURCES_SPACE "SOURCES +=" #define QMAKE_SOURCES "SOURCES+=" #define QMAKE_CONFIG_SPACE "CONFIG +=" diff --git a/src/hash/disambiguatefuncs.gperf b/src/hash/disambiguatefuncs.gperf index d48989d..efa2bb5 100644 --- a/src/hash/disambiguatefuncs.gperf +++ b/src/hash/disambiguatefuncs.gperf @@ -11,6 +11,7 @@ const char *disambiguate_h(SourceFile *sourcefile); const char *disambiguate_in(SourceFile *sourcefile); const char *disambiguate_inc(SourceFile *sourcefile); const char *disambiguate_m(SourceFile *sourcefile); +const char *disambiguate_pl(SourceFile *sourcefile); const char *disambiguate_pp(SourceFile *sourcefile); const char *disambiguate_pro(SourceFile *sourcefile); const char *disambiguate_st(SourceFile *sourcefile); @@ -26,6 +27,7 @@ h, disambiguate_h in, disambiguate_in inc, disambiguate_inc m, disambiguate_m +pl, disambiguate_pl pp, disambiguate_pp pro, disambiguate_pro st, disambiguate_st diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index ccc5972..a8c2bf2 100644 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -99,6 +99,7 @@ latex, LANG_TEX lisp, LANG_LISP lsp, LANG_LISP ltx, LANG_TEX +lgt, LANG_LOGTALK lua, LANG_LUA m, DISAMBIGUATE("m") m3, LANG_MODULA3 @@ -133,7 +134,7 @@ php3, LANG_PHP php4, LANG_PHP php5, LANG_PHP pike, LANG_PIKE -pl, LANG_PERL +pl, DISAMBIGUATE("pl") pm, LANG_PERL pmc, LANG_C pmod, LANG_PIKE diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index b322815..65b2929 100644 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -52,6 +52,7 @@ javascript, LANG_JAVASCRIPT, "JavaScript", 0 jsp, LANG_JSP, "", 0 limbo, LANG_LIMBO, "Limbo", 0 lisp, LANG_LISP, "Lisp", 0 +logtalk, LANG_LOGTALK, "Logtalk", 0 lua, LANG_LUA, "Lua", 0 make, LANG_MAKE, "Make", 2 matlab, LANG_MATLAB, "Matlab", 0 @@ -72,6 +73,7 @@ pascal, LANG_PASCAL, "Pascal", 0 perl, LANG_PERL, "Perl", 0 php, LANG_PHP, "PHP", 0 pike, LANG_PIKE, "Pike", 0 +prolog, LANG_PROLOG, "Prolog", 0 puppet, LANG_PUPPET, "Puppet", 0 python, LANG_PYTHON, "Python", 0 r, LANG_R, "R", 0 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index 04ec084..1947d5d 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -42,6 +42,7 @@ #include "../parsers/jsp.h" #include "../parsers/lisp.h" #include "../parsers/limbo.h" +#include "../parsers/logtalk.h" #include "../parsers/lua.h" #include "../parsers/makefile.h" #include "../parsers/matlab.h" @@ -62,6 +63,7 @@ #include "../parsers/perl.h" #include "../parsers/phphtml.h" #include "../parsers/pike.h" +#include "../parsers/prolog.h" #include "../parsers/puppet.h" #include "../parsers/python.h" #include "../parsers/r.h" @@ -136,6 +138,7 @@ javascript, parse_javascript jsp, parse_jsp lisp, parse_lisp limbo, parse_limbo +logtalk, parse_logtalk lua, parse_lua make, parse_makefile matlab, parse_matlab @@ -156,6 +159,7 @@ pascal, parse_pascal perl, parse_perl php, parse_phtml pike, parse_pike +prolog, parse_prolog puppet, parse_puppet python, parse_python r, parse_r diff --git a/src/languages.h b/src/languages.h index 107c7a5..a88ec46 100644 --- a/src/languages.h +++ b/src/languages.h @@ -54,6 +54,7 @@ #define LANG_JSP "jsp" #define LANG_LIMBO "limbo" #define LANG_LISP "lisp" +#define LANG_LOGTALK "logtalk" #define LANG_LUA "lua" #define LANG_MAKE "make" #define LANG_MATLAB "matlab" @@ -74,6 +75,7 @@ #define LANG_PERL "perl" #define LANG_PHP "php" #define LANG_PIKE "pike" +#define LANG_PROLOG "prolog" #define LANG_PUPPET "puppet" #define LANG_PYTHON "python" #define LANG_R "r" From fdc90846233a020a3b1a6afa73bdd0e98f7fcdb8 Mon Sep 17 00:00:00 2001 From: Paulo Moura Date: Sun, 7 Aug 2011 00:39:39 +0100 Subject: [PATCH 310/387] Added basic support for Logtalk and Prolog (missing parsers in previous commit\!). --- src/parsers/logtalk.rl | 112 +++++++++++++++++++++++++++++++++++++++++++++++++ src/parsers/prolog.rl | 112 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+) create mode 100644 src/parsers/logtalk.rl create mode 100644 src/parsers/prolog.rl diff --git a/src/parsers/logtalk.rl b/src/parsers/logtalk.rl new file mode 100644 index 0000000..337c056 --- /dev/null +++ b/src/parsers/logtalk.rl @@ -0,0 +1,112 @@ +// logtalk.rl written by Paulo Moura. pmouralogtalkorg. + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_LOGTALK_PARSER_H +#define OHCOUNT_LOGTALK_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *LOGTALK_LANG = LANG_LOGTALK; + +// the languages entities +const char *logtalk_entities[] = { + "space", "comment", "string", "any" +}; + +// constants associated with the entities +enum { + LOGTALK_SPACE = 0, LOGTALK_COMMENT, LOGTALK_STRING, LOGTALK_ANY +}; + +/*****************************************************************************/ + +%%{ + machine logtalk; + write data; + include common "common.rl"; + + # Line counting machine + + action logtalk_ccallback { + switch(entity) { + case LOGTALK_SPACE: + ls + break; + case LOGTALK_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(LOGTALK_LANG) + break; + case NEWLINE: + std_newline(LOGTALK_LANG) + } + } + + logtalk_line_comment = '%' @comment nonnewline*; + logtalk_block_comment = '/*' any* :>> '*/'; + logtalk_comment = logtalk_line_comment | logtalk_block_comment; + + logtalk_sq_str = '\'' @code ([^\r\n\f'\\] | '\\' nonnewline)* '\''; + logtalk_dq_str = '"' @code ([^\r\n\f"\\] | '\\' nonnewline)* '"'; + logtalk_string = logtalk_sq_str | logtalk_dq_str; + + logtalk_line := |* + spaces ${ entity = LOGTALK_SPACE; } => logtalk_ccallback; + logtalk_comment; + logtalk_string; + newline ${ entity = NEWLINE; } => logtalk_ccallback; + ^space ${ entity = LOGTALK_ANY; } => logtalk_ccallback; + *|; + + # Entity machine + + action logtalk_ecallback { + callback(LOGTALK_LANG, logtalk_entities[entity], cint(ts), cint(te), + userdata); + } + + logtalk_line_comment_entity = '%' nonnewline*; + logtalk_block_comment_entity = '/*' any* :>> '*/'; + logtalk_comment_entity = logtalk_line_comment_entity | logtalk_block_comment_entity; + + logtalk_entity := |* + space+ ${ entity = LOGTALK_SPACE; } => logtalk_ecallback; + logtalk_comment_entity ${ entity = LOGTALK_COMMENT; } => logtalk_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with Logtalk code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_logtalk(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + %% write init; + cs = (count) ? logtalk_en_logtalk_line : logtalk_en_logtalk_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(LOGTALK_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/src/parsers/prolog.rl b/src/parsers/prolog.rl new file mode 100644 index 0000000..35622a7 --- /dev/null +++ b/src/parsers/prolog.rl @@ -0,0 +1,112 @@ +// prolog.rl written by Paulo Moura. pmouraprologorg. + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_PROLOG_PARSER_H +#define OHCOUNT_PROLOG_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *PROLOG_LANG = LANG_PROLOG; + +// the languages entities +const char *prolog_entities[] = { + "space", "comment", "string", "any" +}; + +// constants associated with the entities +enum { + PROLOG_SPACE = 0, PROLOG_COMMENT, PROLOG_STRING, PROLOG_ANY +}; + +/*****************************************************************************/ + +%%{ + machine prolog; + write data; + include common "common.rl"; + + # Line counting machine + + action prolog_ccallback { + switch(entity) { + case PROLOG_SPACE: + ls + break; + case PROLOG_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(PROLOG_LANG) + break; + case NEWLINE: + std_newline(PROLOG_LANG) + } + } + + prolog_line_comment = '%' @comment nonnewline*; + prolog_block_comment = '/*' any* :>> '*/'; + prolog_comment = prolog_line_comment | prolog_block_comment; + + prolog_sq_str = '\'' @code ([^\r\n\f'\\] | '\\' nonnewline)* '\''; + prolog_dq_str = '"' @code ([^\r\n\f"\\] | '\\' nonnewline)* '"'; + prolog_string = prolog_sq_str | prolog_dq_str; + + prolog_line := |* + spaces ${ entity = PROLOG_SPACE; } => prolog_ccallback; + prolog_comment; + prolog_string; + newline ${ entity = NEWLINE; } => prolog_ccallback; + ^space ${ entity = PROLOG_ANY; } => prolog_ccallback; + *|; + + # Entity machine + + action prolog_ecallback { + callback(PROLOG_LANG, prolog_entities[entity], cint(ts), cint(te), + userdata); + } + + prolog_line_comment_entity = '%' nonnewline*; + prolog_block_comment_entity = '/*' any* :>> '*/'; + prolog_comment_entity = prolog_line_comment_entity | prolog_block_comment_entity; + + prolog_entity := |* + space+ ${ entity = PROLOG_SPACE; } => prolog_ecallback; + prolog_comment_entity ${ entity = PROLOG_COMMENT; } => prolog_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with Prolog code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_prolog(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + %% write init; + cs = (count) ? prolog_en_prolog_line : prolog_en_prolog_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(PROLOG_LANG) } +} + +#endif + +/*****************************************************************************/ From f9ae4eec1ac0ebb15ec71b1468f90b9253264bfa Mon Sep 17 00:00:00 2001 From: Paulo Moura Date: Sun, 7 Aug 2011 01:29:14 +0100 Subject: [PATCH 311/387] Added basic unit tests for Logtalk parsing. --- src/parsers/logtalk.rl | 9 ++++++++- test/detect_files/foo.lgt | 9 +++++++++ test/expected_dir/logtalk.lgt | 11 +++++++++++ test/src_dir/logtalk.lgt | 11 +++++++++++ test/unit/detector_test.h | 1 + test/unit/parser_test.h | 2 ++ test/unit/parsers/test_logtalk.h | 27 +++++++++++++++++++++++++++ 7 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 test/detect_files/foo.lgt create mode 100644 test/expected_dir/logtalk.lgt create mode 100644 test/src_dir/logtalk.lgt create mode 100644 test/unit/parsers/test_logtalk.h diff --git a/src/parsers/logtalk.rl b/src/parsers/logtalk.rl index 337c056..439a901 100644 --- a/src/parsers/logtalk.rl +++ b/src/parsers/logtalk.rl @@ -45,7 +45,14 @@ enum { } logtalk_line_comment = '%' @comment nonnewline*; - logtalk_block_comment = '/*' any* :>> '*/'; + logtalk_block_comment = + '/*' @comment ( + newline %{ entity = INTERNAL_NL; } %logtalk_ccallback + | + ws + | + (nonnewline - ws) @comment + )* :>> '*/'; logtalk_comment = logtalk_line_comment | logtalk_block_comment; logtalk_sq_str = '\'' @code ([^\r\n\f'\\] | '\\' nonnewline)* '\''; diff --git a/test/detect_files/foo.lgt b/test/detect_files/foo.lgt new file mode 100644 index 0000000..673fab2 --- /dev/null +++ b/test/detect_files/foo.lgt @@ -0,0 +1,9 @@ +% this is a Logtalk source file + +:- object(hello_world). + + % the initialization/1 directive argument is automatically executed + % when the object is loaded into memory: + :- initialization((nl, write('********** Hello World! **********'), nl)). + +:- end_object. diff --git a/test/expected_dir/logtalk.lgt b/test/expected_dir/logtalk.lgt new file mode 100644 index 0000000..9f30fe1 --- /dev/null +++ b/test/expected_dir/logtalk.lgt @@ -0,0 +1,11 @@ +logtalk comment /* test file for Logtalk parsing */ +logtalk blank +logtalk comment % this is a Logtalk source file +logtalk blank +logtalk code :- object(hello_world). +logtalk blank +logtalk comment % the initialization/1 directive argument is automatically executed +logtalk comment % when the object is loaded into memory: +logtalk code :- initialization((nl, write('********** Hello World! **********'), nl)). +logtalk blank +logtalk code :- end_object. diff --git a/test/src_dir/logtalk.lgt b/test/src_dir/logtalk.lgt new file mode 100644 index 0000000..e65124b --- /dev/null +++ b/test/src_dir/logtalk.lgt @@ -0,0 +1,11 @@ +/* test file for Logtalk parsing */ + +% this is a Logtalk source file + +:- object(hello_world). + + % the initialization/1 directive argument is automatically executed + % when the object is loaded into memory: + :- initialization((nl, write('********** Hello World! **********'), nl)). + +:- end_object. diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index bbba1c2..4b1556a 100644 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -95,6 +95,7 @@ void test_detector_detect_polyglot() { ASSERT_DETECT(LANG_VALA, "foo.vala"); ASSERT_DETECT(LANG_TEX, "foo.tex"); ASSERT_DETECT(LANG_XSLT, "example.xsl"); + ASSERT_DETECT(LANG_LOGTALK, "foo.lgt"); ASSERT_DETECT(LANG_LISP, "core.lisp"); ASSERT_DETECT(LANG_DMD, "foo.d"); ASSERT_DETECT(LANG_VIM, "foo.vim"); diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index 2831972..880a011 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -116,6 +116,7 @@ void test_parser_verify_entity(SourceFile *sf, const char *entity, #include "parsers/test_javascript.h" #include "parsers/test_jsp.h" #include "parsers/test_lisp.h" +#include "parsers/test_logtalk.h" #include "parsers/test_lua.h" #include "parsers/test_make.h" #include "parsers/test_matlab.h" @@ -291,6 +292,7 @@ void all_parser_tests() { all_javascript_tests(); all_jsp_tests(); all_lisp_tests(); + all_logtalk_tests(); all_lua_tests(); all_make_tests(); all_matlab_tests(); diff --git a/test/unit/parsers/test_logtalk.h b/test/unit/parsers/test_logtalk.h new file mode 100644 index 0000000..950e890 --- /dev/null +++ b/test/unit/parsers/test_logtalk.h @@ -0,0 +1,27 @@ + +void test_logtalk_comments() { + test_parser_verify_parse( + test_parser_sourcefile("logtalk", " %comment"), + "logtalk", "", "//comment", 0 + ); +} + +void test_logtalk_empty_comments() { + test_parser_verify_parse( + test_parser_sourcefile("logtalk", " %\n"), + "logtalk", "", "//\n", 0 + ); +} + +void test_logtalk_block_comment() { + test_parser_verify_parse( + test_parser_sourcefile("logtalk", " /*d*/"), + "logtalk", "", "/*d*/", 0 + ); +} + +void all_logtalk_tests() { + test_logtalk_comments(); + test_logtalk_empty_comments(); + test_logtalk_block_comment(); +} From de940f24c3e1f98631fde79b1d97332291b268a7 Mon Sep 17 00:00:00 2001 From: Paulo Moura Date: Sun, 7 Aug 2011 02:32:11 +0100 Subject: [PATCH 312/387] Added basic unit tests for Prolog parsing. --- src/parsers/prolog.rl | 9 ++++++++- test/detect_files/foo_perl1.pl | 2 ++ test/detect_files/foo_perl2.pl | 3 +++ test/detect_files/foo_prolog1.pl | 6 ++++++ test/expected_dir/prolog.pl | 9 +++++++++ test/src_dir/prolog.pl | 9 +++++++++ test/unit/detector_test.h | 8 ++++++++ 7 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 test/detect_files/foo_perl1.pl create mode 100644 test/detect_files/foo_perl2.pl create mode 100644 test/detect_files/foo_prolog1.pl create mode 100644 test/expected_dir/prolog.pl create mode 100644 test/src_dir/prolog.pl diff --git a/src/parsers/prolog.rl b/src/parsers/prolog.rl index 35622a7..3301f02 100644 --- a/src/parsers/prolog.rl +++ b/src/parsers/prolog.rl @@ -45,7 +45,14 @@ enum { } prolog_line_comment = '%' @comment nonnewline*; - prolog_block_comment = '/*' any* :>> '*/'; + prolog_block_comment = + '/*' @comment ( + newline %{ entity = INTERNAL_NL; } %prolog_ccallback + | + ws + | + (nonnewline - ws) @comment + )* :>> '*/'; prolog_comment = prolog_line_comment | prolog_block_comment; prolog_sq_str = '\'' @code ([^\r\n\f'\\] | '\\' nonnewline)* '\''; diff --git a/test/detect_files/foo_perl1.pl b/test/detect_files/foo_perl1.pl new file mode 100644 index 0000000..8371027 --- /dev/null +++ b/test/detect_files/foo_perl1.pl @@ -0,0 +1,2 @@ +#!/usr/bin/perl +print "Hello, world!\n"; diff --git a/test/detect_files/foo_perl2.pl b/test/detect_files/foo_perl2.pl new file mode 100644 index 0000000..2f94700 --- /dev/null +++ b/test/detect_files/foo_perl2.pl @@ -0,0 +1,3 @@ + +# Also a Perl file but without the shebang line +print "Hello, world!\n"; \ No newline at end of file diff --git a/test/detect_files/foo_prolog1.pl b/test/detect_files/foo_prolog1.pl new file mode 100644 index 0000000..af8467d --- /dev/null +++ b/test/detect_files/foo_prolog1.pl @@ -0,0 +1,6 @@ + +% select(Element, List, Remaining) + +select(H, [H| T], T). +select(H, [X| R], [X| T]) :- + select(H, R, T). \ No newline at end of file diff --git a/test/expected_dir/prolog.pl b/test/expected_dir/prolog.pl new file mode 100644 index 0000000..f009dba --- /dev/null +++ b/test/expected_dir/prolog.pl @@ -0,0 +1,9 @@ +prolog comment /* test file for Prolog parsing */ +prolog blank +prolog comment % this is a Prolog source file +prolog blank +prolog comment % select(Element, List, Remaining) +prolog blank +prolog code select(H, [H| T], T). +prolog code select(H, [X| R], [X| T]) :- +prolog code select(H, R, T). diff --git a/test/src_dir/prolog.pl b/test/src_dir/prolog.pl new file mode 100644 index 0000000..5a82d23 --- /dev/null +++ b/test/src_dir/prolog.pl @@ -0,0 +1,9 @@ +/* test file for Prolog parsing */ + +% this is a Prolog source file + +% select(Element, List, Remaining) + +select(H, [H| T], T). +select(H, [X| R], [X| T]) :- + select(H, R, T). diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index 4b1556a..604592e 100644 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -71,6 +71,13 @@ void test_detector_disambiguate_m() { void test_detector_disambiguate_in() { ASSERT_NODETECT("empty.in"); } + +void test_detector_disambiguate_pl() { + ASSERT_DETECT(LANG_PERL, "foo_perl1.pl"); + ASSERT_DETECT(LANG_PERL, "foo_perl2.pl"); + ASSERT_DETECT(LANG_PROLOG, "foo_prolog1.pl"); +} + void test_detector_disambiguate_pro() { ASSERT_DETECT(LANG_IDL_PVWAVE, "foo.pro"); ASSERT_DETECT(LANG_MAKE, "qmake.pro"); @@ -169,6 +176,7 @@ void all_detector_tests() { test_detector_smalltalk(); test_detector_disambiguate_m(); test_detector_disambiguate_in(); + test_detector_disambiguate_pl(); test_detector_disambiguate_pro(); test_detector_fortran_fixedfree(); test_detector_detect_polyglot(); From 6140158cb949e21956ec6a29d08c351fa1cc887d Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Mon, 8 Aug 2011 15:03:22 -0700 Subject: [PATCH 313/387] OTWO-922 Adds CoffeeScript parser --- src/hash/extensions.gperf | 1 + src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 2 + src/languages.h | 1 + src/parsers/coffeescript.rl | 170 +++++++++++++++++++++++++++++++++++++++++++ test/detect_files/foo.coffee | 2 + test/expected_dir/foo.coffee | 26 +++++++ test/src_dir/foo.coffee | 26 +++++++ test/unit/detector_test.h | 1 + 9 files changed, 230 insertions(+) create mode 100644 src/parsers/coffeescript.rl create mode 100644 test/detect_files/foo.coffee create mode 100644 test/expected_dir/foo.coffee create mode 100644 test/src_dir/foo.coffee diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index 919a6da..caa3a7f 100644 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -35,6 +35,7 @@ cc, LANG_CPP chai, LANG_CHAISCRIPT clj, LANG_CLOJURE cmake, LANG_CMAKE +coffee, LANG_COFFEESCRIPT com, LANG_DCL cpp, LANG_CPP cs, DISAMBIGUATE("cs") diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index ac25849..91d1cfc 100644 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -22,6 +22,7 @@ clearsilver, LANG_CLEARSILVER, "ClearSilver", 0 clearsilver_template, LANG_CLEARSILVER_TEMPLATE, "ClearSilver", 0 clojure, LANG_CLOJURE, "Clojure", 0 cmake, LANG_CMAKE, "Cmake script", 2 +coffescript, LANG_COFFEESCRIPT, "CoffeeScript", 0 cpp, LANG_CPP, "C++", 0 cs_aspx, LANG_CS_ASPX, "", 0 csharp, LANG_CSHARP, "C#", 0 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index ab58fa4..4c1c049 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -15,6 +15,7 @@ #include "../parsers/classic_basic.h" #include "../parsers/clearsilver.h" #include "../parsers/clearsilverhtml.h" +#include "../parsers/coffeescript.h" #include "../parsers/cmake.h" #include "../parsers/cs_aspx.h" #include "../parsers/css.h" @@ -108,6 +109,7 @@ classic_basic, parse_classic_basic clearsilver, parse_clearsilver clearsilver_template, parse_cshtml clojure, parse_clojure +coffeescript, parse_coffeescript cpp, parse_cpp cs_aspx, parse_cs_aspx csharp, parse_csharp diff --git a/src/languages.h b/src/languages.h index b7803d9..14ea1e9 100644 --- a/src/languages.h +++ b/src/languages.h @@ -24,6 +24,7 @@ #define LANG_CLEARSILVER_TEMPLATE "clearsilver_template" #define LANG_CLOJURE "clojure" #define LANG_CMAKE "cmake" +#define LANG_COFFEESCRIPT "coffeescript" #define LANG_CPP "cpp" #define LANG_CS_ASPX "cs_aspx" #define LANG_CSHARP "csharp" diff --git a/src/parsers/coffeescript.rl b/src/parsers/coffeescript.rl new file mode 100644 index 0000000..b08a653 --- /dev/null +++ b/src/parsers/coffeescript.rl @@ -0,0 +1,170 @@ +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_COFFEESCRIPT_PARSER_H +#define OHCOUNT_COFFEESCRIPT_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *COFFEESCRIPT_LANG = LANG_COFFEESCRIPT; + +// the languages entities +const char *coffeescript_entities[] = { + "space", "comment", "string", "any" +}; + +// constants associated with the entities +enum { + COFFEESCRIPT_SPACE = 0, COFFEESCRIPT_COMMENT, COFFEESCRIPT_STRING, COFFEESCRIPT_ANY +}; + +/*****************************************************************************/ + +#include "javascript.h" + +%%{ + machine coffeescript; + write data; + include common "common.rl"; + #EMBED(javascript) + + # Line counting machine + + action coffeescript_ccallback { + switch(entity) { + case COFFEESCRIPT_SPACE: + ls + break; + case COFFEESCRIPT_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(COFFEESCRIPT_LANG) + break; + case NEWLINE: + std_newline(COFFEESCRIPT_LANG) + } + } + + coffeescript_line_comment = ('#') @comment nonnewline*; + coffeescript_block_comment = + '###' @comment ( + newline %{ entity = INTERNAL_NL; } %coffeescript_ccallback + | + ws + | + (nonnewline - ws) @comment + )* :>> '###'; + coffeescript_comment = coffeescript_line_comment | coffeescript_block_comment; + + coffeescript_sq_str = + '\'' @enqueue @code ( + newline %{ entity = INTERNAL_NL; } %coffeescript_ccallback + | + ws + | + [^\r\n\f\t '\\] @code + | + '\\' nonnewline @code + )* '\'' @commit @code; + coffeescript_dq_str = + '"' @enqueue @code ( + newline %{ entity = INTERNAL_NL; } %coffeescript_ccallback + | + ws + | + [^\r\n\f\t "\\] @code + | + '\\' nonnewline @code + )* '"' @commit @code; + coffeescript_sq_here_doc = + '\'\'\'' @code ( + newline %{ entity = INTERNAL_NL; } %coffeescript_ccallback + | + ws + | + (nonnewline - ws) @code + )* :>> '\'\'\'' @code; + coffeescript_dq_here_doc = + '"""' @code ( + newline %{ entity = INTERNAL_NL; } %coffeescript_ccallback + | + ws + | + (nonnewline - ws) @code + )* :>> '"""' @code; + coffeescript_string = (coffeescript_sq_str | coffeescript_dq_str | + coffeescript_sq_here_doc | coffeescript_dq_here_doc) @code; + + coffeescript_js_entry = '`' @code; + coffeescript_js_outry = '`' @check_blank_outry @code; + coffeescript_js_line := |* + coffeescript_js_outry @{ p = ts; fret; }; + # unmodified JavaScript patterns + spaces ${ entity = JS_SPACE; } => js_ccallback; + js_comment; + js_string; + newline ${ entity = NEWLINE; } => js_ccallback; + ^space ${ entity = JS_ANY; } => js_ccallback; + *|; + + coffeescript_line := |* + coffeescript_js_entry @coffeescript_ccallback + @{ saw(JS_LANG); } => { fcall coffeescript_js_line; }; + spaces ${ entity = COFFEESCRIPT_SPACE; } => coffeescript_ccallback; + coffeescript_comment; + coffeescript_string; + newline ${ entity = NEWLINE; } => coffeescript_ccallback; + ^space ${ entity = COFFEESCRIPT_ANY; } => coffeescript_ccallback; + *|; + + # Entity machine + + action coffeescript_ecallback { + callback(COFFEESCRIPT_LANG, coffeescript_entities[entity], cint(ts), cint(te), + userdata); + } + + coffeescript_line_comment_entity = ('#') nonnewline*; + coffeescript_block_comment_entity = '###' any* :>> '###'; + coffeescript_comment_entity = coffeescript_line_comment_entity | + coffeescript_block_comment_entity; + + coffeescript_entity := |* + space+ ${ entity = COFFEESCRIPT_SPACE; } => coffeescript_ecallback; + coffeescript_comment_entity ${ entity = COFFEESCRIPT_COMMENT; } => coffeescript_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with CoffeeScript code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_coffeescript(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + %% write init; + cs = (count) ? coffeescript_en_coffeescript_line : coffeescript_en_coffeescript_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(COFFEESCRIPT_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/test/detect_files/foo.coffee b/test/detect_files/foo.coffee new file mode 100644 index 0000000..f5fa263 --- /dev/null +++ b/test/detect_files/foo.coffee @@ -0,0 +1,2 @@ +# CoffeeScript sample +square = (x) -> x * x diff --git a/test/expected_dir/foo.coffee b/test/expected_dir/foo.coffee new file mode 100644 index 0000000..d121da7 --- /dev/null +++ b/test/expected_dir/foo.coffee @@ -0,0 +1,26 @@ +coffeescript comment # A CoffeeScript parser test file +coffeescript blank +coffeescript code simple_code = true +coffeescript blank +coffeescript comment ### +coffeescript comment A multi-line block comment +coffeescript comment begins and ends with three hash marks +coffeescript comment ### +coffeescript blank +coffeescript code multi_line_string = ''' +coffeescript code A multi-line string constant ("here doc") +coffeescript code begins and ends with three quote marks +coffeescript code ''' +coffeescript blank +coffeescript code foo = "A string can wrap across multiple lines +coffeescript code and may contain #{interpolated_values}" +coffeescript blank +coffeescript blank +coffeescript comment ### +coffeescript comment A clever parser can use Ohcount's "Polyglot" feature treat the +coffeescript comment following as embedded JavaScript. +coffeescript comment ### +javascript code embedded_js = `function() { +javascript code return [document.title, "Hello JavaScript"].join(": "); +coffeescript code }` +coffeescript blank diff --git a/test/src_dir/foo.coffee b/test/src_dir/foo.coffee new file mode 100644 index 0000000..aa0f216 --- /dev/null +++ b/test/src_dir/foo.coffee @@ -0,0 +1,26 @@ +# A CoffeeScript parser test file + +simple_code = true + +### +A multi-line block comment +begins and ends with three hash marks +### + +multi_line_string = ''' + A multi-line string constant ("here doc") + begins and ends with three quote marks + ''' + +foo = "A string can wrap across multiple lines + and may contain #{interpolated_values}" + + +### +A clever parser can use Ohcount's "Polyglot" feature treat the +following as embedded JavaScript. +### +embedded_js = `function() { + return [document.title, "Hello JavaScript"].join(": "); +}` + diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index 6fbd8d1..2d2fb3a 100644 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -121,6 +121,7 @@ void test_detector_detect_polyglot() { ASSERT_DETECT(LANG_AUTOCONF, "m4.m4"); ASSERT_DETECT(LANG_NSIS, "foo.nsi"); ASSERT_DETECT(LANG_NSIS, "foo.nsh"); + ASSERT_DETECT(LANG_COFFEESCRIPT, "foo.coffee"); ASSERT_NODETECT("empty.inc"); } From 6d72715772a7aba424a481ae700ab1abb8642870 Mon Sep 17 00:00:00 2001 From: Piotr Fusik Date: Thu, 15 Jul 2010 20:26:21 +0200 Subject: [PATCH 314/387] Add file extensions "asx" and "as8" - 6502 assembler. --- src/detector.c | 25 +++++++++++++++++++++++++ src/hash/disambiguatefuncs.gperf | 2 ++ src/hash/extensions.gperf | 2 ++ test/detect_files/AdvancedStreamRedirector.asx | 11 +++++++++++ test/detect_files/assembler6502.asx | 21 +++++++++++++++++++++ test/expected_dir/assembler6502.as8 | 21 +++++++++++++++++++++ test/expected_dir/assembler6502.asx | 21 +++++++++++++++++++++ test/src_dir/assembler6502.as8 | 21 +++++++++++++++++++++ test/src_dir/assembler6502.asx | 21 +++++++++++++++++++++ test/unit/detector_test.h | 6 ++++++ 10 files changed, 151 insertions(+) create mode 100644 test/detect_files/AdvancedStreamRedirector.asx create mode 100644 test/detect_files/assembler6502.asx create mode 100644 test/expected_dir/assembler6502.as8 create mode 100644 test/expected_dir/assembler6502.asx create mode 100644 test/src_dir/assembler6502.as8 create mode 100644 test/src_dir/assembler6502.asx diff --git a/src/detector.c b/src/detector.c index 17c79b4..e0dba70 100644 --- a/src/detector.c +++ b/src/detector.c @@ -221,6 +221,31 @@ const char *disambiguate_aspx(SourceFile *sourcefile) { return LANG_CS_ASPX; } +// 6502 assembly or XML-based Advanced Stream Redirector ? +const char *disambiguate_asx(SourceFile *sourcefile) { + char *p = ohcount_sourcefile_get_contents(sourcefile); + char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); + for (; p < eof; p++) { + switch (*p) { + case ' ': + case '\t': + case '\n': + case '\r': + break; + case '<': + case '\0': + // byte-order marks: + case (char) 0xef: + case (char) 0xfe: + case (char) 0xff: + return NULL; // XML + default: + return LANG_ASSEMBLER; + } + } + return LANG_ASSEMBLER; // only blanks - not valid XML, may be valid asm +} + const char *disambiguate_b(SourceFile *sourcefile) { char *p = ohcount_sourcefile_get_contents(sourcefile); char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); diff --git a/src/hash/disambiguatefuncs.gperf b/src/hash/disambiguatefuncs.gperf index db133b7..51e6700 100644 --- a/src/hash/disambiguatefuncs.gperf +++ b/src/hash/disambiguatefuncs.gperf @@ -3,6 +3,7 @@ #include "../sourcefile.h" const char *disambiguate_aspx(SourceFile *sourcefile); +const char *disambiguate_asx(SourceFile *sourcefile); const char *disambiguate_b(SourceFile *sourcefile); const char *disambiguate_basic(SourceFile *sourcefile); const char *disambiguate_cs(SourceFile *sourcefile); @@ -19,6 +20,7 @@ const char *disambiguate_st(SourceFile *sourcefile); struct DisambiguateFuncsMap { const char *key; const char* (*value)(SourceFile*); }; %% aspx, disambiguate_aspx +asx, disambiguate_asx b, disambiguate_b basic, disambiguate_basic cs, disambiguate_cs diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index caa3a7f..875777b 100644 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -13,9 +13,11 @@ adb, LANG_ADA ads, LANG_ADA aiff, BINARY as, LANG_ACTIONSCRIPT +as8, LANG_ASSEMBLER ascx, DISAMBIGUATE("aspx") asm, LANG_ASSEMBLER aspx, DISAMBIGUATE("aspx") +asx, DISAMBIGUATE("asx") au, BINARY avi, BINARY awk, LANG_AWK diff --git a/test/detect_files/AdvancedStreamRedirector.asx b/test/detect_files/AdvancedStreamRedirector.asx new file mode 100644 index 0000000..9aed988 --- /dev/null +++ b/test/detect_files/AdvancedStreamRedirector.asx @@ -0,0 +1,11 @@ + + Example.com Live Stream + + Short Announcement to Play Before Main Stream + + + + Example radio + + + diff --git a/test/detect_files/assembler6502.asx b/test/detect_files/assembler6502.asx new file mode 100644 index 0000000..09846ae --- /dev/null +++ b/test/detect_files/assembler6502.asx @@ -0,0 +1,21 @@ +; "Hello world" in 6502 assembly language for 8-bit Atari. +; Assembler: http://xasm.atari.org/ or http://mads.atari8.info/ + + org $3000 +main lda #$21 + sta $22f + lda #

    dl + sta $231 + jmp * + +text dta d' HELLO, ',d'WORLD! '* + +; Display List +dl dta b($70),b($70),b($70),b($47),a(text),b($41),a(dl) + + org $2e0 + dta a(main) + + end diff --git a/test/expected_dir/assembler6502.as8 b/test/expected_dir/assembler6502.as8 new file mode 100644 index 0000000..177ebcf --- /dev/null +++ b/test/expected_dir/assembler6502.as8 @@ -0,0 +1,21 @@ +assembler comment ; "Hello world" in 6502 assembly language for 8-bit Atari. +assembler comment ; Assembler: http://xasm.atari.org/ or http://mads.atari8.info/ +assembler blank +assembler code org $3000 +assembler code main lda #$21 +assembler code sta $22f +assembler code lda #
    dl +assembler code sta $231 +assembler code jmp * +assembler blank +assembler code text dta d' HELLO, ',d'WORLD! '* +assembler blank +assembler comment ; Display List +assembler code dl dta b($70),b($70),b($70),b($47),a(text),b($41),a(dl) +assembler blank +assembler code org $2e0 +assembler code dta a(main) +assembler blank +assembler code end diff --git a/test/expected_dir/assembler6502.asx b/test/expected_dir/assembler6502.asx new file mode 100644 index 0000000..177ebcf --- /dev/null +++ b/test/expected_dir/assembler6502.asx @@ -0,0 +1,21 @@ +assembler comment ; "Hello world" in 6502 assembly language for 8-bit Atari. +assembler comment ; Assembler: http://xasm.atari.org/ or http://mads.atari8.info/ +assembler blank +assembler code org $3000 +assembler code main lda #$21 +assembler code sta $22f +assembler code lda #
    dl +assembler code sta $231 +assembler code jmp * +assembler blank +assembler code text dta d' HELLO, ',d'WORLD! '* +assembler blank +assembler comment ; Display List +assembler code dl dta b($70),b($70),b($70),b($47),a(text),b($41),a(dl) +assembler blank +assembler code org $2e0 +assembler code dta a(main) +assembler blank +assembler code end diff --git a/test/src_dir/assembler6502.as8 b/test/src_dir/assembler6502.as8 new file mode 100644 index 0000000..09846ae --- /dev/null +++ b/test/src_dir/assembler6502.as8 @@ -0,0 +1,21 @@ +; "Hello world" in 6502 assembly language for 8-bit Atari. +; Assembler: http://xasm.atari.org/ or http://mads.atari8.info/ + + org $3000 +main lda #$21 + sta $22f + lda #
    dl + sta $231 + jmp * + +text dta d' HELLO, ',d'WORLD! '* + +; Display List +dl dta b($70),b($70),b($70),b($47),a(text),b($41),a(dl) + + org $2e0 + dta a(main) + + end diff --git a/test/src_dir/assembler6502.asx b/test/src_dir/assembler6502.asx new file mode 100644 index 0000000..09846ae --- /dev/null +++ b/test/src_dir/assembler6502.asx @@ -0,0 +1,21 @@ +; "Hello world" in 6502 assembly language for 8-bit Atari. +; Assembler: http://xasm.atari.org/ or http://mads.atari8.info/ + + org $3000 +main lda #$21 + sta $22f + lda #
    dl + sta $231 + jmp * + +text dta d' HELLO, ',d'WORLD! '* + +; Display List +dl dta b($70),b($70),b($70),b($47),a(text),b($41),a(dl) + + org $2e0 + dta a(main) + + end diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index 2d2fb3a..d2b6b66 100644 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -59,6 +59,11 @@ void test_detector_smalltalk() { ASSERT_NODETECT("english.st"); } +void test_detector_disambiguate_asx() { + ASSERT_DETECT(LANG_ASSEMBLER, "assembler6502.asx"); + ASSERT_NODETECT("AdvancedStreamRedirector.asx"); +} + void test_detector_disambiguate_m() { ASSERT_DETECT(LANG_OBJECTIVE_C, "t1.m"); ASSERT_DETECT(LANG_OBJECTIVE_C, "t2.m"); @@ -172,6 +177,7 @@ void test_detector_emacs_mode() { void all_detector_tests() { test_detector_smalltalk(); + test_detector_disambiguate_asx(); test_detector_disambiguate_m(); test_detector_disambiguate_in(); test_detector_disambiguate_pro(); From dcd2f72734bde58320d386cdcc0135fb0acc36f3 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 9 Aug 2011 08:38:16 -0700 Subject: [PATCH 315/387] Completes eC parser - Adds parse_ec() to the list of parsers - Adds a test to ensure that line counter works --- src/hash/parsers.gperf | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index 04ec084..33e3630 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -115,6 +115,7 @@ dcl, parse_dcl dmd, parse_d dylan, parse_dylan ebuild, parse_ebuild +ec, parse_ec eiffel, parse_eiffel erlang, parse_erlang exheres, parse_exheres From a18e88cf444da89b0b41243f03d1f08ff7681576 Mon Sep 17 00:00:00 2001 From: Paulo Moura Date: Tue, 9 Aug 2011 11:11:04 -0500 Subject: [PATCH 316/387] Minor improvement for detecting Perl files. --- src/detector.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/detector.c b/src/detector.c index 87f634c..0aa71fc 100644 --- a/src/detector.c +++ b/src/detector.c @@ -693,6 +693,8 @@ const char *disambiguate_pl(SourceFile *sourcefile) { char *contents = ohcount_sourcefile_get_contents(sourcefile); if (contents && strstr(contents, "#!/usr/bin/perl")) return LANG_PERL; + else if (contents && strstr(contents, "#!/usr/local/bin/perl")) + return LANG_PERL; else if (contents && strstr(contents, ":-")) return LANG_PROLOG; else From a22bcf1201900635eee6383a71115274e5b9dc88 Mon Sep 17 00:00:00 2001 From: Sebastian Staudt Date: Thu, 11 Aug 2011 14:47:42 +0200 Subject: [PATCH 317/387] Added more filenames and extensions for Ruby --- src/hash/extensions.gperf | 3 +++ src/hash/filenames.gperf | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index 97a1498..0d74d44 100755 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -72,6 +72,7 @@ frm, LANG_VISUALBASIC frx, LANG_VISUALBASIC fs, LANG_FSHARP ftn, DISAMBIGUATE("fortran") +gemspec, LANG_RUBY gif, BINARY glsl, LANG_GLSL go, LANG_GOLANG @@ -154,6 +155,7 @@ r, DISAMBIGUATE("r") r3, LANG_REBOL ra, BINARY rb, LANG_RUBY +rbw, LANG_RUBY reb, LANG_REBOL rebol, LANG_REBOL rex, LANG_REXX @@ -162,6 +164,7 @@ rhtml, LANG_RHTML rkt, LANG_RACKET rktd, LANG_RACKET rktl, LANG_RACKET +ru, LANG_RUBY s, LANG_ASSEMBLER sc, LANG_SCHEME scala, LANG_SCALA diff --git a/src/hash/filenames.gperf b/src/hash/filenames.gperf index c4b5083..b149019 100644 --- a/src/hash/filenames.gperf +++ b/src/hash/filenames.gperf @@ -14,3 +14,7 @@ configure.ac, LANG_AUTOCONF configure.in, LANG_AUTOCONF init.pp, LANG_PUPPET makefile, LANG_MAKE +Rakefile, LANG_RUBY +rakefile, LANG_RUBY +Gemfile, LANG_RUBY +Vagrantfile, LANG_RUBY From 127441e866f2ba14dfacb5f499c4acda1bc02260 Mon Sep 17 00:00:00 2001 From: Sebastian Staudt Date: Thu, 11 Aug 2011 14:50:54 +0200 Subject: [PATCH 318/387] Treat Mustache templates as HTML Mustache introduces only a small amount of additional syntax, so treating its templates as pure HTML shouldn't hurt. --- src/hash/extensions.gperf | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index 97a1498..6436b8b 100755 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -120,6 +120,7 @@ mov, BINARY mp, LANG_METAPOST_WITH_TEX mp3, BINARY mpg, BINARY +mustache, LANG_HTML mxml, LANG_MXML nix, LANG_NIX nse, LANG_LUA From a072689492aff66baf7b148ebb3762d7e4e55bc8 Mon Sep 17 00:00:00 2001 From: Piotr Fusik Date: Mon, 29 Aug 2011 14:42:53 +0200 Subject: [PATCH 319/387] Check if *.def files are Modula-2. --- src/detector.c | 25 +++++++++++++++++++++++++ src/hash/disambiguatefuncs.gperf | 2 ++ src/hash/extensions.gperf | 2 +- test/detect_files/module-definition.def | 5 +++++ test/detect_files/sampleDef.def | 12 ++++++++++++ test/unit/detector_test.h | 6 ++++++ 6 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 test/detect_files/module-definition.def create mode 100644 test/detect_files/sampleDef.def diff --git a/src/detector.c b/src/detector.c index e0dba70..043ce1d 100644 --- a/src/detector.c +++ b/src/detector.c @@ -347,6 +347,31 @@ const char *disambiguate_cs(SourceFile *sourcefile) { return LANG_CSHARP; } +const char *disambiguate_def(SourceFile *sourcefile) { + char *p = ohcount_sourcefile_get_contents(sourcefile); + char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); + for (; p < eof; p++) { + switch (*p) { + case ' ': + case '\t': + case '\n': + case '\r': + break; + case '(': + if (p[1] == '*') // Modula-2 comment + return LANG_MODULA2; + return NULL; + case 'D': + if (strncmp(p, "DEFINITION", 10) == 0) // Modula-2 "DEFINITION MODULE" + return LANG_MODULA2; + return NULL; + default: + return NULL; // not Modula-2 + } + } + return NULL; // only blanks +} + const char *disambiguate_fortran(SourceFile *sourcefile) { char *p, *pe; diff --git a/src/hash/disambiguatefuncs.gperf b/src/hash/disambiguatefuncs.gperf index 51e6700..4202ea6 100644 --- a/src/hash/disambiguatefuncs.gperf +++ b/src/hash/disambiguatefuncs.gperf @@ -7,6 +7,7 @@ const char *disambiguate_asx(SourceFile *sourcefile); const char *disambiguate_b(SourceFile *sourcefile); const char *disambiguate_basic(SourceFile *sourcefile); const char *disambiguate_cs(SourceFile *sourcefile); +const char *disambiguate_def(SourceFile *sourcefile); const char *disambiguate_fortran(SourceFile *sourcefile); const char *disambiguate_h(SourceFile *sourcefile); const char *disambiguate_in(SourceFile *sourcefile); @@ -24,6 +25,7 @@ asx, disambiguate_asx b, disambiguate_b basic, disambiguate_basic cs, disambiguate_cs +def, disambiguate_def fortran, disambiguate_fortran h, disambiguate_h in, disambiguate_in diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index 97a1498..925d626 100755 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -48,7 +48,7 @@ cu, LANG_CUDA cxx, LANG_CPP d, LANG_DMD dat, BINARY -def, LANG_MODULA2 +def, DISAMBIGUATE("def") di, LANG_DMD doc, BINARY dylan, LANG_DYLAN diff --git a/test/detect_files/module-definition.def b/test/detect_files/module-definition.def new file mode 100644 index 0000000..b3a1d21 --- /dev/null +++ b/test/detect_files/module-definition.def @@ -0,0 +1,5 @@ +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/test/detect_files/sampleDef.def b/test/detect_files/sampleDef.def new file mode 100644 index 0000000..cd7c9ed --- /dev/null +++ b/test/detect_files/sampleDef.def @@ -0,0 +1,12 @@ +DEFINITION MODULE Sample; (* in Modula-2 *) + +(* This is a comment *) + +(* This is a comment ... + ... spanning more than one line *) + +CONST + sqString = 'this is a string within "a string" ...'; + dqString = "this is a string within 'a string' ..."; + +END Sample. diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index a67c735..60db30b 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -64,6 +64,11 @@ void test_detector_disambiguate_asx() { ASSERT_NODETECT("AdvancedStreamRedirector.asx"); } +void test_detector_disambiguate_def() { + ASSERT_DETECT(LANG_MODULA2, "sampleDef.def"); + ASSERT_NODETECT("module-definition.def"); +} + void test_detector_disambiguate_m() { ASSERT_DETECT(LANG_OBJECTIVE_C, "t1.m"); ASSERT_DETECT(LANG_OBJECTIVE_C, "t2.m"); @@ -180,6 +185,7 @@ void test_detector_emacs_mode() { void all_detector_tests() { test_detector_smalltalk(); test_detector_disambiguate_asx(); + test_detector_disambiguate_def(); test_detector_disambiguate_m(); test_detector_disambiguate_in(); test_detector_disambiguate_pro(); From 90a85d6be1242b1daaf625a16ae8d2b01fdb27ee Mon Sep 17 00:00:00 2001 From: Caio Marcelo de Oliveira Filho Date: Sat, 22 Oct 2011 02:08:48 -0300 Subject: [PATCH 320/387] Add support for Qt's QML language Reusing the JS parser, since QML is 'almost' JavaScript. The approximation is good enough for the line counting purposes. --- src/hash/extensions.gperf | 1 + src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 1 + src/languages.h | 1 + src/parsers/javascript.rl | 12 ++++++++++++ test/detect_files/foo.qml | 7 +++++++ test/expected_dir/example.qml | 17 +++++++++++++++++ test/src_dir/example.qml | 17 +++++++++++++++++ test/unit/detector_test.h | 1 + test/unit/parser_test.h | 1 + test/unit/parsers/test_qml.h | 23 +++++++++++++++++++++++ 11 files changed, 82 insertions(+) create mode 100644 test/detect_files/foo.qml create mode 100644 test/expected_dir/example.qml create mode 100644 test/src_dir/example.qml create mode 100644 test/unit/parsers/test_qml.h diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index 97a1498..5ef510c 100755 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -149,6 +149,7 @@ pp, DISAMBIGUATE("pp") ppt, BINARY pro, DISAMBIGUATE("pro") py, LANG_PYTHON +qml, LANG_QML qt, BINARY r, DISAMBIGUATE("r") r3, LANG_REBOL diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index dc7eeb4..aebf7a1 100755 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -77,6 +77,7 @@ php, LANG_PHP, "PHP", 0 pike, LANG_PIKE, "Pike", 0 puppet, LANG_PUPPET, "Puppet", 0 python, LANG_PYTHON, "Python", 0 +qml, LANG_QML, "QML", 1 r, LANG_R, "R", 0 racket, LANG_RACKET, "Racket", 0 rebol, LANG_REBOL, "REBOL", 0 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index 9c98093..10facd2 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -164,6 +164,7 @@ php, parse_phtml pike, parse_pike puppet, parse_puppet python, parse_python +qml, parse_qml r, parse_r racket, parse_racket rebol, parse_rebol diff --git a/src/languages.h b/src/languages.h index e62ca97..8a24d0d 100755 --- a/src/languages.h +++ b/src/languages.h @@ -79,6 +79,7 @@ #define LANG_PIKE "pike" #define LANG_PUPPET "puppet" #define LANG_PYTHON "python" +#define LANG_QML "qml" #define LANG_R "r" #define LANG_RACKET "racket" #define LANG_REBOL "rebol" diff --git a/src/parsers/javascript.rl b/src/parsers/javascript.rl index 1f34177..62dfc3e 100644 --- a/src/parsers/javascript.rl +++ b/src/parsers/javascript.rl @@ -134,4 +134,16 @@ void parse_javascript(char *buffer, int length, int count, if (count) { process_last_line(JS_LANG) } } +const char *QML_LANG = LANG_QML; +const char *ORIG_JS_LANG = LANG_JAVASCRIPT; +void parse_qml(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, + int s, int e, void *udata), + void *userdata + ) { + JS_LANG = QML_LANG; + parse_javascript(buffer, length, count, callback, userdata); + JS_LANG = ORIG_JS_LANG; +} + #endif diff --git a/test/detect_files/foo.qml b/test/detect_files/foo.qml new file mode 100644 index 0000000..e30475a --- /dev/null +++ b/test/detect_files/foo.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 + +Rectangle { + width: 200 + height: 200 + color: "crimson" +} diff --git a/test/expected_dir/example.qml b/test/expected_dir/example.qml new file mode 100644 index 0000000..ab96abc --- /dev/null +++ b/test/expected_dir/example.qml @@ -0,0 +1,17 @@ +qml comment // Just an example of QML file... +qml blank +qml code import QtQuick 2.0 +qml blank +qml code Rectangle { +qml code width: 200 +qml code height: 200 +qml code color: "crimson" +qml blank +qml code MouseArea { +qml code anchors.fill: parent +qml code onClicked: { +qml comment // Was clicked +qml code Qt.quit(); +qml code } +qml code } +qml code } diff --git a/test/src_dir/example.qml b/test/src_dir/example.qml new file mode 100644 index 0000000..b92a82d --- /dev/null +++ b/test/src_dir/example.qml @@ -0,0 +1,17 @@ +// Just an example of QML file... + +import QtQuick 2.0 + +Rectangle { + width: 200 + height: 200 + color: "crimson" + + MouseArea { + anchors.fill: parent + onClicked: { + // Was clicked + Qt.quit(); + } + } +} diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index a67c735..0f7035c 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -129,6 +129,7 @@ void test_detector_detect_polyglot() { ASSERT_DETECT(LANG_NSIS, "foo.nsi"); ASSERT_DETECT(LANG_NSIS, "foo.nsh"); ASSERT_DETECT(LANG_COFFEESCRIPT, "foo.coffee"); + ASSERT_DETECT(LANG_QML, "foo.qml"); ASSERT_NODETECT("empty.inc"); } diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index 28a3c9a..a04338a 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -133,6 +133,7 @@ void test_parser_verify_entity(SourceFile *sf, const char *entity, #include "parsers/test_pike.h" #include "parsers/test_puppet.h" #include "parsers/test_python.h" +#include "parsers/test_qml.h" #include "parsers/test_r.h" #include "parsers/test_racket.h" #include "parsers/test_rebol.h" diff --git a/test/unit/parsers/test_qml.h b/test/unit/parsers/test_qml.h new file mode 100644 index 0000000..d4ba843 --- /dev/null +++ b/test/unit/parsers/test_qml.h @@ -0,0 +1,23 @@ + +void test_qml_comments() { + test_parser_verify_parse( + test_parser_sourcefile("qml", " //comment"), + "qml", "", "//comment", 0 + ); +} + +void test_qml_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("qml", " //comment"), + "comment", "//comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("qml", " /*comment*/"), + "comment", "/*comment*/" + ); +} + +void all_qml_tests() { + test_qml_comments(); + test_qml_comment_entities(); +} From 2bad7f93b0c6528c55d2725f38683cb8bbf500f4 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Sun, 9 Oct 2011 17:06:59 -0400 Subject: [PATCH 321/387] Enable building on Mac, which lacks the strnlen function by using memchr instead of it --- src/detector.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/detector.c b/src/detector.c index e0dba70..f03f831 100644 --- a/src/detector.c +++ b/src/detector.c @@ -678,6 +678,12 @@ const char *disambiguate_m(SourceFile *sourcefile) { #include +// strnlen is not available on OS X, so we roll our own +size_t mystrnlen(const char *begin, size_t maxlen) { + const char *end = memchr(begin, '\0', maxlen); + return end ? (end - begin) : maxlen; +} + const char *disambiguate_pp(SourceFile *sourcefile) { char *p = ohcount_sourcefile_get_contents(sourcefile); char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); @@ -704,7 +710,7 @@ const char *disambiguate_pp(SourceFile *sourcefile) { int rc; int ovector[30]; - rc = pcre_exec(re, NULL, p, strnlen(p, 100), 0, 0, ovector, 30); + rc = pcre_exec(re, NULL, p, mystrnlen(p, 100), 0, 0, ovector, 30); if(rc > 0) { return LANG_PUPPET; } From 431ee2fbe3d2bf83abc2eb6d655fa396a1960ebc Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 15 Dec 2011 14:30:59 -0800 Subject: [PATCH 322/387] Fixes crash in disambiguate_r() when source file is empty Thanks to ehsan for discovering this bug. --- src/detector.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/detector.c b/src/detector.c index f03f831..c7125b4 100644 --- a/src/detector.c +++ b/src/detector.c @@ -739,6 +739,9 @@ const char *disambiguate_pro(SourceFile *sourcefile) { const char *disambiguate_r(SourceFile *sourcefile) { char *contents = ohcount_sourcefile_get_contents(sourcefile); + if (!contents) + return LANG_R; + char *eof = contents + ohcount_sourcefile_get_contents_size(sourcefile); // Detect REBOL by looking for the occurence of "rebol" in the contents From 50e8a86d8e3bd885f759897ceb5d9ea7b278dcf0 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 15 Dec 2011 14:48:16 -0800 Subject: [PATCH 323/387] Corrections to Logtalk unit tests --- test/unit/parsers/test_logtalk.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/parsers/test_logtalk.h b/test/unit/parsers/test_logtalk.h index 950e890..8b83ffb 100644 --- a/test/unit/parsers/test_logtalk.h +++ b/test/unit/parsers/test_logtalk.h @@ -2,14 +2,14 @@ void test_logtalk_comments() { test_parser_verify_parse( test_parser_sourcefile("logtalk", " %comment"), - "logtalk", "", "//comment", 0 + "logtalk", "", "%comment", 0 ); } void test_logtalk_empty_comments() { test_parser_verify_parse( test_parser_sourcefile("logtalk", " %\n"), - "logtalk", "", "//\n", 0 + "logtalk", "", "%\n", 0 ); } From b9cdabaf7a7f0d210bc7652d6ef8df14c8d12c48 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Fri, 16 Dec 2011 11:19:19 -0800 Subject: [PATCH 324/387] Adds additional comment styles for MS-DOS batch files In addition to 'REM', we now accept '@REM' and '::'. Note that test/expected_dir/bat1.bat should be tab-delimited (not space-delimited), so this patch also corrects that. --- src/parsers/bat.rl | 4 ++-- test/expected_dir/bat1.bat | 5 +++++ test/src_dir/bat1.bat | 5 +++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/parsers/bat.rl b/src/parsers/bat.rl index 682720c..9966a21 100644 --- a/src/parsers/bat.rl +++ b/src/parsers/bat.rl @@ -44,7 +44,7 @@ enum { } } - bat_comment = /rem/i @comment nonnewline*; + bat_comment = ( /rem/i | /@rem/i | '::' ) @comment nonnewline*; bat_line := |* spaces ${ entity = BAT_SPACE; } => bat_ccallback; @@ -59,7 +59,7 @@ enum { callback(BAT_LANG, bat_entities[entity], cint(ts), cint(te), userdata); } - bat_comment_entity = /rem/i nonnewline*; + bat_comment_entity = ( /rem/i | /@rem/i | '::' ) nonnewline*; bat_entity := |* space+ ${ entity = BAT_SPACE; } => bat_ecallback; diff --git a/test/expected_dir/bat1.bat b/test/expected_dir/bat1.bat index 037c64d..fa70f7f 100644 --- a/test/expected_dir/bat1.bat +++ b/test/expected_dir/bat1.bat @@ -1,6 +1,11 @@ bat comment REM comment 1 bat comment rem comment 2 bat comment rEm comment 3 +bat comment rEm.comment 4 +bat comment Rem=comment 5 +bat comment @Rem comment 6 +bat comment @reM=comment 7 +bat comment ::comment 8 bat blank bat code echo not a rem comment! bat blank diff --git a/test/src_dir/bat1.bat b/test/src_dir/bat1.bat index d04519b..acb3486 100644 --- a/test/src_dir/bat1.bat +++ b/test/src_dir/bat1.bat @@ -1,6 +1,11 @@ REM comment 1 rem comment 2 rEm comment 3 +rEm.comment 4 +Rem=comment 5 +@Rem comment 6 +@reM=comment 7 +::comment 8 echo not a rem comment! From 3539672d96df456aaeb7293c19f8254ddab2bcda Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Wed, 21 Dec 2011 09:46:35 -0800 Subject: [PATCH 325/387] OTWO-1137 Escapes single quotes in file paths --- src/detector.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/detector.c b/src/detector.c index aba9b2b..d2079c8 100644 --- a/src/detector.c +++ b/src/detector.c @@ -25,6 +25,25 @@ # define mkstemp(p) _open(_mktemp(p), _O_CREAT | _O_SHORT_LIVED | _O_EXCL) #endif +/* Replaces single quotes (') with an escape sequence ('\'') + * suitable for use on the command line. + */ +void escape_path(char *safe, const char *unsafe) { + do { + switch (*unsafe) { + case '\'': + *safe++ = '\''; + *safe++ = '\\'; + *safe++ = '\''; + *safe++ = '\''; + break; + default: + *safe++ = *unsafe; + break; + } + } while (*unsafe++); +} + const char *ohcount_detect_language(SourceFile *sourcefile) { const char *language = NULL; char *p, *pe; @@ -135,8 +154,13 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { close(fd); tmpfile = 1; } - char command[strlen(path) + 11]; - sprintf(command, "file -b '%s'", path); + + /* Filenames may include single quotes, which must be escaped */ + char escaped_path[strlen(path) * 4 + 1]; + escape_path(escaped_path, path); + + char command[strlen(escaped_path) + 11]; + sprintf(command, "file -b '%s'", escaped_path); FILE *f = popen(command, "r"); if (f) { if (fgets(line, sizeof(line), f) == NULL) { From 140f487859b6b5da92752c29ae186882ae9449a5 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Thu, 22 Dec 2011 08:07:09 -0800 Subject: [PATCH 326/387] Adds unit test for escape_path() --- src/detector.h | 3 +++ test/unit/detector_test.h | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/detector.h b/src/detector.h index 53277b8..48d19dc 100644 --- a/src/detector.h +++ b/src/detector.h @@ -31,4 +31,7 @@ const char *ohcount_detect_language(SourceFile *sourcefile); int ohcount_is_binary_filename(const char *filename); +/* Exported for unit testing */ +void escape_path(char *safe, const char *unsafe); + #endif diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index 40b3390..ae7f9d4 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -191,7 +191,24 @@ void test_detector_emacs_mode() { ASSERT_DETECT(LANG_C, "emacs_mode.c"); } +void test_detector_escape_path() { + char escaped[100]; + + escape_path(escaped, ""); + assert(strcmp(escaped, "") == 0); + + escape_path(escaped, "hello.c"); + assert(strcmp(escaped, "hello.c") == 0); + + escape_path(escaped, "'"); + assert(strcmp(escaped, "\'\\\'\'") == 0); + + escape_path(escaped, "Robin's 'Fancy' Filename"); + assert(strcmp(escaped, "Robin\'\\\'\'s \'\\\'\'Fancy\'\\\'\' Filename") == 0); +} + void all_detector_tests() { + test_detector_escape_path(); test_detector_smalltalk(); test_detector_disambiguate_asx(); test_detector_disambiguate_def(); From d6f0d82bb371100c81c28c56fc17ca0955656d77 Mon Sep 17 00:00:00 2001 From: Harald Klimach Date: Sat, 31 Dec 2011 12:16:11 +0100 Subject: [PATCH 327/387] Return free format in the Fortran disambiguation, if the code is definetly not fixed. --- src/detector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detector.c b/src/detector.c index d2079c8..82c5232 100644 --- a/src/detector.c +++ b/src/detector.c @@ -406,7 +406,7 @@ const char *disambiguate_fortran(SourceFile *sourcefile) { int i; for (i = 1; i <= 5; i++) if (!isdigit(*(p + i)) && *(p + i) != ' ') - return LANG_FORTRANFIXED; // definately not f77 + return LANG_FORTRANFREE; // definately not fixed // Possibly fixed (doesn't match /^\s*\d+\s*$/). pe = p; while (*pe == ' ' || *pe == '\t') pe++; From c18af47c35634eb354057bfc979b0a79dbedd398 Mon Sep 17 00:00:00 2001 From: Harald Klimach Date: Mon, 2 Jan 2012 01:33:38 +0100 Subject: [PATCH 328/387] More typical Fortran free formatted test file. --- test/detect_files/fortranfree.f | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/detect_files/fortranfree.f b/test/detect_files/fortranfree.f index 5da5944..d980995 100644 --- a/test/detect_files/fortranfree.f +++ b/test/detect_files/fortranfree.f @@ -1,8 +1,8 @@ ! -*- F90 -*- - program fortranfreecheck -! Simple check. Not valid fixed form thanks to the continuation. - write(*,*) 2 + & -& 2 - goto 22 +program fortranfreecheck +! Simple check. Not valid fixed form thanks to code starting in first column. + write(*,*) 2 + & + & 2 + goto 22 22 write(*,*) 'bar' - end +end program fortranfreecheck From bb382f24ffdd07cd089b09d50c3df6fbd8848fbc Mon Sep 17 00:00:00 2001 From: Harald Klimach Date: Tue, 3 Jan 2012 10:27:44 +0100 Subject: [PATCH 329/387] Changed the logic to disambiguate free and fixed formatted Fortran Test the assumption of a fixed format code and indicate free format, as soon as any line breaks this assumption. (It is easier to check for fixed form constraints) Rules for fixed format are taken from the standard, see ftp://ftp.nag.co.uk/sc22wg5/N1801-N1850/N1830.pdf p. 47. --- src/detector.c | 91 +++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 29 deletions(-) diff --git a/src/detector.c b/src/detector.c index 82c5232..e5f8828 100644 --- a/src/detector.c +++ b/src/detector.c @@ -397,43 +397,76 @@ const char *disambiguate_def(SourceFile *sourcefile) { } const char *disambiguate_fortran(SourceFile *sourcefile) { - char *p, *pe; + char *p; p = ohcount_sourcefile_get_contents(sourcefile); char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); + + // Try the assumption of a fixed formatted source code, and return free + // format if anything opposes this assumption. + // Rules based on the Fortran standard, page 47: + // ftp://ftp.nag.co.uk/sc22wg5/N1801-N1850/N1830.pdf while (p < eof) { - if (*p == ' ' && p + 5 < eof) { - int i; - for (i = 1; i <= 5; i++) - if (!isdigit(*(p + i)) && *(p + i) != ' ') - return LANG_FORTRANFREE; // definately not fixed - // Possibly fixed (doesn't match /^\s*\d+\s*$/). - pe = p; - while (*pe == ' ' || *pe == '\t') pe++; - if (pe - p <= 5) { - if (!isdigit(*pe)) - return LANG_FORTRANFIXED; - while (isdigit(*pe)) pe++; - while (*pe == ' ' || *pe == '\t') pe++; - if (*pe != '\r' && *pe != '\n' && pe - p == 5) - return LANG_FORTRANFIXED; - } - } - while (*p != '\r' && *p != '\n' && *p != '&' && p < eof) p++; - if (*p == '&') { - p++; - // Look for free-form continuation. - while (*p == ' ' || *p == '\t') p++; - if (*p == '\r' || *p == '\n') { - pe = p; - while (*pe == '\r' || *pe == '\n' || *pe == ' ' || *pe == '\t') pe++; - if (*pe == '&') + int i = 1; + int blanklabel; + // Process a single line; tabulators are not valid in Fortran code + // but some compilers accept them to skip the first 5 columns. + if (*p == ' ' || *p == '\t' || isdigit(*p)) { + // Only consider lines starting with a blank or digit + // (non-comment in fixed) + if (*p == '\t') i = 5; + blanklabel = (*p == ' ' || *p == '\t'); + while (*p != '\r' && *p != '\n' && p < eof) { + p++; i++; + if (i <= 5) { + blanklabel = blanklabel && (*p == ' '); + if ( !isdigit(*p) && *p != ' ' && *p != '!') + // Non-digit, non-blank, non-comment character in the label field + // definetly not valid fixed formatted code! + return LANG_FORTRANFREE; + } + if ((i == 6) && !blanklabel && *p != ' ' && *p != '0') + // Fixed format continuation line with non-blank label field + // not allowed, assume free format: return LANG_FORTRANFREE; + // Ignore comments (a ! character in column 6 is a continuation in + // fixed form) + if (*p == '!' && i != 6) { + while (*p != '\r' && *p != '\n' && p < eof) p++; + } else { + // Ignore quotes + if (*p == '"') { + if (p < eof) {p++; i++;} + while (*p != '"' && *p != '\r' && *p != '\n' && p < eof) { + p++; i++; + } + } + if (*p == '\'') { + if (p < eof) {p++; i++;} + while (*p != '\'' && *p != '\r' && *p != '\n' && p < eof) { + p++; i++; + } + } + // Check for free format line continuation + if (i > 6 && i <= 72 && *p == '&') + // Found an unquoted free format continuation character in the fixed + // format code section. This has to be free format. + return LANG_FORTRANFREE; + } } + } else { + // Not a statement line in fixed format... + if (*p != 'C' && *p != 'c' && *p != '*' && *p != '!') + // Not a valid fixed form comment, has to be free formatted source + return LANG_FORTRANFREE; + // Comment in fixed form, ignore this line + while (*p != '\r' && *p != '\n' && p < eof) p++; } - while (*p == '\r' || *p == '\n') p++; + // Skip all line ends + while ((*p == '\r' || *p == '\n') && p < eof) p++; } - return LANG_FORTRANFREE; // might as well be free-form + // Assume fixed format if none of the lines broke the assumptions + return LANG_FORTRANFIXED; } const char *disambiguate_h(SourceFile *sourcefile) { From bd31ad2e9de91ba5b9f63cf80031ad27efddd45d Mon Sep 17 00:00:00 2001 From: Harald Klimach Date: Tue, 3 Jan 2012 11:45:10 +0100 Subject: [PATCH 330/387] Update Fortran extensions to cover the list, supported by gfortran (.FPP, .F, .FOR, .FTN, .F90, .F95, .F03 or .F08), see http://gcc.gnu.org/onlinedocs/gfortran/Preprocessing-Options.html --- src/hash/extensions.gperf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index 58bc9ea..8edd6c5 100755 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -63,11 +63,14 @@ exheres-0, LANG_EXHERES exlib, LANG_EXHERES f, DISAMBIGUATE("fortran") f03, DISAMBIGUATE("fortran") +f08, DISAMBIGUATE("fortran") f77, DISAMBIGUATE("fortran") f90, DISAMBIGUATE("fortran") f95, DISAMBIGUATE("fortran") factor, LANG_FACTOR frag, LANG_GLSL +for, DISAMBIGUATE("fortran") +fpp, DISAMBIGUATE("fortran") frm, LANG_VISUALBASIC frx, LANG_VISUALBASIC fs, LANG_FSHARP From 8aa2a6a058d65e414c24cbe53b7847d98a2945cf Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Wed, 8 Feb 2012 10:24:28 -0500 Subject: [PATCH 331/387] OTWO-1300 Improves *.pl disambiguation to ignore smileys :-) Smiley faces in Perl strings and comments look similar to Prolog rule syntax. This patch makes two improvements: - Better detection of perl shebangs (#!%PERL% now recognized) - A prolog ':-' token must be followed by a space or a newline --- src/detector.c | 21 ++++++++++++++------- test/detect_files/perl_shebang_prolog_body.pl | 3 +++ test/detect_files/perl_with_smiley.pl | 2 ++ test/unit/detector_test.h | 2 ++ 4 files changed, 21 insertions(+), 7 deletions(-) create mode 100644 test/detect_files/perl_shebang_prolog_body.pl create mode 100644 test/detect_files/perl_with_smiley.pl diff --git a/src/detector.c b/src/detector.c index d2079c8..e1680a3 100644 --- a/src/detector.c +++ b/src/detector.c @@ -769,16 +769,23 @@ const char *disambiguate_pp(SourceFile *sourcefile) { } const char *disambiguate_pl(SourceFile *sourcefile) { - // Attempt to detect based on file contents. char *contents = ohcount_sourcefile_get_contents(sourcefile); - if (contents && strstr(contents, "#!/usr/bin/perl")) - return LANG_PERL; - else if (contents && strstr(contents, "#!/usr/local/bin/perl")) + if (!contents) + return NULL; + + // Check for a perl shebang on first line of file + const char *error; + int erroffset; + pcre *re = pcre_compile("#![^\\n]*perl", PCRE_CASELESS, &error, &erroffset, NULL); + if (pcre_exec(re, NULL, contents, mystrnlen(contents, 100), 0, PCRE_ANCHORED, NULL, 0) > -1) return LANG_PERL; - else if (contents && strstr(contents, ":-")) + + // Check for prolog :- rules + if (strstr(contents, ":- ") || strstr(contents, ":-\n")) return LANG_PROLOG; - else - return LANG_PERL; + + // Perl by default. + return LANG_PERL; } #define QMAKE_SOURCES_SPACE "SOURCES +=" diff --git a/test/detect_files/perl_shebang_prolog_body.pl b/test/detect_files/perl_shebang_prolog_body.pl new file mode 100644 index 0000000..6e2cad5 --- /dev/null +++ b/test/detect_files/perl_shebang_prolog_body.pl @@ -0,0 +1,3 @@ +#!%PERL% +% This is prolog code, but the shebang says perl, so we respect the shebang and choose perl. +Head :- Body. diff --git a/test/detect_files/perl_with_smiley.pl b/test/detect_files/perl_with_smiley.pl new file mode 100644 index 0000000..076bdd0 --- /dev/null +++ b/test/detect_files/perl_with_smiley.pl @@ -0,0 +1,2 @@ +# This is not prolog. Do not be confused by the smiley, which looks like a Prolog rule. +print "Hello, world :-)\n" diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index ae7f9d4..2492757 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -86,6 +86,8 @@ void test_detector_disambiguate_pl() { ASSERT_DETECT(LANG_PERL, "foo_perl1.pl"); ASSERT_DETECT(LANG_PERL, "foo_perl2.pl"); ASSERT_DETECT(LANG_PROLOG, "foo_prolog1.pl"); + ASSERT_DETECT(LANG_PERL, "perl_with_smiley.pl"); + ASSERT_DETECT(LANG_PERL, "perl_shebang_prolog_body.pl"); } void test_detector_disambiguate_pro() { From ad04b509bd0ff9626e478ab3b1dcfaa4c0a98d53 Mon Sep 17 00:00:00 2001 From: "Daniel C. Sobral" Date: Thu, 23 Feb 2012 18:05:15 -0200 Subject: [PATCH 332/387] Initial support for Forth This is based on the Scala parser, which is actually quite incorrect -- assumes existence of single-quote strings (which will cause problem on any file with symbols), doesn't know multiline strings, doesn't handle nested comments: all of which made it a pretty good starting point for Forth. Parsing Forth is impossible, but this will recognize comments, strings and blank lines on most projects. Tested against FreeBSD source. --- src/hash/extensions.gperf | 2 + src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 2 + src/languages.h | 1 + src/parsers/forth.rl | 117 +++++++++++++++++++++++++++++++++++++++++ test/detect_files/forth.4th | 7 +++ test/detect_files/forth.fr | 7 +++ test/expected_dir/forth.4th | 7 +++ test/src_dir/forth.4th | 7 +++ test/unit/detector_test.h | 2 + test/unit/parser_test.h | 2 + test/unit/parsers/test_forth.h | 15 ++++++ 12 files changed, 170 insertions(+) create mode 100644 src/parsers/forth.rl create mode 100644 test/detect_files/forth.4th create mode 100644 test/detect_files/forth.fr create mode 100644 test/expected_dir/forth.4th create mode 100644 test/src_dir/forth.4th create mode 100644 test/unit/parsers/test_forth.h diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index 58bc9ea..71b2b26 100755 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -6,6 +6,7 @@ %} struct ExtensionMap { const char *key; const char *value; }; %% +4th, LANG_FORTH C, LANG_CPP H, LANG_CPP ada, LANG_ADA @@ -67,6 +68,7 @@ f77, DISAMBIGUATE("fortran") f90, DISAMBIGUATE("fortran") f95, DISAMBIGUATE("fortran") factor, LANG_FACTOR +fr, LANG_FORTH frag, LANG_GLSL frm, LANG_VISUALBASIC frx, LANG_VISUALBASIC diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index 7d400bc..773cf2b 100755 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -38,6 +38,7 @@ emacslisp, LANG_EMACSLISP, "Emacs lisp", 0 erlang, LANG_ERLANG, "Erlang", 0 exheres, LANG_EXHERES, "Exheres", 0 factor, LANG_FACTOR, "Factor", 0 +forth, LANG_FORTH, "Forth", 0 fortranfixed, LANG_FORTRANFIXED, "Fortan (Fixed-format)", 0 fortranfree, LANG_FORTRANFREE, "Fortan (Free-format)", 0 fsharp, LANG_FSHARP, "F#", 0 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index 2493117..08c8d6a 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -27,6 +27,7 @@ #include "../parsers/erlang.h" #include "../parsers/exheres.h" #include "../parsers/factor.h" +#include "../parsers/forth.h" #include "../parsers/fortranfixed.h" #include "../parsers/fortranfree.h" #include "../parsers/fsharp.h" @@ -127,6 +128,7 @@ erlang, parse_erlang exheres, parse_exheres emacslisp, parse_emacslisp factor, parse_factor +forth, parse_forth fortranfixed, parse_fortranfixed fortranfree, parse_fortranfree fsharp, parse_fsharp diff --git a/src/languages.h b/src/languages.h index 6c06960..259ec20 100755 --- a/src/languages.h +++ b/src/languages.h @@ -40,6 +40,7 @@ #define LANG_EXHERES "exheres" #define LANG_EMACSLISP "emacslisp" #define LANG_FACTOR "factor" +#define LANG_FORTH "forth" #define LANG_FORTRANFIXED "fortranfixed" #define LANG_FORTRANFREE "fortranfree" #define LANG_FSHARP "fsharp" diff --git a/src/parsers/forth.rl b/src/parsers/forth.rl new file mode 100644 index 0000000..c7c53c0 --- /dev/null +++ b/src/parsers/forth.rl @@ -0,0 +1,117 @@ +// forth.rl +// derived from code written by Mitchell Foral. mitchellcaladbolgnet. + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_FORTH_PARSER_H +#define OHCOUNT_FORTH_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *FORTH_LANG = LANG_FORTH; + +// the languages entities +const char *forth_entities[] = { + "space", "comment", "string", "any", +}; + +// constants associated with the entities +enum { + FORTH_SPACE = 0, FORTH_COMMENT, FORTH_STRING, FORTH_ANY +}; + +/*****************************************************************************/ + +%%{ + machine forth; + write data; + include common "common.rl"; + + # Line counting machine + + action forth_ccallback { + switch(entity) { + case FORTH_SPACE: + ls + break; + case FORTH_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(FORTH_LANG) + break; + case NEWLINE: + std_newline(FORTH_LANG) + } + } + + forth_line_comment = '\\' @comment nonnewline*; + forth_block_comment = + '(' @comment ( + newline %{ entity = INTERNAL_NL; } %forth_ccallback + | + ws + | + (nonnewline - ws) @comment + )* :>> ')'; + forth_comment = forth_line_comment | forth_block_comment; + + forth_string = '"' @code ([^\r\n\f"])* '"'; + + forth_line := |* + spaces ${ entity = FORTH_SPACE; } => forth_ccallback; + forth_comment; + forth_string; + newline ${ entity = NEWLINE; } => forth_ccallback; + ^space ${ entity = FORTH_ANY; } => forth_ccallback; + *|; + + # Entity machine + + action forth_ecallback { + callback(FORTH_LANG, forth_entities[entity], cint(ts), cint(te), userdata); + } + + forth_line_comment_entity = '\\' nonnewline*; + forth_block_comment_entity = '(' any* :>> ')'; + forth_comment_entity = forth_line_comment_entity | forth_block_comment_entity; + + forth_entity := |* + space+ ${ entity = FORTH_SPACE; } => forth_ecallback; + forth_comment_entity ${ entity = FORTH_COMMENT; } => forth_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with Forth code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_forth(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + %% write init; + cs = (count) ? forth_en_forth_line : forth_en_forth_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(FORTH_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/test/detect_files/forth.4th b/test/detect_files/forth.4th new file mode 100644 index 0000000..75ce18d --- /dev/null +++ b/test/detect_files/forth.4th @@ -0,0 +1,7 @@ +\ Sample Forth code + +( This is a comment + spanning multiple lines ) + +: somedefinition ; + diff --git a/test/detect_files/forth.fr b/test/detect_files/forth.fr new file mode 100644 index 0000000..75ce18d --- /dev/null +++ b/test/detect_files/forth.fr @@ -0,0 +1,7 @@ +\ Sample Forth code + +( This is a comment + spanning multiple lines ) + +: somedefinition ; + diff --git a/test/expected_dir/forth.4th b/test/expected_dir/forth.4th new file mode 100644 index 0000000..e7f5ab5 --- /dev/null +++ b/test/expected_dir/forth.4th @@ -0,0 +1,7 @@ +forth comment \ Sample Forth code +forth blank +forth comment ( This is a comment +forth comment spanning multiple lines ) +forth blank +forth code : somedefinition ; +forth blank diff --git a/test/src_dir/forth.4th b/test/src_dir/forth.4th new file mode 100644 index 0000000..75ce18d --- /dev/null +++ b/test/src_dir/forth.4th @@ -0,0 +1,7 @@ +\ Sample Forth code + +( This is a comment + spanning multiple lines ) + +: somedefinition ; + diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index 2492757..a1fd212 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -139,6 +139,8 @@ void test_detector_detect_polyglot() { ASSERT_DETECT(LANG_IDL_PVWAVE, "foo.pro"); ASSERT_DETECT(LANG_ASSEMBLER, "foo.z80"); ASSERT_DETECT(LANG_PHP, "php.inc"); + ASSERT_DETECT(LANG_FORTH, "forth.4th"); + ASSERT_DETECT(LANG_FORTH, "forth.fr"); ASSERT_DETECT(LANG_FSHARP, "fs1.fs"); ASSERT_DETECT(LANG_AUTOCONF, "m4.m4"); ASSERT_DETECT(LANG_NSIS, "foo.nsi"); diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index 3d50368..bdb7f26 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -102,6 +102,7 @@ void test_parser_verify_entity(SourceFile *sf, const char *entity, #include "parsers/test_erlang.h" #include "parsers/test_exheres.h" #include "parsers/test_factor.h" +#include "parsers/test_forth.h" #include "parsers/test_fortran.h" #include "parsers/test_fsharp.h" #include "parsers/test_glsl.h" @@ -283,6 +284,7 @@ void all_parser_tests() { all_erlang_tests(); all_exheres_tests(); all_factor_tests(); + all_forth_tests(); all_fortran_tests(); all_fsharp_tests(); all_glsl_tests(); diff --git a/test/unit/parsers/test_forth.h b/test/unit/parsers/test_forth.h new file mode 100644 index 0000000..9f93497 --- /dev/null +++ b/test/unit/parsers/test_forth.h @@ -0,0 +1,15 @@ + +void test_forth_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("forth", " \\comment"), + "comment", "\\comment" + ); + test_parser_verify_entity( + test_parser_sourcefile("forth", " (comment)"), + "comment", "(comment)" + ); +} + +void all_forth_tests() { + test_forth_comment_entities(); +} From 912757ac95048f4f2d6bdc1baa87a527b3f0d2b2 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 6 Mar 2012 14:02:18 -0800 Subject: [PATCH 333/387] README updates and corrections --- README => README.md | 54 ++++++++++++++++++++++++----------------------------- 1 file changed, 24 insertions(+), 30 deletions(-) rename README => README.md (54%) diff --git a/README b/README.md similarity index 54% rename from README rename to README.md index cfdfb17..4481ee9 100644 --- a/README +++ b/README.md @@ -1,10 +1,6 @@ == Ohcount == -NOTE: THE PRIMARY DOCUMENTATION FOR OHCOUNT IS EXTRACTED FROM SOURCE CODE -BY DOXYGEN. FOR THE MOST UP-TO-DATE DOCS, PLEASE SEE BELOW FOR INFO -ON BUILDING AND REFERING TO THE DOXYGEN DOCS. - -Ohloh/SourceForge's source code line counter. +Ohloh's source code line counter. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License Version 2 as @@ -43,53 +39,51 @@ language detection features from a Ruby application. == System Requirements == -Ohcount is supported on Mac OS X 10.4 and 10.5 and Ubuntu 8.04 LTS. Other Linux +Ohcount is supported on Mac OS X 10.4 and 10.5 and Ubuntu 10.04 LTS. Other Linux environments should also work, but your mileage may vary. Ohcount does not support Windows. -Ohcount targets Ruby 1.8.6. The build script requires a bash shell. You +Ohcount targets Ruby 1.8.7. The build script requires a bash shell. You also need a C compiler to build the native extensions. == Source Code == Ohcount source code is available as a Git repository: - git clone git://github.com/andyverprauskus/ohcount.git - -== Doc files == - -To build the more extensive Doxygen docs, do - > cd doc - > Doxygen Doxyfile - -After building the docs, view them with a browser by opening doc/html/index.html. -On a mac, you can install Doxygen with "sudo port install Doxygen". -On Debian/Ubuntu, install with "sudo apt-get instal doxygen". + git clone git://github.com/blackducksw/ohcount.git == Building Ohcount == -You will need ragel 6.3 or higher, bash, pcre, gcc (version 4.1.2 or greater) and SWIG to build ohcount. Once you have them, go to the top directory of ohcount and type: +You will need ragel 6.3 or higher, bash, pcre, gcc (version 4.1.2 or greater) and SWIG to build ohcount. Once you have them, go to the top directory of ohcount and run - > bash build -or > ./build +``` +./build +``` == Using Ohcount == -Once you've building ohcount, the executable program will be at bin/ohcount. The most basic use is to count lines of code in a directory tree, run: - "ohcount" to count the current directory and source code in any child directories +Once you've built ohcount, the executable program will be at bin/ohcount. The most basic use is to count lines of code in a directory tree. run: -== For additional docs, including how to add a new language, see the Doxygen docs == +``` +bin/ohcount +``` -Particularly, for instructions on adding a new language, follow the instructions at doc/html/detector_doc.html -Read http://labs.ohloh.net/ohcount/wiki/HowToSubmitPatches for information about having your patch accepted. +Ohcount support several options. Run `ohcount --help` for more information. == Building language wrappers to use ohcount from Ruby or Python == -To build the ruby wrapper, run "bash build ruby". -To build the python wrapper, run "python python/setup.py build; python python/setup.py install". The python wrapper is new and has only been tested on Gentoo and CentOS. Feedback on it is particularly welcome. +To build the ruby wrapper: + +``` +./build ruby +``` +To build the python wrapper, run -== Dependencies == +``` +python python/setup.py build +python python/setup.py install +``` -To build ohcount, your system will need: SWIG, pcre, ragel, gperf, bash +The python wrapper is currently unsupported. From ae92e3f6c6148263f12ef4aabef0d40f42089185 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Tue, 6 Mar 2012 14:05:06 -0800 Subject: [PATCH 334/387] Change README to use Github flavored Markdown --- README.md | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 4481ee9..403f20b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -== Ohcount == +Ohcount +======= Ohloh's source code line counter. @@ -6,6 +7,9 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License Version 2 as published by the Free Software Foundation. +License +------- + Ohcount is specifically licensed under GPL v2.0, and no later version. This program is distributed in the hope that it will be useful, @@ -16,7 +20,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . -== Overview == +Overview +-------- Ohcount is a library for counting lines of source code. It was originally developed at Ohloh, and is used to generate @@ -37,7 +42,8 @@ individual source file. Ohcount includes a Ruby binding which allows you to directly access its language detection features from a Ruby application. -== System Requirements == +System Requirements +------------------- Ohcount is supported on Mac OS X 10.4 and 10.5 and Ubuntu 10.04 LTS. Other Linux environments should also work, but your mileage may vary. @@ -47,13 +53,15 @@ Ohcount does not support Windows. Ohcount targets Ruby 1.8.7. The build script requires a bash shell. You also need a C compiler to build the native extensions. -== Source Code == +Source Code +----------- Ohcount source code is available as a Git repository: git clone git://github.com/blackducksw/ohcount.git -== Building Ohcount == +Building Ohcount +---------------- You will need ragel 6.3 or higher, bash, pcre, gcc (version 4.1.2 or greater) and SWIG to build ohcount. Once you have them, go to the top directory of ohcount and run @@ -61,7 +69,8 @@ You will need ragel 6.3 or higher, bash, pcre, gcc (version 4.1.2 or greater) an ./build ``` -== Using Ohcount == +Using Ohcount +------------- Once you've built ohcount, the executable program will be at bin/ohcount. The most basic use is to count lines of code in a directory tree. run: @@ -71,7 +80,8 @@ bin/ohcount Ohcount support several options. Run `ohcount --help` for more information. -== Building language wrappers to use ohcount from Ruby or Python == +Building Ruby and Python Libraries +---------------------------------- To build the ruby wrapper: From 6bed45d6fb7c080ae5c163c12b4eb8749a3492ac Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Wed, 7 Mar 2012 16:10:11 -0800 Subject: [PATCH 335/387] Use libmagic instead of spawning a process to run `file` --- README.md | 3 +- build | 6 +-- src/detector.c | 158 +++++++++++++++++++++++++++++++++------------------------ 3 files changed, 96 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index 403f20b..edec965 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,8 @@ Ohcount source code is available as a Git repository: Building Ohcount ---------------- -You will need ragel 6.3 or higher, bash, pcre, gcc (version 4.1.2 or greater) and SWIG to build ohcount. Once you have them, go to the top directory of ohcount and run +You will need ragel 6.3 or higher, bash, pcre, magic, gcc (version 4.1.2 or greater) +and SWIG. Once you have them, go to the top directory of ohcount and run ``` ./build diff --git a/build b/build index 8a20208..cc696ac 100755 --- a/build +++ b/build @@ -96,7 +96,7 @@ build_ohcount() build_parser_o echo "Building Ohcount" mkdir -p bin/ - sh -c "$cc src/ohcount.c $files -o bin/ohcount -lpcre" || exit 1 + sh -c "$cc src/ohcount.c $files -o bin/ohcount -lpcre -lmagic" || exit 1 } build_test_suite() @@ -104,7 +104,7 @@ build_test_suite() build_hash_headers build_parser_o echo "Building test suite" - sh -c "$cc test/unit/all_tests.c $files -o test/unit/run_tests -lpcre" \ + sh -c "$cc test/unit/all_tests.c $files -o test/unit/run_tests -lpcre -lmagic" \ || exit 1 } @@ -121,7 +121,7 @@ build_ruby_bindings() mkdir -p ruby/$arch sh -c "$cc $RB_SHARED ruby/ohcount_wrap.c $files -o ruby/$arch/$RB_SHARED_NAME \ -I`ruby -rmkmf -e 'print Config::expand(CONFIG["archdir"])'` \ - -lpcre" || exit 1 + -lpcre -lmagic" || exit 1 sh -c "cd test/unit/ruby && ruby ruby_test.rb" || exit 1 } diff --git a/src/detector.c b/src/detector.c index 2b42d8f..77d19a6 100644 --- a/src/detector.c +++ b/src/detector.c @@ -2,6 +2,7 @@ // See COPYING for license information. #include +#include #include #include #include @@ -44,6 +45,94 @@ void escape_path(char *safe, const char *unsafe) { } while (*unsafe++); } +/* Parse the output of libmagic and return a language, if any. + * The contents of string `line` will be destroyed. + */ +const char *magic_parse(char *line) { + char *p, *pe; + char *eol = line + strlen(line); + + char buf[80]; + size_t length; + + for (p = line; p < eol; p++) *p = tolower(*p); + p = strstr(line, "script text"); + if (p && p == line) { // /^script text(?: executable)? for \w/ + p = strstr(line, "for "); + if (p) { + p += 4; + pe = p; + while (isalnum(*pe)) pe++; + length = pe - p; + strncpy(buf, p, length); + buf[length] = '\0'; + struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); + if (rl) return(rl->name); + } + } else if (p) { // /(\w+)(?: -\w+)* script text/ + do { + p--; + pe = p; + while (*p == ' ') p--; + while (p != line && isalnum(*(p - 1))) p--; + if (p != line && *(p - 1) == '-') p--; + } while (*p == '-'); // Skip over any switches. + length = pe - p; + strncpy(buf, p, length); + buf[length] = '\0'; + struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); + if (rl) return(rl->name); + } else if (strstr(line, "xml")) return(LANG_XML); + + return NULL; +} + +/* Use libmagic to detect file language + */ +const char *detect_language_magic(SourceFile *sourcefile) { + char line[80]; + + magic_t cookie = magic_open(MAGIC_NONE); + if (cookie == NULL) { + fprintf(stderr, "libmagic: %s\n", magic_error(cookie)); + exit(1); + } + if (magic_load(cookie, NULL) != 0) { + fprintf(stderr, "libmagic: %s\n", magic_error(cookie)); + magic_close(cookie); + exit(1); + } + + if (sourcefile->diskpath) { + const char *magic = magic_file(cookie, sourcefile->diskpath); + if (magic == NULL) { + fprintf(stderr, "libmagic: %s\n", magic_error(cookie)); + magic_close(cookie); + exit(1); + } + strncpy(line, magic, sizeof(line)); + line[sizeof(line)-1] = '\0'; + } else { + char *p = ohcount_sourcefile_get_contents(sourcefile); + if (!p) return NULL; + + const char *magic = magic_buffer(cookie, p, strlen(p)); + if (magic == NULL) { + fprintf(stderr, "libmagic: %s\n", magic_error(cookie)); + magic_close(cookie); + exit(1); + } + strncpy(line, magic, sizeof(line)); + line[sizeof(line)-1] = '\0'; + } + + magic_close(cookie); + + return magic_parse(line); +} + +/* Use all available means to detect file language + */ const char *ohcount_detect_language(SourceFile *sourcefile) { const char *language = NULL; char *p, *pe; @@ -135,74 +224,9 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { // Attempt to detect based on Unix 'file' command. if(!language) { - int tmpfile = 0; - char *path = sourcefile->filepath; - if (sourcefile->diskpath) - path = sourcefile->diskpath; - if (access(path, F_OK) != 0) { // create temporary file - path = malloc(21); - strncpy(path, "/tmp/ohcount_XXXXXXX\0", 21); - int fd = mkstemp(path); - char *contents = ohcount_sourcefile_get_contents(sourcefile); - log_it("contents:"); - log_it(contents); - length = contents ? strlen(contents) : 0; - if (write(fd, contents, length) != length) { - fprintf(stderr, "src/detector.c: Could not write temporary file %s.\n", path); - exit(1); - } - close(fd); - tmpfile = 1; - } - - /* Filenames may include single quotes, which must be escaped */ - char escaped_path[strlen(path) * 4 + 1]; - escape_path(escaped_path, path); - - char command[strlen(escaped_path) + 11]; - sprintf(command, "file -b '%s'", escaped_path); - FILE *f = popen(command, "r"); - if (f) { - if (fgets(line, sizeof(line), f) == NULL) { - fprintf(stderr, "src/detector.c: fgets() failed\n"); - exit(1); - } - char *eol = line + strlen(line); - for (p = line; p < eol; p++) *p = tolower(*p); - p = strstr(line, "script text"); - if (p && p == line) { // /^script text(?: executable)? for \w/ - p = strstr(line, "for "); - if (p) { - p += 4; - pe = p; - while (isalnum(*pe)) pe++; - length = pe - p; - strncpy(buf, p, length); - buf[length] = '\0'; - struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); - if (rl) language = rl->name; - } - } else if (p) { // /(\w+)(?: -\w+)* script text/ - do { - p--; - pe = p; - while (*p == ' ') p--; - while (p != line && isalnum(*(p - 1))) p--; - if (p != line && *(p - 1) == '-') p--; - } while (*p == '-'); // Skip over any switches. - length = pe - p; - strncpy(buf, p, length); - buf[length] = '\0'; - struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); - if (rl) language = rl->name; - } else if (strstr(line, "xml")) language = LANG_XML; - pclose(f); - if (tmpfile) { - remove(path); - free(path); - } - } + language = detect_language_magic(sourcefile); } + if (language) { if (ISAMBIGUOUS(language)) { // Call the appropriate function for disambiguation. From 4a4345283b347cd928e45ef4a25ca948995229b3 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Wed, 7 Mar 2012 22:50:47 -0800 Subject: [PATCH 336/387] Removes unused escape_path() function --- src/detector.c | 19 ------------------- test/unit/detector_test.h | 17 ----------------- 2 files changed, 36 deletions(-) diff --git a/src/detector.c b/src/detector.c index 77d19a6..005f6df 100644 --- a/src/detector.c +++ b/src/detector.c @@ -26,25 +26,6 @@ # define mkstemp(p) _open(_mktemp(p), _O_CREAT | _O_SHORT_LIVED | _O_EXCL) #endif -/* Replaces single quotes (') with an escape sequence ('\'') - * suitable for use on the command line. - */ -void escape_path(char *safe, const char *unsafe) { - do { - switch (*unsafe) { - case '\'': - *safe++ = '\''; - *safe++ = '\\'; - *safe++ = '\''; - *safe++ = '\''; - break; - default: - *safe++ = *unsafe; - break; - } - } while (*unsafe++); -} - /* Parse the output of libmagic and return a language, if any. * The contents of string `line` will be destroyed. */ diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index a1fd212..7eda100 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -195,24 +195,7 @@ void test_detector_emacs_mode() { ASSERT_DETECT(LANG_C, "emacs_mode.c"); } -void test_detector_escape_path() { - char escaped[100]; - - escape_path(escaped, ""); - assert(strcmp(escaped, "") == 0); - - escape_path(escaped, "hello.c"); - assert(strcmp(escaped, "hello.c") == 0); - - escape_path(escaped, "'"); - assert(strcmp(escaped, "\'\\\'\'") == 0); - - escape_path(escaped, "Robin's 'Fancy' Filename"); - assert(strcmp(escaped, "Robin\'\\\'\'s \'\\\'\'Fancy\'\\\'\' Filename") == 0); -} - void all_detector_tests() { - test_detector_escape_path(); test_detector_smalltalk(); test_detector_disambiguate_asx(); test_detector_disambiguate_def(); From fb1cc0962643aa7dbb2f87c5ed2308ce9e2cfad5 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Mon, 9 Apr 2012 13:50:12 -0700 Subject: [PATCH 337/387] Fixes recursion bug in disambiguate_in(). The basic strategy of disambiguate_in() is to strip the trailing *.in extension from the filepath, and then to disambiguate the file as if it originally had that name. Thus, given file "foo.in", disambiguate_in() will disambiguate "foo". disambiguate_in() achieves this while re-using the exact same file on disk. This is possible because a SourceFile struct has both a `filepath` (the name we use for disambiguation purposes) and the `diskpath` (the actual name on disk). So disambiguate_in() instantiates a new SourceFile with a stripped filepath, yet the same diskpath and same file contents. The bug is that the code did this incorrectly: when assigning the diskpath of the new SourceFile, it would mistakenly assign it the previous SourceFile's *filepath* instead of the previous SourceFile's diskpath. If disambiguate_in() runs just once (when the file has just a single *.in extension, the usual case), this mistake does not matter because the filepath and diskpath are the same. But if disambiguate_in() recurses on itself (when the file has multiple *.in.in extensions), then during the second pass the filepath and diskpath will not be equal -- they will differ by one missing *.in extension. Thus the diskpath of the new SourceFile will refer to a (probably) non-existent file. The bug is hard to explain but was simple to correct. In addition to correcting the diskpath assignment, I've fixed a memory leak: it was possible to allocate a new SourceFile, and then immediately return NULL, which fails to free the SourceFile. I've moved the allocation *after* the NULL return check to avoid this. --- src/detector.c | 14 +++++++++----- test/detect_files/foo.in.in | 2 ++ test/unit/detector_test.h | 1 + 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 test/detect_files/foo.in.in diff --git a/src/detector.c b/src/detector.c index 005f6df..685b29d 100644 --- a/src/detector.c +++ b/src/detector.c @@ -584,15 +584,19 @@ const char *disambiguate_in(SourceFile *sourcefile) { char buf[length]; strncpy(buf, p, length); buf[length] = '\0'; - SourceFile *undecorated = ohcount_sourcefile_new(buf); p = ohcount_sourcefile_get_contents(sourcefile); if (!p) { return NULL; } - // The filepath without the '.in' extension does not exist on disk. The - // sourcefile->diskpath field must be set incase the detector needs to run - // 'file -b' on the file. - ohcount_sourcefile_set_diskpath(undecorated, sourcefile->filepath); + + // A SourceFile's filepath and diskpath need not be the same. + // Here, we'll take advantage of this to set up a new SourceFile + // whose filepath does not have the *.in extension, but whose + // diskpath still points back to the original file on disk (if any). + SourceFile *undecorated = ohcount_sourcefile_new(buf); + if (sourcefile->diskpath) { + ohcount_sourcefile_set_diskpath(undecorated, sourcefile->diskpath); + } ohcount_sourcefile_set_contents(undecorated, p); undecorated->filenames = sourcefile->filenames; language = ohcount_sourcefile_get_language(undecorated); diff --git a/test/detect_files/foo.in.in b/test/detect_files/foo.in.in new file mode 100644 index 0000000..32f8e97 --- /dev/null +++ b/test/detect_files/foo.in.in @@ -0,0 +1,2 @@ +[Foo] +Foo=Bar diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index 7eda100..3809cf6 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -80,6 +80,7 @@ void test_detector_disambiguate_m() { void test_detector_disambiguate_in() { ASSERT_NODETECT("empty.in"); + ASSERT_NODETECT("foo.in.in"); } void test_detector_disambiguate_pl() { From 8f1c2d42d18eec1011a9d061e48ee99cf6df3db1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Pinson?= Date: Wed, 11 Apr 2012 17:50:39 +0200 Subject: [PATCH 338/387] Add support for the Augeas language (based on Ocaml) --- src/hash/extensions.gperf | 1 + src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 2 + src/languages.h | 1 + src/parsers/augeas.rl | 129 ++++++++++++++++++++++++++++++++++++++++ test/expected_dir/augeas.aug | 14 +++++ test/src_dir/augeas.aug | 14 +++++ test/unit/detector_test.h | 1 + test/unit/parser_test.h | 2 + test/unit/parsers/test_augeas.h | 19 ++++++ 10 files changed, 184 insertions(+) create mode 100644 src/parsers/augeas.rl create mode 100644 test/expected_dir/augeas.aug create mode 100644 test/src_dir/augeas.aug create mode 100644 test/unit/parsers/test_augeas.h diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index ae98136..dad4777 100755 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -20,6 +20,7 @@ asm, LANG_ASSEMBLER aspx, DISAMBIGUATE("aspx") asx, DISAMBIGUATE("asx") au, BINARY +aug, LANG_AUGEAS avi, BINARY awk, LANG_AWK b, DISAMBIGUATE("b") diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index 773cf2b..6f9f09c 100755 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -6,6 +6,7 @@ struct LanguageMap; actionscript, LANG_ACTIONSCRIPT, "ActionScript", 0 ada, LANG_ADA, "Ada", 0 assembler, LANG_ASSEMBLER, "Assembler", 0 +augeas, LANG_AUGEAS, "Augeas", 0 autoconf, LANG_AUTOCONF, "Autoconf", 2 automake, LANG_AUTOMAKE, "Automake", 2 awk, LANG_AWK, "AWK", 0 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index 08c8d6a..9e3e6a1 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -2,6 +2,7 @@ #include "../parsers/actionscript.h" #include "../parsers/ada.h" #include "../parsers/assembler.h" +#include "../parsers/augeas.h" #include "../parsers/autoconf.h" #include "../parsers/automake.h" #include "../parsers/awk.h" @@ -97,6 +98,7 @@ struct ParserMap { const char *key; void (*parser)(char *, int, int, void(*) (co actionscript, parse_actionscript ada, parse_ada assembler, parse_assembler +augeas, parse_augeas autoconf, parse_autoconf automake, parse_automake awk, parse_awk diff --git a/src/languages.h b/src/languages.h index 259ec20..8abd4d3 100755 --- a/src/languages.h +++ b/src/languages.h @@ -9,6 +9,7 @@ #define LANG_ACTIONSCRIPT "actionscript" #define LANG_ADA "ada" #define LANG_ASSEMBLER "assembler" +#define LANG_AUGEAS "augeas" #define LANG_AUTOCONF "autoconf" #define LANG_AUTOMAKE "automake" #define LANG_AWK "awk" diff --git a/src/parsers/augeas.rl b/src/parsers/augeas.rl new file mode 100644 index 0000000..bfc89d1 --- /dev/null +++ b/src/parsers/augeas.rl @@ -0,0 +1,129 @@ +// augeas.rl, based on ocaml.rl +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_AUGEAS_PARSER_H +#define OHCOUNT_AUGEAS_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *AUGEAS_LANG = LANG_AUGEAS; + +// the languages entities +const char *augeas_entities[] = { + "space", "comment", "string", "any" +}; + +// constants associated with the entities +enum { + AUGEAS_SPACE = 0, AUGEAS_COMMENT, AUGEAS_STRING, AUGEAS_ANY +}; + +/*****************************************************************************/ + +%%{ + machine augeas; + write data; + include common "common.rl"; + + # Line counting machine + + action augeas_ccallback { + switch(entity) { + case AUGEAS_SPACE: + ls + break; + case AUGEAS_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(AUGEAS_LANG) + break; + case NEWLINE: + std_newline(AUGEAS_LANG) + } + } + + action augeas_comment_nc_res { nest_count = 0; } + action augeas_comment_nc_inc { nest_count++; } + action augeas_comment_nc_dec { nest_count--; } + + augeas_nested_block_comment = + '(*' >augeas_comment_nc_res @comment ( + newline %{ entity = INTERNAL_NL; } %augeas_ccallback + | + ws + | + '(*' @augeas_comment_nc_inc @comment + | + '*)' @augeas_comment_nc_dec @comment + | + (nonnewline - ws) @comment + )* :>> ('*)' when { nest_count == 0 }) @comment; + + augeas_comment = augeas_nested_block_comment; + augeas_string = '"' @code ([^\r\n\f"\\] | '\\' nonnewline)* '"'; + + + augeas_line := |* + spaces ${ entity = AUGEAS_SPACE; } => augeas_ccallback; + augeas_comment; + augeas_string; + newline ${ entity = NEWLINE; } => augeas_ccallback; + ^space ${ entity = AUGEAS_ANY; } => augeas_ccallback; + *|; + + # Entity machine + + action augeas_ecallback { + callback(AUGEAS_LANG, augeas_entities[entity], cint(ts), cint(te), userdata); + } + + augeas_comment_entity = '(*' >augeas_comment_nc_res ( + '(*' @augeas_comment_nc_inc + | + '*)' @augeas_comment_nc_dec + | + any + )* :>> ('*)' when { nest_count == 0 }); + + augeas_entity := |* + space+ ${ entity = AUGEAS_SPACE; } => augeas_ecallback; + augeas_comment_entity ${ entity = AUGEAS_COMMENT; } => augeas_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with Objective Caml code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_augeas(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + int nest_count = 0; + + %% write init; + cs = (count) ? augeas_en_augeas_line : augeas_en_augeas_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(AUGEAS_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/test/expected_dir/augeas.aug b/test/expected_dir/augeas.aug new file mode 100644 index 0000000..f09e7e0 --- /dev/null +++ b/test/expected_dir/augeas.aug @@ -0,0 +1,14 @@ +augeas comment (** documentation *) +augeas code module Augeas = +augeas code autoload xfm +augeas comment (**/**) +augeas comment (* extra comment *) +augeas blank +augeas comment (* multiline +augeas comment comment*) +augeas code let lns = Shellvars.lns +augeas blank +augeas comment (* recursion in (* a +augeas comment comment *) to complicate things *) +augeas code let filter = incl "/foo/bar" +augeas code let xfm = transform lns filter diff --git a/test/src_dir/augeas.aug b/test/src_dir/augeas.aug new file mode 100644 index 0000000..a4e3b2d --- /dev/null +++ b/test/src_dir/augeas.aug @@ -0,0 +1,14 @@ +(** documentation *) +module Augeas = +autoload xfm +(**/**) +(* extra comment *) + +(* multiline + comment*) +let lns = Shellvars.lns + +(* recursion in (* a + comment *) to complicate things *) +let filter = incl "/foo/bar" +let xfm = transform lns filter diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index a1fd212..82b5e47 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -132,6 +132,7 @@ void test_detector_detect_polyglot() { ASSERT_DETECT(LANG_EXHERES, "foo.exlib"); ASSERT_DETECT(LANG_EIFFEL, "eiffel.e"); ASSERT_DETECT(LANG_OCAML, "ocaml.ml"); + ASSERT_DETECT(LANG_AUGEAS, "augeas.aug"); ASSERT_DETECT(LANG_STRATEGO, "stratego.str"); ASSERT_DETECT(LANG_GLSL, "foo.glsl"); ASSERT_DETECT(LANG_GLSL, "foo_glsl.vert"); diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index bdb7f26..347c0b7 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -76,6 +76,7 @@ void test_parser_verify_entity(SourceFile *sf, const char *entity, #include "parsers/test_actionscript.h" #include "parsers/test_ada.h" #include "parsers/test_assembler.h" +#include "parsers/test_augeas.h" #include "parsers/test_autoconf.h" #include "parsers/test_automake.h" #include "parsers/test_awk.h" @@ -258,6 +259,7 @@ void all_parser_tests() { all_actionscript_tests(); all_ada_tests(); all_assembler_tests(); + all_augeas_tests(); all_autoconf_tests(); all_automake_tests(); all_awk_tests(); diff --git a/test/unit/parsers/test_augeas.h b/test/unit/parsers/test_augeas.h new file mode 100644 index 0000000..2e2e60a --- /dev/null +++ b/test/unit/parsers/test_augeas.h @@ -0,0 +1,19 @@ + +void test_augeas_comments() { + test_parser_verify_parse( + test_parser_sourcefile("augeas", " (* comment *)"), + "augeas", "", "(* comment *)", 0 + ); +} + +void test_augeas_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("augeas", " (*comment*)"), + "comment", "(*comment*)" + ); +} + +void all_augeas_tests() { + test_augeas_comments(); + test_augeas_comment_entities(); +} From ddb48288e2ee6928d54b7adbf31bbc742a397fe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Pinson?= Date: Wed, 11 Apr 2012 23:46:16 +0200 Subject: [PATCH 339/387] Add dtx and sty for LANG_TEX --- src/hash/extensions.gperf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index ae98136..eee70e3 100755 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -52,6 +52,7 @@ dat, BINARY def, DISAMBIGUATE("def") di, LANG_DMD doc, BINARY +dtx, LANG_TEX dylan, LANG_DYLAN e, LANG_EIFFEL ebuild, LANG_EBUILD @@ -186,6 +187,7 @@ sql, LANG_SQL ss, LANG_SCHEME st, DISAMBIGUATE("st") str, LANG_STRATEGO +sty, LANG_TEX svg, BINARY svgz, BINARY svn, BINARY From 3b4f7766f5ef6ca58da70ac8932628221b8dcdc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Pinson?= Date: Thu, 12 Apr 2012 00:02:56 +0200 Subject: [PATCH 340/387] Make DTX a separate language derived from TeX. --- src/hash/extensions.gperf | 2 +- src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 2 + src/languages.h | 1 + src/parsers/tex_dtx.rl | 103 ++++++++++++++++++++++++++++++++++++++++++++++ test/detect_files/foo.dtx | 9 ++++ test/expected_dir/foo.dtx | 9 ++++ test/src_dir/foo.dtx | 9 ++++ test/unit/detector_test.h | 1 + 9 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 src/parsers/tex_dtx.rl create mode 100644 test/detect_files/foo.dtx create mode 100644 test/expected_dir/foo.dtx create mode 100644 test/src_dir/foo.dtx diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index eee70e3..a91e2d8 100755 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -52,7 +52,7 @@ dat, BINARY def, DISAMBIGUATE("def") di, LANG_DMD doc, BINARY -dtx, LANG_TEX +dtx, LANG_TEX_DTX dylan, LANG_DYLAN e, LANG_EIFFEL ebuild, LANG_EBUILD diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index 773cf2b..c70ebc0 100755 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -30,6 +30,7 @@ css, LANG_CSS, "CSS", 1 cuda, LANG_CUDA, "CUDA", 0 dcl, LANG_DCL, "DCL", 0 dmd, LANG_DMD, "D", 0 +dtx, LANG_TEX_DTX, "DTX for TeX/LaTeX", 1 dylan, LANG_DYLAN, "Dylan", 0 ebuild, LANG_EBUILD, "Ebuild", 0 ec, LANG_EC, "eC", 0 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index 08c8d6a..1c621a5 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -83,6 +83,7 @@ #include "../parsers/sql.h" #include "../parsers/tcl.h" #include "../parsers/tex.h" +#include "../parsers/tex_dtx.h" #include "../parsers/vb_aspx.h" #include "../parsers/vhdl.h" #include "../parsers/vim.h" @@ -187,6 +188,7 @@ structured_basic, parse_structured_basic sql, parse_sql tcl, parse_tcl tex, parse_tex +tex_dtx, parse_tex_dtx vala, parse_vala vb_aspx, parse_vb_aspx vhdl, parse_vhdl diff --git a/src/languages.h b/src/languages.h index 259ec20..9a18426 100755 --- a/src/languages.h +++ b/src/languages.h @@ -99,6 +99,7 @@ #define LANG_SQL "sql" #define LANG_TCL "tcl" #define LANG_TEX "tex" +#define LANG_TEX_DTX "tex_dtx" #define LANG_VALA "vala" #define LANG_VB_ASPX "vb_aspx" #define LANG_VHDL "vhdl" diff --git a/src/parsers/tex_dtx.rl b/src/parsers/tex_dtx.rl new file mode 100644 index 0000000..f0b562d --- /dev/null +++ b/src/parsers/tex_dtx.rl @@ -0,0 +1,103 @@ +// tex_dtx.rl written by Raphael Pinson, +// based on tex.rl by Mitchell Foral. mitchellcaladbolgnet. + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_TEX_DTX_PARSER_H +#define OHCOUNT_TEX_DTX_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *TEX_DTX_LANG = LANG_TEX_DTX; + +// the languages entities +const char *tex_dtx_entities[] = { + "space", "comment", "string", "any" +}; + +// constants associated with the entities +enum { + TEX_DTX_SPACE = 0, TEX_DTX_COMMENT, TEX_DTX_STRING, TEX_DTX_ANY +}; + +/*****************************************************************************/ + +%%{ + machine tex_dtx; + write data; + include common "common.rl"; + + # Line counting machine + + action tex_dtx_ccallback { + switch(entity) { + case TEX_DTX_SPACE: + ls + break; + case TEX_DTX_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(TEX_DTX_LANG) + break; + case NEWLINE: + std_newline(TEX_DTX_LANG) + } + } + + tex_dtx_comment = '%%' @comment nonnewline*; + + tex_dtx_line := |* + spaces ${ entity = TEX_DTX_SPACE; } => tex_dtx_ccallback; + tex_dtx_comment; + newline ${ entity = NEWLINE; } => tex_dtx_ccallback; + ^space ${ entity = TEX_DTX_ANY; } => tex_dtx_ccallback; + *|; + + # Entity machine + + action tex_dtx_ecallback { + callback(TEX_DTX_LANG, tex_dtx_entities[entity], cint(ts), cint(te), userdata); + } + + tex_dtx_comment_entity = '%%' nonnewline*; + + tex_dtx_entity := |* + space+ ${ entity = TEX_DTX_SPACE; } => tex_dtx_ecallback; + tex_dtx_comment_entity ${ entity = TEX_DTX_COMMENT; } => tex_dtx_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with Tex markup. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_tex_dtx(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + %% write init; + cs = (count) ? tex_dtx_en_tex_dtx_line : tex_dtx_en_tex_dtx_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(TEX_DTX_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/test/detect_files/foo.dtx b/test/detect_files/foo.dtx new file mode 100644 index 0000000..d8cb14d --- /dev/null +++ b/test/detect_files/foo.dtx @@ -0,0 +1,9 @@ +\begin{document} +\texbf Hello world + + +% \acommand +% \anothercommand +%% sample comment + +\end{document} diff --git a/test/expected_dir/foo.dtx b/test/expected_dir/foo.dtx new file mode 100644 index 0000000..1275756 --- /dev/null +++ b/test/expected_dir/foo.dtx @@ -0,0 +1,9 @@ +tex_dtx code \begin{document} +tex_dtx code \texbf Hello world +tex_dtx blank +tex_dtx blank +tex_dtx code % \acommand +tex_dtx code % \anothercommand +tex_dtx comment %% sample comment +tex_dtx blank +tex_dtx code \end{document} diff --git a/test/src_dir/foo.dtx b/test/src_dir/foo.dtx new file mode 100644 index 0000000..d8cb14d --- /dev/null +++ b/test/src_dir/foo.dtx @@ -0,0 +1,9 @@ +\begin{document} +\texbf Hello world + + +% \acommand +% \anothercommand +%% sample comment + +\end{document} diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index a1fd212..d13cb11 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -118,6 +118,7 @@ void test_detector_detect_polyglot() { ASSERT_DETECT(LANG_PHP, "upper_case_php"); ASSERT_DETECT(LANG_SMALLTALK, "example.st"); ASSERT_DETECT(LANG_VALA, "foo.vala"); + ASSERT_DETECT(LANG_TEX_DTX, "foo.dtx"); ASSERT_DETECT(LANG_TEX, "foo.tex"); ASSERT_DETECT(LANG_XSLT, "example.xsl"); ASSERT_DETECT(LANG_LOGTALK, "foo.lgt"); From e46b9ad7fccb570bac2d50c541ca190614c95225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Pinson?= Date: Thu, 12 Apr 2012 10:33:17 +0200 Subject: [PATCH 341/387] Add .cls to LANG_TEX --- src/hash/extensions.gperf | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index a91e2d8..aafc4b4 100755 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -37,6 +37,7 @@ cache, BINARY cc, LANG_CPP chai, LANG_CHAISCRIPT clj, LANG_CLOJURE +cls, LANG_TEX cmake, LANG_CMAKE coffee, LANG_COFFEESCRIPT com, LANG_DCL From bfc0e493e8b246520fcadced5bfaee6fdb1aa9c9 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Tue, 24 Apr 2012 16:16:13 +0200 Subject: [PATCH 342/387] Add support for Coq .v files (based on the OCaml parser). --- src/hash/extensions.gperf | 1 + src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 2 + src/languages.h | 1 + src/parsers/coq.rl | 135 +++++++++++++++++++++++++++++++++++++++++++ test/detect_files/coq.v | 10 ++++ test/expected_dir/coq.v | 10 ++++ test/src_dir/coq.v | 10 ++++ test/unit/detector_test.h | 1 + test/unit/parser_test.h | 2 + test/unit/parsers/test_coq.h | 19 ++++++ 11 files changed, 192 insertions(+) create mode 100644 src/parsers/coq.rl create mode 100644 test/detect_files/coq.v create mode 100644 test/expected_dir/coq.v create mode 100644 test/src_dir/coq.v create mode 100644 test/unit/parsers/test_coq.h diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index fcae35e..f8da0c6 100755 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -203,6 +203,7 @@ tif, BINARY tiff, BINARY tpl, LANG_HTML vala, LANG_VALA +v, LANG_COQ vb, LANG_VISUALBASIC vba, LANG_VISUALBASIC vbs, LANG_VISUALBASIC diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index 20c3d75..c47d212 100755 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -24,6 +24,7 @@ clearsilver_template, LANG_CLEARSILVER_TEMPLATE, "ClearSilver", 0 clojure, LANG_CLOJURE, "Clojure", 0 cmake, LANG_CMAKE, "Cmake script", 2 coffescript, LANG_COFFEESCRIPT, "CoffeeScript", 0 +coq, LANG_COQ, "Coq", 0 cpp, LANG_CPP, "C++", 0 cs_aspx, LANG_CS_ASPX, "", 0 csharp, LANG_CSHARP, "C#", 0 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index 19ae557..6672b4b 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -18,6 +18,7 @@ #include "../parsers/clearsilverhtml.h" #include "../parsers/coffeescript.h" #include "../parsers/cmake.h" +#include "../parsers/coq.h" #include "../parsers/cs_aspx.h" #include "../parsers/css.h" #include "../parsers/d.h" @@ -116,6 +117,7 @@ clearsilver, parse_clearsilver clearsilver_template, parse_cshtml clojure, parse_clojure coffeescript, parse_coffeescript +coq, parse_coq cpp, parse_cpp cs_aspx, parse_cs_aspx csharp, parse_csharp diff --git a/src/languages.h b/src/languages.h index 3e083de..fe0fd9e 100755 --- a/src/languages.h +++ b/src/languages.h @@ -26,6 +26,7 @@ #define LANG_CLOJURE "clojure" #define LANG_CMAKE "cmake" #define LANG_COFFEESCRIPT "coffeescript" +#define LANG_COQ "coq" #define LANG_CPP "cpp" #define LANG_CS_ASPX "cs_aspx" #define LANG_CSHARP "csharp" diff --git a/src/parsers/coq.rl b/src/parsers/coq.rl new file mode 100644 index 0000000..eaa3330 --- /dev/null +++ b/src/parsers/coq.rl @@ -0,0 +1,135 @@ +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_COQ_PARSER_H +#define OHCOUNT_COQ_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *COQ_LANG = LANG_COQ; + +// the languages entities +const char *coq_entities[] = { + "space", "comment", "string", "any" +}; + +// constants associated with the entities +enum { + COQ_SPACE = 0, COQ_COMMENT, COQ_STRING, COQ_ANY +}; + +/*****************************************************************************/ + +%%{ + machine coq; + write data; + include common "common.rl"; + + # Line counting machine + + action coq_ccallback { + switch(entity) { + case COQ_SPACE: + ls + break; + case COQ_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(COQ_LANG) + break; + case NEWLINE: + std_newline(COQ_LANG) + } + } + + action coq_comment_nc_res { nest_count = 0; } + action coq_comment_nc_inc { nest_count++; } + action coq_comment_nc_dec { nest_count--; } + + coq_nested_block_comment = + '(*' >coq_comment_nc_res @comment ( + newline %{ entity = INTERNAL_NL; } %coq_ccallback + | + ws + | + '(*' @coq_comment_nc_inc @comment + | + '*)' @coq_comment_nc_dec @comment + | + (nonnewline - ws) @comment + )* :>> ('*)' when { nest_count == 0 }) @comment; + + coq_comment = coq_nested_block_comment; + + coq_string = + '"' @code ( + newline %{ entity = INTERNAL_NL; } %coq_ccallback + | + ws + | + [^"] @code + )* '"'; + + coq_line := |* + spaces ${ entity = COQ_SPACE; } => coq_ccallback; + coq_comment; + coq_string; + newline ${ entity = NEWLINE; } => coq_ccallback; + ^space ${ entity = COQ_ANY; } => coq_ccallback; + *|; + + # Entity machine + + action coq_ecallback { + callback(COQ_LANG, coq_entities[entity], cint(ts), cint(te), userdata); + } + + coq_comment_entity = '(*' >coq_comment_nc_res ( + '(*' @coq_comment_nc_inc + | + '*)' @coq_comment_nc_dec + | + any + )* :>> ('*)' when { nest_count == 0 }); + + coq_entity := |* + space+ ${ entity = COQ_SPACE; } => coq_ecallback; + coq_comment_entity ${ entity = COQ_COMMENT; } => coq_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with Coq code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_coq(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + int nest_count = 0; + + %% write init; + cs = (count) ? coq_en_coq_line : coq_en_coq_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(COQ_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/test/detect_files/coq.v b/test/detect_files/coq.v new file mode 100644 index 0000000..37ae74c --- /dev/null +++ b/test/detect_files/coq.v @@ -0,0 +1,10 @@ +Require Import String. +(* comment *) +Check "multiline +string"%string. + +(* multiline + comment *) + +(* recursion in (* a + comment *) to complicate things *) diff --git a/test/expected_dir/coq.v b/test/expected_dir/coq.v new file mode 100644 index 0000000..d7daa1d --- /dev/null +++ b/test/expected_dir/coq.v @@ -0,0 +1,10 @@ +coq code Require Import String. +coq comment (* comment *) +coq code Check "multiline +coq code string"%string. +coq blank +coq comment (* multiline +coq comment comment *) +coq blank +coq comment (* recursion in (* a +coq comment comment *) to complicate things *) diff --git a/test/src_dir/coq.v b/test/src_dir/coq.v new file mode 100644 index 0000000..37ae74c --- /dev/null +++ b/test/src_dir/coq.v @@ -0,0 +1,10 @@ +Require Import String. +(* comment *) +Check "multiline +string"%string. + +(* multiline + comment *) + +(* recursion in (* a + comment *) to complicate things *) diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index b6484f8..3b75baf 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -150,6 +150,7 @@ void test_detector_detect_polyglot() { ASSERT_DETECT(LANG_NSIS, "foo.nsh"); ASSERT_DETECT(LANG_COFFEESCRIPT, "foo.coffee"); ASSERT_DETECT(LANG_QML, "foo.qml"); + ASSERT_DETECT(LANG_COQ, "coq.v"); ASSERT_NODETECT("empty.inc"); } diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index 347c0b7..b4009c1 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -91,6 +91,7 @@ void test_parser_verify_entity(SourceFile *sf, const char *entity, #include "parsers/test_clearsilvertemplate.h" #include "parsers/test_clearsilver.h" #include "parsers/test_clojure.h" +#include "parsers/test_coq.h" #include "parsers/test_cs_aspx.h" #include "parsers/test_csharp.h" #include "parsers/test_css.h" @@ -274,6 +275,7 @@ void all_parser_tests() { all_clearsilver_template_tests(); all_clearsilver_tests(); all_clojure_tests(); + all_coq_tests(); all_cs_aspx_tests(); all_csharp_tests(); all_css_tests(); diff --git a/test/unit/parsers/test_coq.h b/test/unit/parsers/test_coq.h new file mode 100644 index 0000000..d3f97c7 --- /dev/null +++ b/test/unit/parsers/test_coq.h @@ -0,0 +1,19 @@ + +void test_coq_comments() { + test_parser_verify_parse( + test_parser_sourcefile("coq", " (* comment *)"), + "coq", "", "(* comment *)", 0 + ); +} + +void test_coq_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("coq", " (*comment*)"), + "comment", "(*comment*)" + ); +} + +void all_coq_tests() { + test_coq_comments(); + test_coq_comment_entities(); +} From 3057017b068af28c33111b50e612229ee3c2bc94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Pinson?= Date: Fri, 25 May 2012 16:32:56 +0200 Subject: [PATCH 343/387] Puppet parser: detect classes and defines with colons --- src/detector.c | 2 +- test/expected_dir/puppet1.pp | 4 ++-- test/src_dir/puppet1.pp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/detector.c b/src/detector.c index 685b29d..e67521b 100644 --- a/src/detector.c +++ b/src/detector.c @@ -783,7 +783,7 @@ const char *disambiguate_pp(SourceFile *sourcefile) { pcre *re; const char *error; int erroffset; - re = pcre_compile("(define\\s+\\w+\\s*\\(|class \\s+\\w+\\s*{)", 0, &error, &erroffset, NULL); + re = pcre_compile("(define\\s+[\\w:]+\\s*\\(|class \\s+[\\w:]+\\s*{)", 0, &error, &erroffset, NULL); for (; p < eof; p++) { if (strncmp(p, "$include", 8) == 0 || diff --git a/test/expected_dir/puppet1.pp b/test/expected_dir/puppet1.pp index e5e6c89..cbb3d94 100644 --- a/test/expected_dir/puppet1.pp +++ b/test/expected_dir/puppet1.pp @@ -1,6 +1,6 @@ -puppet code class bob_openldap { +puppet code class bob::open_ldap { puppet blank -puppet code define server ( +puppet code define foo::server ( puppet code $argsfile = undef, puppet code $bdb_cachesize = '', puppet code $bdb_checkpoint = '', diff --git a/test/src_dir/puppet1.pp b/test/src_dir/puppet1.pp index f30389d..dea2fd8 100644 --- a/test/src_dir/puppet1.pp +++ b/test/src_dir/puppet1.pp @@ -1,6 +1,6 @@ -class bob_openldap { +class bob::open_ldap { - define server ( + define foo::server ( $argsfile = undef, $bdb_cachesize = '', $bdb_checkpoint = '', From f02286ea7e3ace0465258dfe00b88c8465a387a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Pinson?= Date: Fri, 25 May 2012 18:13:23 +0200 Subject: [PATCH 344/387] Avoid detecting Pascal code as Puppet --- src/detector.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/detector.c b/src/detector.c index e67521b..2c47db5 100644 --- a/src/detector.c +++ b/src/detector.c @@ -783,7 +783,8 @@ const char *disambiguate_pp(SourceFile *sourcefile) { pcre *re; const char *error; int erroffset; - re = pcre_compile("(define\\s+[\\w:]+\\s*\\(|class \\s+[\\w:]+\\s*{)", 0, &error, &erroffset, NULL); + re = pcre_compile("^\\s*(define\\s+[\\w:]+\\s*\\(|class \\s+[\\w:]+\\s*{)", + PCRE_MULTILINE, &error, &erroffset, NULL); for (; p < eof; p++) { if (strncmp(p, "$include", 8) == 0 || @@ -793,18 +794,13 @@ const char *disambiguate_pp(SourceFile *sourcefile) { if (strncmp(p, "enable =>", 9) == 0 || strncmp(p, "ensure =>", 9) == 0 || strncmp(p, "content =>", 10) == 0 || - strncmp(p, "source =>", 9) == 0 || - strncmp(p, "include ", 8) == 0) + strncmp(p, "source =>", 9) == 0) { return LANG_PUPPET; + } /* regexp for checking for define and class declarations */ - - int rc; - int ovector[30]; - rc = pcre_exec(re, NULL, p, mystrnlen(p, 100), 0, 0, ovector, 30); - if(rc > 0) { + if (pcre_exec(re, NULL, p, mystrnlen(p, 100), 0, 0, NULL, 0) > -1) return LANG_PUPPET; - } } return LANG_PASCAL; From 17dca289babe7a81bace895ac9a2faf0690db334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Pinson?= Date: Fri, 25 May 2012 18:30:14 +0200 Subject: [PATCH 345/387] Recognize Puppet node definitions --- src/detector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detector.c b/src/detector.c index 2c47db5..e4b8192 100644 --- a/src/detector.c +++ b/src/detector.c @@ -783,7 +783,7 @@ const char *disambiguate_pp(SourceFile *sourcefile) { pcre *re; const char *error; int erroffset; - re = pcre_compile("^\\s*(define\\s+[\\w:]+\\s*\\(|class \\s+[\\w:]+\\s*{)", + re = pcre_compile("^\\s*(define\\s+[\\w:-]+\\s*\\(|class\\s+[\\w:-]+(\\s+inherits\\s+[\\w:-]+)?\\s*{|node\\s+\\'[\\w:\\.-]+\\'\\s*{)", PCRE_MULTILINE, &error, &erroffset, NULL); for (; p < eof; p++) { From 34a4e73278808ee3ab46679a4a1f80035f0409ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Pinson?= Date: Sat, 26 May 2012 13:07:36 +0200 Subject: [PATCH 346/387] Puppet parser: improve regex matching for caret to work --- src/detector.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/detector.c b/src/detector.c index e4b8192..1c0185c 100644 --- a/src/detector.c +++ b/src/detector.c @@ -778,6 +778,7 @@ size_t mystrnlen(const char *begin, size_t maxlen) { const char *disambiguate_pp(SourceFile *sourcefile) { char *p = ohcount_sourcefile_get_contents(sourcefile); char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); + char *q; /* prepare regular expressions */ pcre *re; @@ -786,23 +787,23 @@ const char *disambiguate_pp(SourceFile *sourcefile) { re = pcre_compile("^\\s*(define\\s+[\\w:-]+\\s*\\(|class\\s+[\\w:-]+(\\s+inherits\\s+[\\w:-]+)?\\s*{|node\\s+\\'[\\w:\\.-]+\\'\\s*{)", PCRE_MULTILINE, &error, &erroffset, NULL); - for (; p < eof; p++) { - if (strncmp(p, "$include", 8) == 0 || - strncmp(p, "$INCLUDE", 8) == 0 || - strncmp(p, "end.", 4) == 0) + for (q = p; q < eof; q++) { + if (strncmp(q, "$include", 8) == 0 || + strncmp(q, "$INCLUDE", 8) == 0 || + strncmp(q, "end.", 4) == 0) return LANG_PASCAL; - if (strncmp(p, "enable =>", 9) == 0 || - strncmp(p, "ensure =>", 9) == 0 || - strncmp(p, "content =>", 10) == 0 || - strncmp(p, "source =>", 9) == 0) { + if (strncmp(q, "enable =>", 9) == 0 || + strncmp(q, "ensure =>", 9) == 0 || + strncmp(q, "content =>", 10) == 0 || + strncmp(q, "source =>", 9) == 0) { return LANG_PUPPET; } + } - /* regexp for checking for define and class declarations */ - if (pcre_exec(re, NULL, p, mystrnlen(p, 100), 0, 0, NULL, 0) > -1) - return LANG_PUPPET; + /* regexp for checking for define and class declarations */ + if (pcre_exec(re, NULL, p, mystrnlen(p, 10000), 0, 0, NULL, 0) > -1) + return LANG_PUPPET; - } return LANG_PASCAL; } From 5151d7fff3d7c9b325f6e8af418a7ee68d7a9244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Pinson?= Date: Sat, 26 May 2012 19:51:23 +0200 Subject: [PATCH 347/387] Puppet/Pascal: try harder to find Puppet keywords --- src/detector.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/detector.c b/src/detector.c index 1c0185c..5ee71ef 100644 --- a/src/detector.c +++ b/src/detector.c @@ -780,28 +780,38 @@ const char *disambiguate_pp(SourceFile *sourcefile) { char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); char *q; - /* prepare regular expressions */ - pcre *re; - const char *error; - int erroffset; - re = pcre_compile("^\\s*(define\\s+[\\w:-]+\\s*\\(|class\\s+[\\w:-]+(\\s+inherits\\s+[\\w:-]+)?\\s*{|node\\s+\\'[\\w:\\.-]+\\'\\s*{)", - PCRE_MULTILINE, &error, &erroffset, NULL); - for (q = p; q < eof; q++) { if (strncmp(q, "$include", 8) == 0 || - strncmp(q, "$INCLUDE", 8) == 0 || - strncmp(q, "end.", 4) == 0) + strncmp(q, "$INCLUDE", 8) == 0) return LANG_PASCAL; if (strncmp(q, "enable =>", 9) == 0 || strncmp(q, "ensure =>", 9) == 0 || strncmp(q, "content =>", 10) == 0 || + strncmp(q, "notify =>", 9) == 0 || + strncmp(q, "require =>", 10) == 0 || strncmp(q, "source =>", 9) == 0) { return LANG_PUPPET; } } - /* regexp for checking for define and class declarations */ - if (pcre_exec(re, NULL, p, mystrnlen(p, 10000), 0, 0, NULL, 0) > -1) + /* prepare regular expressions */ + const char *error; + int erroffset; + + /* try harder with optional spaces */ + pcre *keyword; + keyword = pcre_compile("^\\s*(ensure|content|notify|require|source)\\s+=>", + PCRE_MULTILINE, &error, &erroffset, NULL); + + if (pcre_exec(keyword, NULL, p, mystrnlen(p, 10000), 0, 0, NULL, 0) > -1) + return LANG_PUPPET; + + /* check for standard puppet constructs */ + pcre *construct; + construct = pcre_compile("^\\s*(define\\s+[\\w:-]+\\s*\\(|class\\s+[\\w:-]+(\\s+inherits\\s+[\\w:-]+)?\\s*{|node\\s+\\'?[\\w:\\.-]+\\'?\\s*{)", + PCRE_MULTILINE, &error, &erroffset, NULL); + + if (pcre_exec(construct, NULL, p, mystrnlen(p, 10000), 0, 0, NULL, 0) > -1) return LANG_PUPPET; return LANG_PASCAL; From cc968230f7aedbe88f055ef325a0fddf535b8132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Pinson?= Date: Sat, 26 May 2012 20:26:45 +0200 Subject: [PATCH 348/387] Puppet/Pascal: strncmp calls are really not helping, functionaly or timewise --- src/detector.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/detector.c b/src/detector.c index 5ee71ef..9e8045d 100644 --- a/src/detector.c +++ b/src/detector.c @@ -777,22 +777,6 @@ size_t mystrnlen(const char *begin, size_t maxlen) { const char *disambiguate_pp(SourceFile *sourcefile) { char *p = ohcount_sourcefile_get_contents(sourcefile); - char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); - char *q; - - for (q = p; q < eof; q++) { - if (strncmp(q, "$include", 8) == 0 || - strncmp(q, "$INCLUDE", 8) == 0) - return LANG_PASCAL; - if (strncmp(q, "enable =>", 9) == 0 || - strncmp(q, "ensure =>", 9) == 0 || - strncmp(q, "content =>", 10) == 0 || - strncmp(q, "notify =>", 9) == 0 || - strncmp(q, "require =>", 10) == 0 || - strncmp(q, "source =>", 9) == 0) { - return LANG_PUPPET; - } - } /* prepare regular expressions */ const char *error; From 22ee05c90be3b2449043451cfbdbbb05c207f4c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Pinson?= Date: Sat, 2 Jun 2012 00:02:42 +0200 Subject: [PATCH 349/387] Prevent segfault on empty files --- src/detector.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/detector.c b/src/detector.c index 9e8045d..d5184dc 100644 --- a/src/detector.c +++ b/src/detector.c @@ -771,6 +771,8 @@ const char *disambiguate_m(SourceFile *sourcefile) { // strnlen is not available on OS X, so we roll our own size_t mystrnlen(const char *begin, size_t maxlen) { + if (begin == NULL) + return 0; const char *end = memchr(begin, '\0', maxlen); return end ? (end - begin) : maxlen; } From 6d77bd49a20c199625b136883ccc4f39922eabc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Pinson?= Date: Sat, 2 Jun 2012 07:59:45 +0200 Subject: [PATCH 350/387] Return NULL when NULL is passed to disambiguate_pp --- src/detector.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/detector.c b/src/detector.c index d5184dc..8d5231e 100644 --- a/src/detector.c +++ b/src/detector.c @@ -780,6 +780,9 @@ size_t mystrnlen(const char *begin, size_t maxlen) { const char *disambiguate_pp(SourceFile *sourcefile) { char *p = ohcount_sourcefile_get_contents(sourcefile); + if (!p) + return NULL; + /* prepare regular expressions */ const char *error; int erroffset; From 45c0c9ebcbe417a8eede5fb31a6f59e7ad81399a Mon Sep 17 00:00:00 2001 From: Arc Riley Date: Mon, 13 Aug 2012 13:27:42 -0400 Subject: [PATCH 351/387] Added support for Genie and Vala .vapi files --- src/hash/extensions.gperf | 2 ++ src/hash/languages.gperf | 1 + src/languages.h | 1 + src/parsers/c.rl | 11 +++++++++++ 4 files changed, 15 insertions(+) diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index fcae35e..ddae57d 100755 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -85,6 +85,7 @@ gif, BINARY glsl, LANG_GLSL go, LANG_GOLANG groovy, LANG_GROOVY +gs, LANG_GENIE gz, BINARY h, DISAMBIGUATE("h") h++, LANG_CPP @@ -203,6 +204,7 @@ tif, BINARY tiff, BINARY tpl, LANG_HTML vala, LANG_VALA +vapi, LANG_VALA vb, LANG_VISUALBASIC vba, LANG_VISUALBASIC vbs, LANG_VISUALBASIC diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index 20c3d75..772f19f 100755 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -44,6 +44,7 @@ forth, LANG_FORTH, "Forth", 0 fortranfixed, LANG_FORTRANFIXED, "Fortan (Fixed-format)", 0 fortranfree, LANG_FORTRANFREE, "Fortan (Free-format)", 0 fsharp, LANG_FSHARP, "F#", 0 +genie, LANG_GENIE, "Genie", 0 glsl, LANG_GLSL, "OpenGL Shading Language", 0 golang, LANG_GOLANG, "Golang", 0 groovy, LANG_GROOVY, "Groovy", 0 diff --git a/src/languages.h b/src/languages.h index 3e083de..0632837 100755 --- a/src/languages.h +++ b/src/languages.h @@ -45,6 +45,7 @@ #define LANG_FORTRANFIXED "fortranfixed" #define LANG_FORTRANFREE "fortranfree" #define LANG_FSHARP "fsharp" +#define LANG_GENIE "genie" #define LANG_GLSL "glsl" #define LANG_GOLANG "golang" #define LANG_GROOVY "groovy" diff --git a/src/parsers/c.rl b/src/parsers/c.rl index fceba51..0ba4008 100755 --- a/src/parsers/c.rl +++ b/src/parsers/c.rl @@ -211,6 +211,17 @@ void parse_vala(char *buffer, int length, int count, C_LANG = ORIG_C_LANG; } +const char *GENIE_LANG = LANG_GENIE; +void parse_genie(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, + int s, int e, void *udata), + void *userdata + ) { + C_LANG = GENIE_LANG; + parse_c(buffer, length, count, callback, userdata); + C_LANG = ORIG_C_LANG; +} + const char *CUDA_LANG = LANG_CUDA; void parse_cuda(char *buffer, int length, int count, void (*callback) (const char *lang, const char *entity, int s, From 052d6c67e41481fcac16cae2d771f24b01d245d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Pinson?= Date: Sat, 2 Jun 2012 00:02:42 +0200 Subject: [PATCH 352/387] Prevent segfault on empty files --- src/detector.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/detector.c b/src/detector.c index 9e8045d..d5184dc 100644 --- a/src/detector.c +++ b/src/detector.c @@ -771,6 +771,8 @@ const char *disambiguate_m(SourceFile *sourcefile) { // strnlen is not available on OS X, so we roll our own size_t mystrnlen(const char *begin, size_t maxlen) { + if (begin == NULL) + return 0; const char *end = memchr(begin, '\0', maxlen); return end ? (end - begin) : maxlen; } From f1eb7c917cd4215cf7801bba77a799c9d8f5a39e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Pinson?= Date: Sat, 2 Jun 2012 07:59:45 +0200 Subject: [PATCH 353/387] Return NULL when NULL is passed to disambiguate_pp --- src/detector.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/detector.c b/src/detector.c index d5184dc..8d5231e 100644 --- a/src/detector.c +++ b/src/detector.c @@ -780,6 +780,9 @@ size_t mystrnlen(const char *begin, size_t maxlen) { const char *disambiguate_pp(SourceFile *sourcefile) { char *p = ohcount_sourcefile_get_contents(sourcefile); + if (!p) + return NULL; + /* prepare regular expressions */ const char *error; int erroffset; From 9504723987a208495068ccc23e12ce12f66ebdf2 Mon Sep 17 00:00:00 2001 From: Abhay Mujumdar Date: Wed, 12 Dec 2012 16:56:50 -0500 Subject: [PATCH 354/387] Merges pull/21, adds a test --- test/unit/detector_test.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index b6484f8..37d6ca0 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -198,6 +198,10 @@ void test_detector_emacs_mode() { ASSERT_DETECT(LANG_C, "emacs_mode.c"); } +void test_non_existent_file(){ + ASSERT_NODETECT("xxx_non_exists_xxxi.pp"); +} + void all_detector_tests() { test_detector_smalltalk(); test_detector_disambiguate_asx(); @@ -216,4 +220,5 @@ void all_detector_tests() { test_detector_xml_with_custom_extension(); test_detector_brainfuck(); test_detector_emacs_mode(); + test_non_existent_file(); } From bdfa6dc6ce34cc40c3306df5fd44e5464da4f1a0 Mon Sep 17 00:00:00 2001 From: "Daniel C. Sobral" Date: Thu, 15 Mar 2012 22:25:09 -0300 Subject: [PATCH 355/387] Detect file import on pp disambiguation It's a convention used by some Puppet modules to have nothing on "init.pp" except imports of class and definition files. Though some Pascal versions seems to use import as well, Puppet's import are followed by glob patterns inside double quotes, while Pascal's import are followed by identifiers. Use imports followed by double quotes to detect these files as Puppet files. --- src/detector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detector.c b/src/detector.c index 8d5231e..a3e8602 100644 --- a/src/detector.c +++ b/src/detector.c @@ -797,7 +797,7 @@ const char *disambiguate_pp(SourceFile *sourcefile) { /* check for standard puppet constructs */ pcre *construct; - construct = pcre_compile("^\\s*(define\\s+[\\w:-]+\\s*\\(|class\\s+[\\w:-]+(\\s+inherits\\s+[\\w:-]+)?\\s*{|node\\s+\\'?[\\w:\\.-]+\\'?\\s*{)", + construct = pcre_compile("^\\s*(define\\s+[\\w:-]+\\s*\\(|class\\s+[\\w:-]+(\\s+inherits\\s+[\\w:-]+)?\\s*{|node\\s+\\'?[\\w:\\.-]+\\'?\\s*{|import\\s+\")", PCRE_MULTILINE, &error, &erroffset, NULL); if (pcre_exec(construct, NULL, p, mystrnlen(p, 10000), 0, 0, NULL, 0) > -1) From cf1533774e099c72675cd880dced286ef2df7e26 Mon Sep 17 00:00:00 2001 From: Abhay Mujumdar Date: Thu, 13 Dec 2012 15:44:27 -0500 Subject: [PATCH 356/387] Adds tests and test files from dcsobral --- test/unit/detector_test.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index a5ca3ca..fa17ee3 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -199,6 +199,13 @@ void test_detector_emacs_mode() { ASSERT_DETECT(LANG_C, "emacs_mode.c"); } +void test_assert_puppet(){ + ASSERT_DETECT(LANG_PUPPET, "puppet_import.pp") + ASSERT_DETECT(LANG_PUPPET, "puppet_import_annotated.pp") + ASSERT_DETECT(LANG_PUPPET, "puppet_test.pp") + ASSERT_DETECT(LANG_PUPPET, "puppet_test_annotated.pp") +} + void test_non_existent_file(){ ASSERT_NODETECT("xxx_non_exists_xxxi.pp"); } From 024e645f1877044d0339e537fbb4b0a8621a4f0a Mon Sep 17 00:00:00 2001 From: Abhay Mujumdar Date: Thu, 13 Dec 2012 15:45:23 -0500 Subject: [PATCH 357/387] Adds test files from dcsobral --- test/detect_files/puppet_import.pp | 2 ++ test/detect_files/puppet_import_annotated.pp | 2 ++ test/detect_files/puppet_test.pp | 3 +++ test/detect_files/puppet_test_annotated.pp | 3 +++ 4 files changed, 10 insertions(+) create mode 100644 test/detect_files/puppet_import.pp create mode 100644 test/detect_files/puppet_import_annotated.pp create mode 100644 test/detect_files/puppet_test.pp create mode 100644 test/detect_files/puppet_test_annotated.pp diff --git a/test/detect_files/puppet_import.pp b/test/detect_files/puppet_import.pp new file mode 100644 index 0000000..6cc1969 --- /dev/null +++ b/test/detect_files/puppet_import.pp @@ -0,0 +1,2 @@ +import "classes/*.pp" +import "definitions/*.pp" diff --git a/test/detect_files/puppet_import_annotated.pp b/test/detect_files/puppet_import_annotated.pp new file mode 100644 index 0000000..f2db624 --- /dev/null +++ b/test/detect_files/puppet_import_annotated.pp @@ -0,0 +1,2 @@ +puppet lcode import "classes/*.pp" +puppet lcode import "definitions/*.pp" diff --git a/test/detect_files/puppet_test.pp b/test/detect_files/puppet_test.pp new file mode 100644 index 0000000..0b9192d --- /dev/null +++ b/test/detect_files/puppet_test.pp @@ -0,0 +1,3 @@ +class main::sub { + include substuff +} diff --git a/test/detect_files/puppet_test_annotated.pp b/test/detect_files/puppet_test_annotated.pp new file mode 100644 index 0000000..b5de2ef --- /dev/null +++ b/test/detect_files/puppet_test_annotated.pp @@ -0,0 +1,3 @@ +puppet lcode class main::sub { +puppet lcode include substuff +puppet lcode } From 3bd4c8e8c6926f6c9e49b6e563d8095de2fe6394 Mon Sep 17 00:00:00 2001 From: Abhay Mujumdar Date: Fri, 21 Dec 2012 10:26:57 -0500 Subject: [PATCH 358/387] Removes failing PP disambiguation tests --- test/unit/detector_test.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index fa17ee3..5f233de 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -199,11 +199,9 @@ void test_detector_emacs_mode() { ASSERT_DETECT(LANG_C, "emacs_mode.c"); } -void test_assert_puppet(){ - ASSERT_DETECT(LANG_PUPPET, "puppet_import.pp") - ASSERT_DETECT(LANG_PUPPET, "puppet_import_annotated.pp") - ASSERT_DETECT(LANG_PUPPET, "puppet_test.pp") - ASSERT_DETECT(LANG_PUPPET, "puppet_test_annotated.pp") +void test_detector_puppet(){ + ASSERT_DETECT(LANG_PUPPET, "puppet_import.pp"); + ASSERT_DETECT(LANG_PUPPET, "puppet_test.pp"); } void test_non_existent_file(){ @@ -228,5 +226,6 @@ void all_detector_tests() { test_detector_xml_with_custom_extension(); test_detector_brainfuck(); test_detector_emacs_mode(); + test_detector_puppet(); test_non_existent_file(); } From 4fb66a8bff6756965ca9b6694ad57439d4af6f0c Mon Sep 17 00:00:00 2001 From: Abhay Mujumdar Date: Fri, 21 Dec 2012 10:42:29 -0500 Subject: [PATCH 359/387] Fixes Genie support and adds a test case Patch for Genie support was missing mapping in src/hash/parsers.gperf file. It was also missing tests. --- src/hash/parsers.gperf | 1 + test/detect_files/client-osx.gs | 38 ++++++++++++++++++++++++++++++++++++++ test/unit/detector_test.h | 5 +++++ 3 files changed, 44 insertions(+) create mode 100644 test/detect_files/client-osx.gs diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index 6672b4b..cfdd138 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -137,6 +137,7 @@ forth, parse_forth fortranfixed, parse_fortranfixed fortranfree, parse_fortranfree fsharp, parse_fsharp +genie, parse_genie glsl, parse_glsl golang, parse_golang groovy, parse_groovy diff --git a/test/detect_files/client-osx.gs b/test/detect_files/client-osx.gs new file mode 100644 index 0000000..21d5773 --- /dev/null +++ b/test/detect_files/client-osx.gs @@ -0,0 +1,38 @@ +/* + * WebSoy - Client for OSX + * Copyright (C) 2011,2012 Copyleft Games Group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program; if not, see http://www.gnu.org/licenses + * + */ + +#if XP_MACOSX + +[indent=4] +uses + GLib + GL + +class Client : Object + scene : soy.scenes.Scene + window : soy.widgets.Window + + construct (window : NP.Window) + self.scene = new soy.scenes.Scene() + self.window = new soy.widgets.Window(null) + + // TODO + +#endif + diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index 5f233de..7566495 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -204,6 +204,10 @@ void test_detector_puppet(){ ASSERT_DETECT(LANG_PUPPET, "puppet_test.pp"); } +void test_detector_genie(){ + ASSERT_DETECT(LANG_GENIE, "client-osx.gs"); +} + void test_non_existent_file(){ ASSERT_NODETECT("xxx_non_exists_xxxi.pp"); } @@ -227,5 +231,6 @@ void all_detector_tests() { test_detector_brainfuck(); test_detector_emacs_mode(); test_detector_puppet(); + test_detector_genie(); test_non_existent_file(); } From b34e7e68c0ff88909ac39b8398c0bdf3533fdc23 Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Sun, 14 Apr 2013 00:03:53 -0400 Subject: [PATCH 360/387] Add support for Mathematica's *.m files --- src/detector.c | 36 +- src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 2 + src/languages.h | 1 + src/parsers/mathematica.rl | 113 +++ test/detect_files/foo_mathematica.m | 2 + test/expected_dir/mathematica1.m | 1484 ++++++++++++++++++++++++++++++++++ test/unit/detector_test.h | 1 + test/unit/parser_test.h | 2 + test/unit/parsers/test_mathematica.h | 11 + 10 files changed, 1648 insertions(+), 5 deletions(-) create mode 100644 src/parsers/mathematica.rl create mode 100644 test/detect_files/foo_mathematica.m create mode 100644 test/expected_dir/mathematica1.m create mode 100644 test/unit/parsers/test_mathematica.h diff --git a/src/detector.c b/src/detector.c index a3e8602..9785338 100644 --- a/src/detector.c +++ b/src/detector.c @@ -625,6 +625,7 @@ const char *disambiguate_m(SourceFile *sourcefile) { int length; // Attempt to detect based on a weighted heuristic of file contents. + int mathematica_score = 0; int matlab_score = 0; int objective_c_score = 0; int limbo_score = 0; @@ -682,8 +683,8 @@ const char *disambiguate_m(SourceFile *sourcefile) { while (*p == ' ' || *p == '\t') p++; if (*p == '%') { // Matlab comment matlab_score++; - } else if (*p == '#' && strncmp(p, "#import", 7) == 0) { // Objective C - objective_c_score++; + } else if (*p == '#' && strncmp(p, "#import", 7) == 0) { // Objective C + objective_c_score++; } else if (*p == '#') { // Limbo or Octave comment while (*p == '#') p++; if (*p == ' ' || *p == '\t') { @@ -753,18 +754,43 @@ const char *disambiguate_m(SourceFile *sourcefile) { } else p++; } + // Look for Mathematica pattern definitions + p = line; + while (p < eol) { + // & as postfix operator + if (*p == '&') { + p++; + while (*p == ' ' || *p == '\t') p++; + if (*p == ',' || *p == ')' || *p == ']') mathematica_score++; + } + // Mathematica comment + if (*p == '(' && *(p + 1) == '*') mathematica_score++; + // some Mathematica operators + if (*p == '/' && *(p + 1) == '.') mathematica_score++; + if (*p == '_' && *(p + 1) == '_') mathematica_score++; + if (*p == '@' && *(p + 1) == '@') mathematica_score++; + p++; + } + // Next line. pe = line_end; while (*pe == '\r' || *pe == '\n') pe++; p = pe; } - if (limbo_score > objective_c_score && limbo_score > matlab_score) + if (limbo_score > objective_c_score && + limbo_score > matlab_score && + limbo_score > mathematica_score) return LANG_LIMBO; - else if (objective_c_score > matlab_score) + else if (objective_c_score > matlab_score && + objective_c_score > mathematica_score) return LANG_OBJECTIVE_C; + else if (octave_syntax_detected) + return LANG_OCTAVE; + else if (matlab_score > mathematica_score) + return LANG_MATLAB; else - return octave_syntax_detected ? LANG_OCTAVE : LANG_MATLAB; + return LANG_MATHEMATICA; } #include diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index 62ca3b8..1340ba2 100755 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -63,6 +63,7 @@ lisp, LANG_LISP, "Lisp", 0 logtalk, LANG_LOGTALK, "Logtalk", 0 lua, LANG_LUA, "Lua", 0 make, LANG_MAKE, "Make", 2 +mathematica, LANG_MATHEMATICA, "Mathematica", 0 matlab, LANG_MATLAB, "Matlab", 0 metafont, LANG_METAFONT, "MetaFont", 1 metapost, LANG_METAPOST, "MetaPost", 1 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index cfdd138..38eebfa 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -50,6 +50,7 @@ #include "../parsers/logtalk.h" #include "../parsers/lua.h" #include "../parsers/makefile.h" +#include "../parsers/mathematica.h" #include "../parsers/matlab.h" #include "../parsers/metafont.h" #include "../parsers/metapost.h" @@ -155,6 +156,7 @@ limbo, parse_limbo logtalk, parse_logtalk lua, parse_lua make, parse_makefile +mathematica, parse_mathematica matlab, parse_matlab metafont, parse_metafont metapost, parse_metapost diff --git a/src/languages.h b/src/languages.h index 0f23ef9..2a44ac6 100755 --- a/src/languages.h +++ b/src/languages.h @@ -64,6 +64,7 @@ #define LANG_LOGTALK "logtalk" #define LANG_LUA "lua" #define LANG_MAKE "make" +#define LANG_MATHEMATICA "mathematica" #define LANG_MATLAB "matlab" #define LANG_METAFONT "metafont" #define LANG_METAPOST "metapost" diff --git a/src/parsers/mathematica.rl b/src/parsers/mathematica.rl new file mode 100644 index 0000000..dcf142e --- /dev/null +++ b/src/parsers/mathematica.rl @@ -0,0 +1,113 @@ +// mathematica.rl written by Erik Schnetter + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_MATHEMATICA_PARSER_H +#define OHCOUNT_MATHEMATICA_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *MATHEMATICA_LANG = LANG_MATHEMATICA; + +// the languages entities +const char *mathematica_entities[] = { + "space", "comment", "string", "any", +}; + +// constants associated with the entities +enum { + MATHEMATICA_SPACE = 0, MATHEMATICA_COMMENT, MATHEMATICA_STRING, MATHEMATICA_ANY +}; + +/*****************************************************************************/ + +%%{ + machine mathematica; + write data; + include common "common.rl"; + + # Line counting machine + + action mathematica_ccallback { + switch(entity) { + case MATHEMATICA_SPACE: + ls + break; + case MATHEMATICA_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(MATHEMATICA_LANG) + break; + case NEWLINE: + std_newline(MATHEMATICA_LANG) + } + } + + mathematica_comment = + '(*' @comment ( + newline %{ entity = INTERNAL_NL; } %mathematica_ccallback + | + ws + | + (nonnewline - ws) @code + )* :>> '*)'; + + mathematica_string = '"' @code ([^"]) '"'; + + mathematica_line := |* + spaces ${ entity = MATHEMATICA_SPACE; } => mathematica_ccallback; + mathematica_comment; + mathematica_string; + newline ${ entity = NEWLINE; } => mathematica_ccallback; + ^space ${ entity = MATHEMATICA_ANY; } => mathematica_ccallback; + *|; + + # Entity machine + + action mathematica_ecallback { + callback(MATHEMATICA_LANG, mathematica_entities[entity], cint(ts), cint(te), + userdata); + } + + mathematica_comment_entity = '(*' any* :>> '*)'; + + mathematica_entity := |* + space+ ${ entity = MATHEMATICA_SPACE; } => mathematica_ecallback; + mathematica_comment_entity ${ entity = MATHEMATICA_COMMENT; } => mathematica_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with MATHEMATICA code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_mathematica(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + %% write init; + cs = (count) ? mathematica_en_mathematica_line : mathematica_en_mathematica_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(MATHEMATICA_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/test/detect_files/foo_mathematica.m b/test/detect_files/foo_mathematica.m new file mode 100644 index 0000000..ceb605c --- /dev/null +++ b/test/detect_files/foo_mathematica.m @@ -0,0 +1,2 @@ +foo[x_] := b +(* a comment *) diff --git a/test/expected_dir/mathematica1.m b/test/expected_dir/mathematica1.m new file mode 100644 index 0000000..b48ed57 --- /dev/null +++ b/test/expected_dir/mathematica1.m @@ -0,0 +1,1484 @@ +mathematica blank +mathematica code SetEnhancedTimes[False]; +mathematica code SetSourceLanguage["C"]; +mathematica blank +mathematica comment (******************************************************************************) +mathematica comment (* Options *) +mathematica comment (******************************************************************************) +mathematica blank +mathematica code createCode[derivOrder_, useJacobian_, splitUpwindDerivs_, useVectors_, useOpenCL_, evolutionTimelevels_, addMatter_, formulation_] := +mathematica code Module[{prefix, suffix, thorn}, +mathematica blank +mathematica code prefix = "ML_"; +mathematica code suffix = +mathematica code "" +mathematica code <> If [useJacobian, "_MP", ""] +mathematica code <> If [derivOrder!=4, "_O" <> ToString[derivOrder], ""] +mathematica code <> If [splitUpwindDerivs, "", "_UPW"] +mathematica code <> If [useVectors, "", "_NV"] +mathematica code <> If [useOpenCL, "_CL", ""] +mathematica comment (* <> If [evolutionTimelevels!=3, "_TL" <> ToString[evolutionTimelevels], ""] *) +mathematica comment (* <> If [addMatter==1, "_M", ""] *) +mathematica code ; +mathematica blank +mathematica code thorn = prefix <> formulation <> suffix; +mathematica blank +mathematica code SetAttributes[IfCCZ4, HoldAll]; +mathematica code IfCCZ4[expr_, else_:Sequence[]] := If[formulation === "CCZ4", expr, Unevaluated[else]]; +mathematica blank +mathematica comment (******************************************************************************) +mathematica comment (* Derivatives *) +mathematica comment (******************************************************************************) +mathematica blank +mathematica code KD = KroneckerDelta; +mathematica blank +mathematica code derivatives = +mathematica code { +mathematica code PDstandardNth[i_] -> StandardCenteredDifferenceOperator[1,fdOrder/2,i], +mathematica code PDstandardNth[i_,i_] -> StandardCenteredDifferenceOperator[2,fdOrder/2,i], +mathematica code PDstandardNth[i_,j_] -> StandardCenteredDifferenceOperator[1,fdOrder/2,i] * +mathematica code StandardCenteredDifferenceOperator[1,fdOrder/2,j], +mathematica code PDdissipationNth[i_] -> +mathematica code (-1)^(fdOrder/2) * +mathematica code spacing[i]^(fdOrder+1) / 2^(fdOrder+2) * +mathematica code StandardCenteredDifferenceOperator[fdOrder+2,fdOrder/2+1,i], +mathematica blank +mathematica comment (* PD: These come from my mathematica notebook +mathematica comment "Upwind-Kranc-Convert.nb" that converts upwinding finite +mathematica comment differencing operators generated by +mathematica comment StandardUpwindDifferenceOperator into this form *) +mathematica blank +mathematica code Sequence@@Flatten[Table[ +mathematica code {PDupwindNth[i] -> Switch[fdOrder, +mathematica code 2, (dir[i]*(-3 + 4*shift[i]^dir[i] - shift[i]^(2*dir[i])))/(2*spacing[i]), +mathematica code 4, (dir[i]*(-10 - 3/shift[i]^dir[i] + 18*shift[i]^dir[i] - +mathematica code 6*shift[i]^(2*dir[i]) + shift[i]^(3*dir[i])))/(12*spacing[i]), +mathematica code 6, (dir[i]*(-35 + 2/shift[i]^(2*dir[i]) - 24/shift[i]^dir[i] + 80*shift[i]^dir[i] - +mathematica code 30*shift[i]^(2*dir[i]) + 8*shift[i]^(3*dir[i]) - shift[i]^(4*dir[i])))/(60*spacing[i]), +mathematica code 8, (dir[i]*(-378 - 5/shift[i]^(3*dir[i]) + 60/shift[i]^(2*dir[i]) - 420/shift[i]^dir[i] + +mathematica code 1050*shift[i]^dir[i] - 420*shift[i]^(2*dir[i]) + 140*shift[i]^(3*dir[i]) - 30*shift[i]^(4*dir[i]) + +mathematica code 3*shift[i]^(5*dir[i])))/(840*spacing[i])], +mathematica blank +mathematica code PDupwindNthAnti[i] -> Switch[fdOrder, +mathematica code 2, (+1 shift[i]^(-2) -4 shift[i]^(-1) +0 shift[i]^( 0) +4 shift[i]^(+1) -1 shift[i]^(+2)) / (4 spacing[i]), +mathematica code 4, (-1 shift[i]^(-3) +6 shift[i]^(-2) -21 shift[i]^(-1 )+0 shift[i]^( 0) +21 shift[i]^(+1) +mathematica code -6 shift[i]^(+2) +1 shift[i]^(+3)) / (24 spacing[i]), +mathematica code 6, (+1 shift[i]^(-4) -8 shift[i]^(-3) +32 shift[i]^(-2) -104 shift[i]^(-1) +0 shift[i]^( 0) +mathematica code +104 shift[i]^(+1) -32 shift[i]^(+2) +8 shift[i]^(+3) -1 shift[i]^(+4)) / (120 spacing[i]), +mathematica code 8, (-3 shift[i]^(-5) +30 shift[i]^(-4) -145 shift[i]^(-3) +480 shift[i]^(-2) -1470 shift[i]^(-1) +mathematica code +0 shift[i]^( 0) +1470 shift[i]^(+1) -480 shift[i]^(+2) +145 shift[i]^(+3) -30 shift[i]^(+4) +mathematica code +3 shift[i]^(+5)) / (1680 spacing[i])], +mathematica blank +mathematica code PDupwindNthSymm[i] -> Switch[fdOrder, +mathematica code 2, (-1 shift[i]^(-2) +4 shift[i]^(-1) -6 shift[i]^( 0) +4 shift[i]^(+1) -1 shift[i]^(+2)) / (4 spacing[i]), +mathematica code 4, (+1 shift[i]^(-3) -6 shift[i]^(-2) +15 shift[i]^(-1) -20 shift[i]^( 0) +15 shift[i]^(+1) +mathematica code -6 shift[i]^(+2) +1 shift[i]^(+3)) / (24 spacing[i]), +mathematica code 6, (-1 shift[i]^(-4) +8 shift[i]^(-3) - 28 shift[i]^(-2)+56 shift[i]^(-1)-70 shift[i]^( 0) +mathematica code +56 shift[i]^(+1) -28 shift[i]^(+2) +8 shift[i]^(+3) -1 shift[i]^(+4)) / (120 spacing[i]), +mathematica code 8, (+3 shift[i]^(-5) -30 shift[i]^(-4) +135 shift[i]^(-3) -360 shift[i]^(-2) +630 shift[i]^(-1) +mathematica code -756 shift[i]^( 0) +630 shift[i]^(+1) -360 shift[i]^(+2) +135 shift[i]^(+3) -30 shift[i]^(+4) +mathematica code +3 shift[i]^(+5)) / (1680 spacing[i])], +mathematica blank +mathematica comment (* TODO: make these higher order stencils *) +mathematica code PDonesided[i] -> dir[i] (-1 + shift[i]^dir[i]) / spacing[i]} /. i->j, {j,1,3}],1] +mathematica code }; +mathematica blank +mathematica code PD = PDstandardNth; +mathematica code PDu = PDupwindNth; +mathematica code PDua = PDupwindNthAnti; +mathematica code PDus = PDupwindNthSymm; +mathematica comment (* PDo = PDonesided; *) +mathematica code PDdiss = PDdissipationNth; +mathematica blank +mathematica code If [splitUpwindDerivs, +mathematica code Upwind[dir_, var_, idx_] := dir PDua[var,idx] + Abs[dir] PDus[var,idx], +mathematica code Upwind[dir_, var_, idx_] := dir PDu[var,idx]]; +mathematica blank +mathematica blank +mathematica blank +mathematica comment (******************************************************************************) +mathematica comment (* Tensors *) +mathematica comment (******************************************************************************) +mathematica blank +mathematica comment (* Register the tensor quantities with the TensorTools package *) +mathematica code Map [DefineTensor, +mathematica code {normal, tangentA, tangentB, dir, +mathematica code nn, nu, nlen, nlen2, su, vg, +mathematica code xx, rr, th, ph, +mathematica code admg, admK, admalpha, admdtalpha, admbeta, admdtbeta, H, M, +mathematica code g, detg, gu, G, R, trR, Km, trK, cdphi, cdphi2, +mathematica code phi, gt, At, Xt, Xtn, Theta, Z, +mathematica code alpha, A, beta, B, Atm, Atu, trA, Ats, trAts, +mathematica code dottrK, dotXt, +mathematica code cXt, cS, cA, +mathematica code e4phi, em4phi, ddetg, detgt, gtu, ddetgt, dgtu, ddgtu, Gtl, Gtlu, Gt, +mathematica code Rt, Rphi, gK, +mathematica code T00, T0, T, rho, S, +mathematica code x, y, z, r, +mathematica code epsdiss}]; +mathematica blank +mathematica comment (* NOTE: It seems as if Lie[.,.] did not take these tensor weights +mathematica comment into account. Presumably, CD[.,.] and CDt[.,.] don't do this either. *) +mathematica code SetTensorAttribute[phi, TensorWeight, +1/6]; +mathematica code SetTensorAttribute[gt, TensorWeight, -2/3]; +mathematica code SetTensorAttribute[Xt, TensorWeight, +2/3]; +mathematica code SetTensorAttribute[At, TensorWeight, -2/3]; +mathematica code SetTensorAttribute[cXt, TensorWeight, +2/3]; +mathematica code SetTensorAttribute[cS, TensorWeight, +2 ]; +mathematica blank +mathematica code Map [AssertSymmetricIncreasing, +mathematica code {admg[la,lb], admK[la,lb], g[la,lb], K[la,lb], R[la,lb], cdphi2[la,lb], +mathematica code gt[la,lb], At[la,lb], Ats[la,lb], Rt[la,lb], Rphi[la,lb], T[la,lb]}]; +mathematica code AssertSymmetricIncreasing [G[ua,lb,lc], lb, lc]; +mathematica code AssertSymmetricIncreasing [Gtl[la,lb,lc], lb, lc]; +mathematica code AssertSymmetricIncreasing [Gt[ua,lb,lc], lb, lc]; +mathematica code AssertSymmetricIncreasing [gK[la,lb,lc], la, lb]; +mathematica code Map [AssertSymmetricIncreasing, +mathematica code {gu[ua,ub], gtu[ua,ub], Atu[ua,ub]}]; +mathematica code AssertSymmetricIncreasing [dgtu[ua,ub,lc], ua, ub]; +mathematica code AssertSymmetricIncreasing [ddgtu[ua,ub,lc,ld], ua, ub]; +mathematica code AssertSymmetricIncreasing [ddgtu[ua,ub,lc,ld], lc, ld]; +mathematica blank +mathematica code DefineConnection [CD, PD, G]; +mathematica code DefineConnection [CDt, PD, Gt]; +mathematica blank +mathematica comment (* Use the CartGrid3D variable names *) +mathematica code x1=x; x2=y; x3=z; +mathematica blank +mathematica comment (* Use the ADMBase variable names *) +mathematica code admg11=gxx; admg12=gxy; admg22=gyy; admg13=gxz; admg23=gyz; admg33=gzz; +mathematica code admK11=kxx; admK12=kxy; admK22=kyy; admK13=kxz; admK23=kyz; admK33=kzz; +mathematica code admalpha=alp; +mathematica code admdtalpha=dtalp; +mathematica code admbeta1=betax; admbeta2=betay; admbeta3=betaz; +mathematica code admdtbeta1=dtbetax; admdtbeta2=dtbetay; admdtbeta3=dtbetaz; +mathematica blank +mathematica comment (* Use the TmunuBase variable names *) +mathematica code T00=eTtt; +mathematica code T01=eTtx; T02=eTty; T03=eTtz; +mathematica code T11=eTxx; T12=eTxy; T22=eTyy; T13=eTxz; T23=eTyz; T33=eTzz; +mathematica blank +mathematica blank +mathematica blank +mathematica comment (******************************************************************************) +mathematica comment (* Expressions *) +mathematica comment (******************************************************************************) +mathematica blank +mathematica comment (* enum constants for conformalMethod; these must be consistent +mathematica comment with the definition of the Cactus parameter conformalMethod *) +mathematica code CMphi = 0; +mathematica code CMW = 1; +mathematica blank +mathematica code detgExpr = Det [MatrixOfComponents [g [la,lb]]]; +mathematica code ddetgExpr[la_] = +mathematica code Sum [D[Det[MatrixOfComponents[g[la, lb]]], X] PD[X, la], +mathematica code {X, Union[Flatten[MatrixOfComponents[g[la, lb]]]]}]; +mathematica blank +mathematica code detgtExpr = Det [MatrixOfComponents [gt[la,lb]]]; +mathematica code ddetgtExpr[la_] = +mathematica code Sum [D[Det[MatrixOfComponents[gt[la, lb]]], X] PD[X, la], +mathematica code {X, Union[Flatten[MatrixOfComponents[gt[la, lb]]]]}]; +mathematica blank +mathematica code etaExpr = SpatialBetaDriverRadius / Max [r, SpatialBetaDriverRadius]; +mathematica code thetaExpr = Min [Exp [1 - r / SpatialShiftGammaCoeffRadius], 1]; +mathematica blank +mathematica blank +mathematica blank +mathematica comment (******************************************************************************) +mathematica comment (* Groups *) +mathematica comment (******************************************************************************) +mathematica blank +mathematica code evolvedGroups = +mathematica code {SetGroupName [CreateGroupFromTensor [phi ], prefix <> "log_confac"], +mathematica code SetGroupName [CreateGroupFromTensor [gt[la,lb]], prefix <> "metric" ], +mathematica code SetGroupName [CreateGroupFromTensor [Xt[ua] ], prefix <> "Gamma" ], +mathematica code SetGroupName [CreateGroupFromTensor [trK ], prefix <> "trace_curv"], +mathematica code SetGroupName [CreateGroupFromTensor [At[la,lb]], prefix <> "curv" ], +mathematica code SetGroupName [CreateGroupFromTensor [alpha ], prefix <> "lapse" ], +mathematica code SetGroupName [CreateGroupFromTensor [A ], prefix <> "dtlapse" ], +mathematica code SetGroupName [CreateGroupFromTensor [beta[ua] ], prefix <> "shift" ], +mathematica code SetGroupName [CreateGroupFromTensor [B[ua] ], prefix <> "dtshift" ], +mathematica code IfCCZ4[SetGroupName[CreateGroupFromTensor[Theta], prefix <> "Theta"]]}; +mathematica code evaluatedGroups = +mathematica code {SetGroupName [CreateGroupFromTensor [H ], prefix <> "Ham"], +mathematica code SetGroupName [CreateGroupFromTensor [M[la] ], prefix <> "mom"], +mathematica code SetGroupName [CreateGroupFromTensor [cS ], prefix <> "cons_detg"], +mathematica code SetGroupName [CreateGroupFromTensor [cXt[ua]], prefix <> "cons_Gamma"], +mathematica code SetGroupName [CreateGroupFromTensor [cA ], prefix <> "cons_traceA"]}; +mathematica blank +mathematica code declaredGroups = Join [evolvedGroups, evaluatedGroups]; +mathematica code declaredGroupNames = Map [First, declaredGroups]; +mathematica blank +mathematica blank +mathematica blank +mathematica code extraGroups = +mathematica code {{"grid::coordinates", {x, y, z, r}}, +mathematica code {"ADMBase::metric", {gxx, gxy, gxz, gyy, gyz, gzz}}, +mathematica code {"ADMBase::curv", {kxx, kxy, kxz, kyy, kyz, kzz}}, +mathematica code {"ADMBase::lapse", {alp}}, +mathematica code {"ADMBase::dtlapse", {dtalp}}, +mathematica code {"ADMBase::shift", {betax, betay, betaz}}, +mathematica code {"ADMBase::dtshift", {dtbetax, dtbetay, dtbetaz}}, +mathematica code {"TmunuBase::stress_energy_scalar", {eTtt}}, +mathematica code {"TmunuBase::stress_energy_vector", {eTtx, eTty, eTtz}}, +mathematica code {"TmunuBase::stress_energy_tensor", {eTxx, eTxy, eTxz, eTyy, eTyz, eTzz}} +mathematica code }; +mathematica blank +mathematica code groups = Join [declaredGroups, extraGroups]; +mathematica blank +mathematica blank +mathematica blank +mathematica comment (******************************************************************************) +mathematica comment (* Initial data *) +mathematica comment (******************************************************************************) +mathematica blank +mathematica code initialCalc = +mathematica code { +mathematica code Name -> thorn <> "_Minkowski", +mathematica code Schedule -> {"IN ADMBase_InitialData"}, +mathematica code ConditionalOnKeyword -> {"my_initial_data", "Minkowski"}, +mathematica code Equations -> +mathematica code { +mathematica code phi -> IfThen[conformalMethod==CMW, 1, 0], +mathematica code gt[la,lb] -> KD[la,lb], +mathematica code trK -> 0, +mathematica code At[la,lb] -> 0, +mathematica code Xt[ua] -> 0, +mathematica code alpha -> 1, +mathematica code A -> 0, +mathematica code beta[ua] -> 0, +mathematica code B[ua] -> 0, +mathematica code IfCCZ4[Theta -> 0] +mathematica code } +mathematica code }; +mathematica blank +mathematica blank +mathematica blank +mathematica comment (******************************************************************************) +mathematica comment (* Split a calculation *) +mathematica comment (******************************************************************************) +mathematica blank +mathematica code PartialCalculation[calc_, suffix_, updates_, evolVars_] := +mathematica code Module[ +mathematica code {name, calc1, replaces, calc2, vars, patterns, eqs, calc3}, +mathematica comment (* Add suffix to name *) +mathematica code name = lookup[calc, Name] <> suffix; +mathematica code calc1 = mapReplace[calc, Name, name]; +mathematica comment (* Replace some entries in the calculation *) +mathematica comment (* replaces = Map[Function[rule, mapReplace[#, rule[[1]], rule[[2]]]&], updates]; *) +mathematica code replaces = updates //. (lhs_ -> rhs_) -> (mapReplace[#, lhs, rhs]&); +mathematica code calc2 = Apply[Composition, replaces][calc1]; +mathematica comment (* Remove unnecessary equations *) +mathematica code vars = Join[evolVars, lookup[calc2, Shorthands]]; +mathematica code patterns = Replace[vars, { Tensor[n_,__] -> Tensor[n,__] , +mathematica code dot[Tensor[n_,__]] -> dot[Tensor[n,__]]}, 1]; +mathematica code eqs = FilterRules[lookup[calc, Equations], patterns]; +mathematica code calc3 = mapReplace[calc2, Equations, eqs]; +mathematica code calc3 +mathematica code ]; +mathematica blank +mathematica blank +mathematica blank +mathematica comment (******************************************************************************) +mathematica comment (* Convert from ADMBase *) +mathematica comment (******************************************************************************) +mathematica blank +mathematica code convertFromADMBaseCalc = +mathematica code { +mathematica code Name -> thorn <> "_convertFromADMBase", +mathematica code Schedule -> {"AT initial AFTER ADMBase_PostInitial"}, +mathematica code ConditionalOnKeyword -> {"my_initial_data", "ADMBase"}, +mathematica code Shorthands -> {g[la,lb], detg, gu[ua,ub], em4phi}, +mathematica code Equations -> +mathematica code { +mathematica code g[la,lb] -> admg[la,lb], +mathematica code detg -> detgExpr, +mathematica code gu[ua,ub] -> 1/detg detgExpr MatrixInverse [g[ua,ub]], +mathematica code +mathematica code phi -> IfThen[conformalMethod==CMW, detg^(-1/6), Log[detg]/12], +mathematica code em4phi -> IfThen[conformalMethod==CMW, phi^2, Exp[-4 phi]], +mathematica code gt[la,lb] -> em4phi g[la,lb], +mathematica code +mathematica code trK -> gu[ua,ub] admK[la,lb], +mathematica code At[la,lb] -> em4phi (admK[la,lb] - (1/3) g[la,lb] trK), +mathematica code +mathematica code alpha -> admalpha, +mathematica code +mathematica code beta[ua] -> admbeta[ua], +mathematica blank +mathematica code IfCCZ4[Theta -> 0] +mathematica code } +mathematica code }; +mathematica blank +mathematica code convertFromADMBaseGammaCalc = +mathematica code { +mathematica code Name -> thorn <> "_convertFromADMBaseGamma", +mathematica code Schedule -> {"AT initial AFTER " <> thorn <> "_convertFromADMBase"}, +mathematica code ConditionalOnKeyword -> {"my_initial_data", "ADMBase"}, +mathematica comment (* +mathematica comment Where -> InteriorNoSync, +mathematica comment *) +mathematica comment (* Do not synchronise right after this routine; instead, synchronise +mathematica comment after extrapolating *) +mathematica code Where -> Interior, +mathematica comment (* Synchronise after this routine, so that the refinement boundaries +mathematica comment are set correctly before extrapolating. (We will need to +mathematica comment synchronise again after extrapolating because extrapolation does +mathematica comment not fill ghost zones, but this is irrelevant here.) *) +mathematica code Shorthands -> {dir[ua], +mathematica code detgt, gtu[ua,ub], Gt[ua,lb,lc], theta}, +mathematica code Equations -> +mathematica code { +mathematica code dir[ua] -> Sign[beta[ua]], +mathematica code +mathematica code detgt -> 1 (* detgtExpr *), +mathematica code gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], +mathematica code Gt[ua,lb,lc] -> 1/2 gtu[ua,ud] +mathematica code (PD[gt[lb,ld],lc] + PD[gt[lc,ld],lb] - PD[gt[lb,lc],ld]), +mathematica code Xt[ua] -> gtu[ub,uc] Gt[ua,lb,lc], +mathematica code +mathematica comment (* +mathematica comment A -> - admdtalpha / (harmonicF alpha^harmonicN) (LapseAdvectionCoeff - 1), +mathematica comment *) +mathematica comment (* If LapseACoeff=0, then A is not evolved, in the sense that it +mathematica comment does not influence the time evolution of other variables. *) +mathematica code A -> IfThen [LapseACoeff != 0, +mathematica code 1 / (- harmonicF alpha^harmonicN) +mathematica code (+ admdtalpha +mathematica code - LapseAdvectionCoeff Upwind[beta[ua], alpha, la]), +mathematica code 0], +mathematica code +mathematica code theta -> thetaExpr, +mathematica code +mathematica comment (* If ShiftBCoeff=0 or theta ShiftGammaCoeff=0, then B^i is not +mathematica comment evolved, in the sense that it does not influence the time +mathematica comment evolution of other variables. *) +mathematica code B[ua] -> IfThen [ShiftGammaCoeff ShiftBCoeff != 0, +mathematica code 1 / (theta ShiftGammaCoeff) +mathematica code (+ admdtbeta[ua] +mathematica code - ShiftAdvectionCoeff Upwind[beta[ub], beta[ua], lb]), +mathematica code 0] +mathematica code } +mathematica code }; +mathematica blank +mathematica comment (* Initialise the Gamma variables to 0. This is necessary with +mathematica comment multipatch because convertFromADMBaseGamma does not perform the +mathematica comment conversion in the boundary points, and the order in which symmetry +mathematica comment (interpatch) and outer boundary conditions is applied means that +mathematica comment points which are both interpatch and symmetry points are never +mathematica comment initialised. *) +mathematica code initGammaCalc = +mathematica code { +mathematica code Name -> thorn <> "_InitGamma", +mathematica code Schedule -> {"AT initial BEFORE " <> thorn <> "_convertFromADMBaseGamma"}, +mathematica code ConditionalOnKeyword -> {"my_initial_data", "ADMBase"}, +mathematica code Where -> Everywhere, +mathematica code Equations -> +mathematica code { +mathematica code Xt[ua] -> 0, +mathematica code A -> 0, +mathematica code B[ua] -> 0 +mathematica code } +mathematica code }; +mathematica blank +mathematica blank +mathematica blank +mathematica comment (******************************************************************************) +mathematica comment (* Convert to ADMBase *) +mathematica comment (******************************************************************************) +mathematica blank +mathematica code convertToADMBaseCalc = +mathematica code { +mathematica code Name -> thorn <> "_convertToADMBase", +mathematica code Schedule -> {"IN " <> thorn <> "_convertToADMBaseGroup"}, +mathematica code Where -> Everywhere, +mathematica code Shorthands -> {e4phi}, +mathematica code Equations -> +mathematica code { +mathematica code e4phi -> IfThen[conformalMethod==CMW, 1/phi^2, Exp[4 phi]], +mathematica code admg[la,lb] -> e4phi gt[la,lb], +mathematica code admK[la,lb] -> e4phi At[la,lb] + (1/3) admg[la,lb] trK, +mathematica code admalpha -> alpha, +mathematica code admbeta[ua] -> beta[ua] +mathematica code } +mathematica code }; +mathematica blank +mathematica code convertToADMBaseDtLapseShiftCalc = +mathematica code { +mathematica code Name -> thorn <> "_convertToADMBaseDtLapseShift", +mathematica code Schedule -> {"IN " <> thorn <> "_convertToADMBaseGroup"}, +mathematica code ConditionalOnKeyword -> {"dt_lapse_shift_method", "correct"}, +mathematica code Where -> Interior, +mathematica code Shorthands -> {dir[ua], detgt, gtu[ua,ub], eta, theta}, +mathematica code Equations -> +mathematica code { +mathematica code dir[ua] -> Sign[beta[ua]], +mathematica code +mathematica code detgt -> 1 (* detgtExpr *), +mathematica comment (* This leads to simpler code... *) +mathematica code gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], +mathematica code +mathematica code eta -> etaExpr, +mathematica code theta -> thetaExpr, +mathematica code +mathematica comment (* see RHS *) +mathematica comment (* +mathematica comment admdtalpha -> - harmonicF alpha^harmonicN +mathematica comment ((1 - LapseAdvectionCoeff) A + LapseAdvectionCoeff trK) +mathematica comment + LapseAdvectionCoeff beta[ua] PDu[alpha,la], +mathematica comment *) +mathematica code admdtalpha -> - harmonicF alpha^harmonicN +mathematica code (+ LapseACoeff A +mathematica code + ((1 - LapseACoeff) +mathematica code (trK - IfCCZ4[2 Theta, 0]))) +mathematica code + LapseAdvectionCoeff Upwind[beta[ua], alpha, la], +mathematica code admdtbeta[ua] -> IfThen[harmonicShift, +mathematica code - 1/2 gtu[ua,uj] phi alpha +mathematica code (- 2 alpha PD[phi,lj] +mathematica code + 2 phi PD[alpha,lj] +mathematica code + gtu[uk,ul] phi alpha +mathematica code (PD[gt[lk,ll],lj] - 2 PD[gt[lj,lk],ll])), +mathematica code (* else *) +mathematica code + theta ShiftGammaCoeff +mathematica code (+ ShiftBCoeff B[ua] +mathematica code + (1 - ShiftBCoeff) +mathematica code (Xt[ua] - eta BetaDriver beta[ua]))] +mathematica code + ShiftAdvectionCoeff Upwind[beta[ub], beta[ua], lb] +mathematica code } +mathematica code }; +mathematica blank +mathematica code convertToADMBaseDtLapseShiftBoundaryCalc = +mathematica code { +mathematica code Name -> thorn <> "_convertToADMBaseDtLapseShiftBoundary", +mathematica code Schedule -> {"IN " <> thorn <> "_convertToADMBaseGroup"}, +mathematica code ConditionalOnKeyword -> {"dt_lapse_shift_method", "correct"}, +mathematica code Where -> BoundaryWithGhosts, +mathematica code Shorthands -> {detgt, gtu[ua,ub], eta, theta}, +mathematica code Equations -> +mathematica code { +mathematica code detgt -> 1 (* detgtExpr *), +mathematica comment (* This leads to simpler code... *) +mathematica code gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], +mathematica code +mathematica code eta -> etaExpr, +mathematica code theta -> thetaExpr, +mathematica code +mathematica comment (* see RHS, but omit derivatives near the boundary *) +mathematica comment (* +mathematica comment admdtalpha -> - harmonicF alpha^harmonicN +mathematica comment ((1 - LapseAdvectionCoeff) A + LapseAdvectionCoeff trK), +mathematica comment *) +mathematica code admdtalpha -> - harmonicF alpha^harmonicN +mathematica code (+ LapseACoeff A +mathematica code + ((1 - LapseACoeff) +mathematica code (trK - IfCCZ4[2 Theta, 0]))), +mathematica code admdtbeta[ua] -> IfThen[harmonicShift, +mathematica code 0, +mathematica code (* else *) +mathematica code + theta ShiftGammaCoeff +mathematica code (+ ShiftBCoeff B[ua] +mathematica code + (1 - ShiftBCoeff) +mathematica code (Xt[ua] - eta BetaDriver beta[ua]))] +mathematica code } +mathematica code }; +mathematica blank +mathematica code convertToADMBaseFakeDtLapseShiftCalc = +mathematica code { +mathematica code Name -> thorn <> "_convertToADMBaseFakeDtLapseShift", +mathematica code Schedule -> {"IN " <> thorn <> "_convertToADMBaseGroup"}, +mathematica code ConditionalOnKeyword -> {"dt_lapse_shift_method", "noLapseShiftAdvection"}, +mathematica code Where -> Everywhere, +mathematica code Shorthands -> {detgt, gtu[ua,ub], eta, theta}, +mathematica code Equations -> +mathematica code { +mathematica code detgt -> 1 (* detgtExpr *), +mathematica comment (* This leads to simpler code... *) +mathematica code gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], +mathematica code +mathematica code eta -> etaExpr, +mathematica code theta -> thetaExpr, +mathematica code +mathematica comment (* see RHS, but omit derivatives everywhere (which is wrong, but +mathematica comment faster, since it does not require synchronisation or boundary +mathematica comment conditions) *) +mathematica comment (* +mathematica comment admdtalpha -> - harmonicF alpha^harmonicN +mathematica comment ((1 - LapseAdvectionCoeff) A + LapseAdvectionCoeff trK), +mathematica comment *) +mathematica code admdtalpha -> - harmonicF alpha^harmonicN +mathematica code (+ LapseACoeff A +mathematica code + ((1 - LapseACoeff) +mathematica code (trK - IfCCZ4[2 Theta, 0]))), +mathematica code admdtbeta[ua] -> IfThen[harmonicShift, +mathematica code 0, +mathematica code (* else *) +mathematica code + theta ShiftGammaCoeff +mathematica code (+ ShiftBCoeff B[ua] +mathematica code + (1 - ShiftBCoeff) +mathematica code (Xt[ua] - eta BetaDriver beta[ua]))] +mathematica code } +mathematica code }; +mathematica blank +mathematica comment (******************************************************************************) +mathematica comment (* Evolution equations *) +mathematica comment (******************************************************************************) +mathematica blank +mathematica code evolCalc = +mathematica code { +mathematica code Name -> thorn <> "_RHS", +mathematica code Schedule -> {"IN " <> thorn <> "_evolCalcGroup"}, +mathematica comment (* +mathematica comment Where -> Interior, +mathematica comment *) +mathematica comment (* Synchronise the RHS grid functions after this routine, so that +mathematica comment the refinement boundaries are set correctly before applying the +mathematica comment radiative boundary conditions. *) +mathematica code Where -> InteriorNoSync, +mathematica code ConditionalOnKeyword -> {"RHS_split", "combined"}, +mathematica code Shorthands -> {dir[ua], +mathematica code detgt, gtu[ua,ub], +mathematica code Gt[ua,lb,lc], Gtl[la,lb,lc], Gtlu[la,lb,uc], Xtn[ua], +mathematica code Rt[la,lb], Rphi[la,lb], R[la,lb], +mathematica code Atm[ua,lb], Atu[ua,ub], +mathematica code e4phi, em4phi, cdphi[la], cdphi2[la,lb], g[la,lb], detg, +mathematica code gu[ua,ub], Ats[la,lb], trAts, eta, theta, +mathematica code rho, S[la], trS, fac1, fac2, dottrK, dotXt[ua], +mathematica code epsdiss[ua], IfCCZ4[Z[ua]], IfCCZ4[dotTheta]}, +mathematica code Equations -> +mathematica code { +mathematica code dir[ua] -> Sign[beta[ua]], +mathematica code +mathematica code detgt -> 1 (* detgtExpr *), +mathematica code +mathematica comment (* This leads to simpler code... *) +mathematica code gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], +mathematica code Gtl[la,lb,lc] -> 1/2 +mathematica code (PD[gt[lb,la],lc] + PD[gt[lc,la],lb] - PD[gt[lb,lc],la]), +mathematica code Gtlu[la,lb,uc] -> gtu[uc,ud] Gtl[la,lb,ld], +mathematica code Gt[ua,lb,lc] -> gtu[ua,ud] Gtl[ld,lb,lc], +mathematica code +mathematica comment (* The conformal connection functions calculated from the conformal metric, +mathematica comment used instead of Xt where no derivatives of Xt are taken *) +mathematica code Xtn[ui] -> gtu[uj,uk] Gt[ui,lj,lk], +mathematica blank +mathematica code e4phi -> IfThen[conformalMethod==CMW, 1/phi^2, Exp[4 phi]], +mathematica code em4phi -> 1 / e4phi, +mathematica code g[la,lb] -> e4phi gt[la,lb], +mathematica code detg -> detgExpr, +mathematica code gu[ua,ub] -> em4phi gtu[ua,ub], +mathematica blank +mathematica comment (* The Z quantities *) +mathematica comment (* gr-qc:1106.2254 (2011), eqn. (23) *) +mathematica code IfCCZ4[ +mathematica code Z[ud] -> (1/2) gu[ua,ud] (- PD[gt[la,lb],lc] gtu[ub,uc] + gt[la,lc] Xt[uc]) +mathematica code ], +mathematica blank +mathematica comment (* PRD 62, 044034 (2000), eqn. (18) *) +mathematica comment (* Adding Z term by changing Xtn to Xt *) +mathematica code Rt[li,lj] -> - (1/2) gtu[ul,um] PD[gt[li,lj],ll,lm] +mathematica code + (1/2) gt[lk,li] PD[Xt[uk],lj] +mathematica code + (1/2) gt[lk,lj] PD[Xt[uk],li] +mathematica code + (1/2) Xtn[uk] Gtl[li,lj,lk] +mathematica code + (1/2) Xtn[uk] Gtl[lj,li,lk] +mathematica code + (+ Gt[uk,li,ll] Gtlu[lj,lk,ul] +mathematica code + Gt[uk,lj,ll] Gtlu[li,lk,ul] +mathematica code + Gt[uk,li,ll] Gtlu[lk,lj,ul]), +mathematica blank +mathematica code fac1 -> IfThen[conformalMethod==CMW, -1/(2 phi), 1], +mathematica code cdphi[la] -> fac1 CDt[phi,la], +mathematica code fac2 -> IfThen[conformalMethod==CMW, 1/(2 phi^2), 0], +mathematica code cdphi2[la,lb] -> fac1 CDt[phi,la,lb] + fac2 CDt[phi,la] CDt[phi,lb], +mathematica blank +mathematica comment (* PRD 62, 044034 (2000), eqn. (15) *) +mathematica code Rphi[li,lj] -> - 2 cdphi2[lj,li] +mathematica code - 2 gt[li,lj] gtu[ul,un] cdphi2[ll,ln] +mathematica code + 4 cdphi[li] cdphi[lj] +mathematica code - 4 gt[li,lj] gtu[ul,un] cdphi[ln] cdphi[ll], +mathematica code +mathematica code Atm[ua,lb] -> gtu[ua,uc] At[lc,lb], +mathematica code Atu[ua,ub] -> Atm[ua,lc] gtu[ub,uc], +mathematica code +mathematica code R[la,lb] -> Rt[la,lb] + Rphi[la,lb], +mathematica code IfCCZ4[ +mathematica code R[la,lb] -> R[la,lb] + (2/phi) (+ g[la,lc] Z[uc] PD[phi,lb] +mathematica code + g[lb,lc] Z[uc] PD[phi,la] - g[la,lb] Z[uc] PD[phi,lc]) +mathematica code + e4phi Z[uc] PD[gt[la,lb],lc] +mathematica code ], +mathematica code +mathematica comment (* Matter terms *) +mathematica blank +mathematica comment (* rho = n^a n^b T_ab *) +mathematica code rho -> addMatter +mathematica code (1/alpha^2 (T00 - 2 beta[ui] T0[li] + beta[ui] beta[uj] T[li,lj])), +mathematica code +mathematica comment (* S_i = -p^a_i n^b T_ab, where p^a_i = delta^a_i + n^a n_i *) +mathematica code S[li] -> addMatter (-1/alpha (T0[li] - beta[uj] T[li,lj])), +mathematica code +mathematica comment (* trS = gamma^ij T_ij *) +mathematica code trS -> addMatter (em4phi gtu[ui,uj] T[li,lj]), +mathematica code +mathematica comment (* RHS terms *) +mathematica code +mathematica comment (* PRD 62, 044034 (2000), eqn. (10) *) +mathematica comment (* PRD 67 084023 (2003), eqn. (16) and (23) *) +mathematica code dot[phi] -> IfThen[conformalMethod==CMW, 1/3 phi, -1/6] +mathematica code (alpha trK - PD[beta[ua],la]), +mathematica code +mathematica comment (* PRD 62, 044034 (2000), eqn. (9) *) +mathematica comment (* gr-qc:1106.2254 (2011), eqn. (14) *) +mathematica comment (* removing trA from Aij ensures that detg = 1 *) +mathematica code dot[gt[la,lb]] -> - 2 alpha (At[la,lb] - IfCCZ4[(1/3) At[lc,ld] gtu[uc,ud] gt[la,lb], 0]) +mathematica code + gt[la,lc] PD[beta[uc],lb] + gt[lb,lc] PD[beta[uc],la] +mathematica code - (2/3) gt[la,lb] PD[beta[uc],lc], +mathematica comment (* PRD 62, 044034 (2000), eqn. (20) *) +mathematica comment (* PRD 67 084023 (2003), eqn (26) *) +mathematica comment (* gr-qc:1106.2254 (2011), eqn. (19) *) +mathematica comment (* Adding Z terms by changing Xtn to Xt, +mathematica comment also adding extra Z and Theta terms *) +mathematica code dotXt[ui] -> - 2 Atu[ui,uj] PD[alpha,lj] +mathematica code + 2 alpha (+ Gt[ui,lj,lk] Atu[uk,uj] +mathematica code - (2/3) gtu[ui,uj] PD[trK,lj] +mathematica code + 6 Atu[ui,uj] cdphi[lj]) +mathematica code + gtu[uj,ul] PD[beta[ui],lj,ll] +mathematica code + (1/3) gtu[ui,uj] PD[beta[ul],lj,ll] +mathematica code - Xtn[uj] PD[beta[ui],lj] +mathematica code + (2/3) Xtn[ui] PD[beta[uj],lj] +mathematica code + IfCCZ4[ +mathematica code + GammaShift 2 e4phi (- Z[uj] PD[beta[ui],lj] +mathematica code + (2/3) Z[ui] PD[beta[uj],lj]) +mathematica code - (4/3) alpha e4phi Z[ui] trK +mathematica code + 2 gtu[ui,uj] (+ alpha PD[Theta,lj] +mathematica code - Theta PD[alpha,lj]) +mathematica code - 2 alpha e4phi dampk1 Z[ui], +mathematica code 0] +mathematica comment (* Equation (4.28) in Baumgarte & Shapiro (Phys. Rept. 376 (2003) 41-131) *) +mathematica code + addMatter (- 16 Pi alpha gtu[ui,uj] S[lj]), +mathematica code dot[Xt[ui]] -> dotXt[ui], +mathematica blank +mathematica comment (* gr-qc:1106.2254 (2011), eqn. (18) *) +mathematica code IfCCZ4[ +mathematica code dotTheta -> +mathematica code - PD[alpha,la] Z[ua] - dampk1 (2 + dampk2) alpha Theta +mathematica code + (1/2) alpha (gu[ua,ub] R[la,lb] - Atm[ua,lb] Atm[ub,la] + (2/3) trK^2 - 2 trK Theta) +mathematica code + addMatter (- 8 Pi alpha rho) +mathematica code ], +mathematica blank +mathematica code IfCCZ4[ +mathematica code dot[Theta] -> dotTheta +mathematica code ], +mathematica blank +mathematica comment (* PRD 62, 044034 (2000), eqn. (11) *) +mathematica comment (* gr-qc:1106.2254 (2011), eqn. (17) *) +mathematica comment (* Adding the RHS of Theta to K, because K_Z4 = K_BSSN + 2 Theta *) +mathematica comment (* Also adding the Z term, as it has to cancel with the one in Theta *) +mathematica code dottrK -> - em4phi ( gtu[ua,ub] ( PD[alpha,la,lb] +mathematica code + 2 cdphi[la] PD[alpha,lb] ) +mathematica code - Xtn[ua] PD[alpha,la] ) +mathematica code + alpha (Atm[ua,lb] Atm[ub,la] + (1/3) trK^2) +mathematica code + IfCCZ4[ +mathematica code + 2 dotTheta + 2 PD[alpha,la] Z[ua] +mathematica code + dampk1 (1 - dampk2) alpha Theta, +mathematica code 0] +mathematica comment (* Equation (4.21) in Baumgarte & Shapiro (Phys. Rept. 376 (2003) 41-131) *) +mathematica code + addMatter (4 Pi alpha (rho + trS)), +mathematica code dot[trK] -> dottrK, +mathematica blank +mathematica comment (* PRD 62, 044034 (2000), eqn. (12) *) +mathematica comment (* TODO: Should we use the Hamiltonian constraint to make Rij tracefree? *) +mathematica comment (* gr-qc:1106.2254 (2011), eqn. (15) *) +mathematica comment (* Adding Z terms in the Ricci and Theta terms *) +mathematica code Ats[la,lb] -> - CDt[alpha,la,lb] + +mathematica code + 2 (PD[alpha,la] cdphi[lb] + PD[alpha,lb] cdphi[la] ) +mathematica code + alpha R[la,lb], +mathematica code trAts -> gu[ua,ub] Ats[la,lb], +mathematica code dot[At[la,lb]] -> + em4phi (+ Ats[la,lb] - (1/3) g[la,lb] trAts ) +mathematica code + alpha (+ ((trK - IfCCZ4[2 Theta, 0]) +mathematica code At[la,lb]) +mathematica code - 2 At[la,lc] Atm[uc,lb]) +mathematica code + At[la,lc] PD[beta[uc],lb] + At[lb,lc] PD[beta[uc],la] +mathematica code - (2/3) At[la,lb] PD[beta[uc],lc] +mathematica comment (* Equation (4.23) in Baumgarte & Shapiro (Phys. Rept. 376 (2003) 41-131) *) +mathematica code + addMatter (- em4phi alpha 8 Pi +mathematica code (T[la,lb] - (1/3) g[la,lb] trS)), +mathematica code +mathematica comment (* dot[alpha] -> - harmonicF alpha^harmonicN trK, *) +mathematica comment (* dot[alpha] -> - harmonicF alpha^harmonicN A + Lie[alpha, beta], *) +mathematica comment (* +mathematica comment dot[alpha] -> - harmonicF alpha^harmonicN ( +mathematica comment (1 - LapseAdvectionCoeff) A + LapseAdvectionCoeff trK) +mathematica comment + LapseAdvectionCoeff beta[ua] PDu[alpha,la], +mathematica blank +mathematica blank +mathematica comment dot[A] -> (1 - LapseAdvectionCoeff) (dottrK - AlphaDriver A), +mathematica blank +mathematica comment *) +mathematica code dot[alpha] -> - harmonicF alpha^harmonicN +mathematica code (+ LapseACoeff A +mathematica code + ((1 - LapseACoeff) +mathematica code (+ trK - IfCCZ4[2 Theta, 0] +mathematica code + AlphaDriver (alpha - 1)))), +mathematica blank +mathematica code dot[A] -> + (LapseACoeff +mathematica code (+ dottrK - IfCCZ4[2 dotTheta, 0] +mathematica code - AlphaDriver A)), +mathematica code +mathematica code eta -> etaExpr, +mathematica code theta -> thetaExpr, +mathematica code +mathematica comment (* dot[beta[ua]] -> eta Xt[ua], *) +mathematica comment (* dot[beta[ua]] -> ShiftGammaCoeff alpha^ShiftAlphaPower B[ua], *) +mathematica code dot[beta[ua]] -> IfThen[harmonicShift, +mathematica code - 1/2 gtu[ua,uj] phi alpha +mathematica code (- 2 alpha PD[phi,lj] +mathematica code + 2 phi PD[alpha,lj] +mathematica code + gtu[uk,ul] phi alpha +mathematica code (PD[gt[lk,ll],lj] - 2 PD[gt[lj,lk],ll])), +mathematica comment (* else *) +mathematica code + theta ShiftGammaCoeff +mathematica code (+ ShiftBCoeff B[ua] +mathematica code + (1 - ShiftBCoeff) +mathematica code (Xt[ua] - eta BetaDriver beta[ua]))], +mathematica blank +mathematica code dot[B[ua]] -> + ShiftBCoeff (dotXt[ua] - eta BetaDriver B[ua]) +mathematica comment (* Note that this dotXt[ua] is not yet \partial_t \tilde \Gamma^i, because the +mathematica comment advection term has not yet been added. It is actually +mathematica comment \partial_t \tilde \Gamma^i - \beta^j \partial_j \tilde \Gamma^i *) +mathematica code } +mathematica code }; +mathematica blank +mathematica code advectCalc = +mathematica code { +mathematica code Name -> thorn <> "_Advect", +mathematica code Schedule -> {"IN " <> thorn <> "_evolCalcGroup " <> +mathematica code "AFTER (" <> thorn <> "_RHS " <> thorn <> "_RHS1 " <> thorn <> "_RHS2)"}, +mathematica comment (* +mathematica comment Where -> Interior, +mathematica comment *) +mathematica comment (* Synchronise the RHS grid functions after this routine, so that +mathematica comment the refinement boundaries are set correctly before applying the +mathematica comment radiative boundary conditions. *) +mathematica code Where -> InteriorNoSync, +mathematica code ConditionalOnKeyword -> {"advection_split", "combined"}, +mathematica code Shorthands -> {dir[ua]}, +mathematica code Equations -> +mathematica code { +mathematica code dir[ua] -> Sign[beta[ua]], +mathematica blank +mathematica code dot[phi] -> dot[phi] + Upwind[beta[ua], phi, la], +mathematica blank +mathematica code dot[gt[la,lb]] -> dot[gt[la,lb]] + Upwind[beta[uc], gt[la,lb], lc], +mathematica blank +mathematica code dot[Xt[ui]] -> dot[Xt[ui]] + Upwind[beta[uj], Xt[ui], lj], +mathematica blank +mathematica code IfCCZ4[ +mathematica code dot[Theta] -> dot[Theta] + Upwind[beta[ua], Theta, la] +mathematica code ], +mathematica blank +mathematica code dot[trK] -> dot[trK] + Upwind[beta[ua], trK, la], +mathematica blank +mathematica code dot[At[la,lb]] -> dot[At[la,lb]] + Upwind[beta[uc], At[la,lb], lc], +mathematica blank +mathematica code dot[alpha] -> dot[alpha] +mathematica code + LapseAdvectionCoeff Upwind[beta[ua], alpha, la], +mathematica blank +mathematica code dot[A] -> dot[A] +mathematica code + LapseACoeff ( +mathematica code + LapseAdvectionCoeff Upwind[beta[ua], A, la] +mathematica code + (1 - LapseAdvectionCoeff) Upwind[beta[ua], trK, la]), +mathematica blank +mathematica code dot[beta[ua]] -> dot[beta[ua]] +mathematica code + ShiftAdvectionCoeff Upwind[beta[ub], beta[ua], lb], +mathematica blank +mathematica code dot[B[ua]] -> dot[B[ua]] +mathematica code + ShiftBCoeff ( +mathematica code + ShiftAdvectionCoeff Upwind[beta[ub], B[ua], lb] +mathematica code + ((1 - ShiftAdvectionCoeff) +mathematica code Upwind[beta[ub], Xt[ua], lb])) +mathematica comment (* Note that the advection term \beta^j \partial_j \tilde \Gamma^i is not +mathematica comment subtracted here when ShiftAdvectionCoefficient == 1 because it was +mathematica comment implicitly subtracted before (see comment in previous calculation of +mathematica comment dot[B[ua]]. *) +mathematica code } +mathematica code }; +mathematica blank +mathematica code varsNames = { +mathematica code {"phi", dot[phi]}, +mathematica code {"gt", dot[gt[la,lb]]}, +mathematica code {"Xt", dot[Xt[ui]]}, +mathematica code {"trK", dot[trK]}, +mathematica code {"At", dot[At[la,lb]]}, +mathematica code {"alpha", dot[alpha]}, +mathematica code {"A", dot[A]}, +mathematica code {"beta", dot[beta[ua]]}, +mathematica code {"B", dot[B[ua]]}, +mathematica code IfCCZ4[{"Theta", dot[Theta]}] +mathematica code }; +mathematica blank +mathematica code advectCalcs = Map[ +mathematica code PartialCalculation[advectCalc, "_"<>ToString[First[#]], +mathematica code {ConditionalOnKeyword -> {"advection_split", +mathematica code "per variable"}}, +mathematica code {Last[#]}]&, +mathematica code varsNames]; +mathematica blank +mathematica code evolCalc1 = PartialCalculation[evolCalc, "1", +mathematica code { +mathematica code ConditionalOnKeyword -> {"RHS_split", "split At"} +mathematica code }, +mathematica code { +mathematica code dot[phi], +mathematica code dot[gt[la,lb]], +mathematica code dot[Xt[ui]], +mathematica code dot[trK], +mathematica code dot[alpha], +mathematica code dot[A], +mathematica code dot[beta[ua]], +mathematica code dot[B[ua]], +mathematica code IfCCZ4[dot[Theta]] +mathematica code }]; +mathematica blank +mathematica code evolCalc2 = PartialCalculation[evolCalc, "2", +mathematica code { +mathematica code ConditionalOnKeyword -> {"RHS_split", "split At"} +mathematica code }, +mathematica code { +mathematica code dot[At[la,lb]] +mathematica code }]; +mathematica blank +mathematica code dissCalc = +mathematica code { +mathematica code Name -> thorn <> "_Dissipation", +mathematica code Schedule -> {"IN " <> thorn <> "_evolCalcGroup " <> +mathematica code "AFTER (" <> thorn <> "_RHS1 " <> thorn <> "_RHS2)"}, +mathematica code ConditionalOnKeyword -> {"apply_dissipation", "always"}, +mathematica code Where -> InteriorNoSync, +mathematica code Shorthands -> {epsdiss[ua]}, +mathematica code Equations -> +mathematica code { +mathematica code epsdiss[ua] -> EpsDiss, +mathematica code Sequence@@Table[ +mathematica code dot[var] -> dot[var] + epsdiss[ux] PDdiss[var,lx], +mathematica code {var, {phi, gt[la,lb], Xt[ui], IfCCZ4[Theta], trK, At[la,lb], +mathematica code alpha, A, beta[ua], B[ua]}}] +mathematica code } +mathematica code }; +mathematica blank +mathematica code dissCalcs = +mathematica code Table[ +mathematica code { +mathematica code Name -> thorn <> "_Dissipation_" <> ToString[var /. {Tensor[n_,__] -> n}], +mathematica code Schedule -> {"IN " <> thorn <> "_evolCalcGroup " <> +mathematica code "AFTER (" <> thorn <> "_RHS1 " <> thorn <> "_RHS2)"}, +mathematica code ConditionalOnKeyword -> {"apply_dissipation", "always"}, +mathematica code Where -> InteriorNoSync, +mathematica code Shorthands -> {epsdiss[ua]}, +mathematica code Equations -> +mathematica code { +mathematica code epsdiss[ua] -> EpsDiss, +mathematica code dot[var] -> dot[var] + epsdiss[ux] PDdiss[var,lx] +mathematica code } +mathematica code }, +mathematica code {var, {phi, gt[la,lb], Xt[ui], IfCCZ4[Theta], trK, At[la,lb], +mathematica code alpha, A, beta[ua], B[ua]}} +mathematica code ]; +mathematica blank +mathematica code RHSStaticBoundaryCalc = +mathematica code { +mathematica code Name -> thorn <> "_RHSStaticBoundary", +mathematica code Schedule -> {"IN MoL_CalcRHS"}, +mathematica code ConditionalOnKeyword -> {"my_rhs_boundary_condition", "static"}, +mathematica code Where -> Boundary, +mathematica code Equations -> +mathematica code { +mathematica code dot[phi] -> 0, +mathematica code dot[gt[la,lb]] -> 0, +mathematica code dot[trK] -> 0, +mathematica code dot[At[la,lb]] -> 0, +mathematica code dot[Xt[ua]] -> 0, +mathematica code dot[alpha] -> 0, +mathematica code dot[A] -> 0, +mathematica code dot[beta[ua]] -> 0, +mathematica code dot[B[ua]] -> 0, +mathematica code IfCCZ4[dot[Theta] -> 0] +mathematica code } +mathematica code }; +mathematica blank +mathematica comment (* Initialise the RHS variables in analysis in case they are going to +mathematica comment be output - the noninterior points cannot be filled, so we define +mathematica comment them to be zero *) +mathematica code initRHSCalc = +mathematica code { +mathematica code Name -> thorn <> "_InitRHS", +mathematica code Schedule -> {"AT analysis BEFORE " <> thorn <> "_evolCalcGroup"}, +mathematica code Where -> Everywhere, +mathematica code Equations -> +mathematica code { +mathematica code dot[phi] -> 0, +mathematica code dot[gt[la,lb]] -> 0, +mathematica code dot[trK] -> 0, +mathematica code dot[At[la,lb]] -> 0, +mathematica code dot[Xt[ua]] -> 0, +mathematica code dot[alpha] -> 0, +mathematica code dot[A] -> 0, +mathematica code dot[beta[ua]] -> 0, +mathematica code dot[B[ua]] -> 0, +mathematica code IfCCZ4[dot[Theta] -> 0] +mathematica code } +mathematica code }; +mathematica blank +mathematica code RHSRadiativeBoundaryCalc = +mathematica code { +mathematica code Name -> thorn <> "_RHSRadiativeBoundary", +mathematica code Schedule -> {"IN MoL_CalcRHS"}, +mathematica code ConditionalOnKeyword -> {"my_rhs_boundary_condition", "radiative"}, +mathematica code Where -> Boundary, +mathematica code Shorthands -> {dir[ua], +mathematica code detgt, gtu[ua,ub], em4phi, gu[ua,ub], +mathematica code nn[la], nu[ua], nlen, nlen2, su[ua], +mathematica code vg}, +mathematica code Equations -> +mathematica code { +mathematica code dir[ua] -> Sign[normal[ua]], +mathematica code +mathematica code detgt -> 1 (* detgtExpr *), +mathematica code gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], +mathematica code em4phi -> IfThen[conformalMethod==CMW, phi^2, Exp[-4 phi]], +mathematica code gu[ua,ub] -> em4phi gtu[ua,ub], +mathematica code +mathematica code nn[la] -> Euc[la,lb] normal[ub], +mathematica code nu[ua] -> gu[ua,ub] nn[lb], +mathematica code nlen2 -> nu[ua] nn[la], +mathematica code nlen -> Sqrt[nlen2], +mathematica code su[ua] -> nu[ua] / nlen, +mathematica code +mathematica code vg -> Sqrt[harmonicF], +mathematica code +mathematica code dot[phi] -> - vg su[uc] PDo[phi ,lc], +mathematica code dot[gt[la,lb]] -> - su[uc] PDo[gt[la,lb],lc], +mathematica code dot[trK] -> - vg su[uc] PDo[trK ,lc], +mathematica code dot[At[la,lb]] -> - su[uc] PDo[At[la,lb],lc], +mathematica code dot[Xt[ua]] -> - su[uc] PDo[Xt[ua] ,lc], +mathematica code dot[alpha] -> - vg su[uc] PDo[alpha ,lc], +mathematica code dot[A] -> - vg su[uc] PDo[A ,lc], +mathematica code dot[beta[ua]] -> - su[uc] PDo[beta[ua] ,lc], +mathematica code dot[B[ua]] -> - su[uc] PDo[B[ua] ,lc], +mathematica code IfCCZ4[ +mathematica code dot[Theta] -> - vg su[uc] PDo[Theta ,lc] +mathematica code ] +mathematica code } +mathematica code }; +mathematica blank +mathematica code enforceCalc = +mathematica code { +mathematica code Name -> thorn <> "_enforce", +mathematica code Schedule -> {"IN MoL_PostStepModify"}, +mathematica code Shorthands -> {detgt, gtu[ua,ub], trAt}, +mathematica code Equations -> +mathematica code { +mathematica comment (* The following comment is still interesting, but is not correct +mathematica comment any more since it is now scheduled in MoL_PostStepModify instead: +mathematica blank +mathematica comment Enforcing the constraints needs to be a projection, because it +mathematica comment is applied in MoL_PostStep and may thus be applied multiple +mathematica comment times, not only during time evolution. Therefore detgt has to +mathematica comment be calculated correctly, without assuming that det gt_ij = 1, +mathematica comment which is not always the case (since we don't enforce it). On +mathematica comment the other hand, this may not be so important... *) +mathematica code detgt -> 1 (* detgtExpr *), +mathematica code gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], +mathematica code +mathematica code trAt -> gtu[ua,ub] At[la,lb], +mathematica code +mathematica code At[la,lb] -> At[la,lb] - (1/3) gt[la,lb] trAt, +mathematica code +mathematica code alpha -> Max[alpha, MinimumLapse] +mathematica code } +mathematica code }; +mathematica blank +mathematica comment (******************************************************************************) +mathematica comment (* Boundary conditions *) +mathematica comment (******************************************************************************) +mathematica blank +mathematica code boundaryCalc = +mathematica code { +mathematica code Name -> thorn <> "_boundary", +mathematica code Schedule -> {"IN MoL_PostStep"}, +mathematica code ConditionalOnKeyword -> {"my_boundary_condition", "Minkowski"}, +mathematica code Where -> BoundaryWithGhosts, +mathematica code Equations -> +mathematica code { +mathematica code phi -> IfThen[conformalMethod==CMW, 1, 0], +mathematica code gt[la,lb] -> KD[la,lb], +mathematica code trK -> 0, +mathematica code At[la,lb] -> 0, +mathematica code Xt[ua] -> 0, +mathematica code alpha -> 1, +mathematica code A -> 0, +mathematica code beta[ua] -> 0, +mathematica code B[ua] -> 0, +mathematica code IfCCZ4[Theta -> 0] +mathematica code } +mathematica code }; +mathematica blank +mathematica comment (******************************************************************************) +mathematica comment (* Constraint equations *) +mathematica comment (******************************************************************************) +mathematica blank +mathematica code constraintsCalc = +mathematica code { +mathematica code Name -> thorn <> "_constraints", +mathematica code Schedule -> Automatic, +mathematica code After -> "MoL_PostStep", +mathematica code Where -> Interior, +mathematica code Shorthands -> {detgt, ddetgt[la], gtu[ua,ub], Z[ua], +mathematica code Gt[ua,lb,lc], Gtl[la,lb,lc], Gtlu[la,lb,uc], Xtn[ua], +mathematica code e4phi, em4phi, +mathematica code g[la,lb], detg, gu[ua,ub], ddetg[la], G[ua,lb,lc], +mathematica code Rt[la,lb], Rphi[la,lb], R[la,lb], trR, Atm[ua,lb], +mathematica code gK[la,lb,lc], cdphi[la], cdphi2[la,lb], +mathematica code rho, S[la], fac1, fac2}, +mathematica code Equations -> +mathematica code { +mathematica code detgt -> 1 (* detgtExpr *), +mathematica code ddetgt[la] -> 0 (* ddetgtExpr[la] *), +mathematica code +mathematica comment (* This leads to simpler code... *) +mathematica code gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], +mathematica code Gtl[la,lb,lc] -> 1/2 +mathematica code (PD[gt[lb,la],lc] + PD[gt[lc,la],lb] - PD[gt[lb,lc],la]), +mathematica code Gtlu[la,lb,uc] -> gtu[uc,ud] Gtl[la,lb,ld], +mathematica code Gt[ua,lb,lc] -> gtu[ua,ud] Gtl[ld,lb,lc], +mathematica code +mathematica comment (* The conformal connection functions calculated from the conformal metric, +mathematica comment used instead of Xt where no derivatives of Xt are taken *) +mathematica code Xtn[ui] -> gtu[uj,uk] Gt[ui,lj,lk], +mathematica blank +mathematica code e4phi -> IfThen[conformalMethod==CMW, 1/phi^2, Exp[4 phi]], +mathematica code em4phi -> 1 / e4phi, +mathematica code g[la,lb] -> e4phi gt[la,lb], +mathematica code detg -> e4phi^3, +mathematica code gu[ua,ub] -> em4phi gtu[ua,ub], +mathematica blank +mathematica comment (* The Z quantities *) +mathematica code IfCCZ4[ +mathematica code Z[ud] -> (1/2) gu[ua,ud] (- PD[gt[la,lb],lc] gtu[ub,uc] + gt[la,lc] Xt[uc]) +mathematica code ], +mathematica code +mathematica comment (* PRD 62, 044034 (2000), eqn. (18) *) +mathematica code Rt[li,lj] -> - (1/2) gtu[ul,um] PD[gt[li,lj],ll,lm] +mathematica code + (1/2) gt[lk,li] PD[Xt[uk],lj] +mathematica code + (1/2) gt[lk,lj] PD[Xt[uk],li] +mathematica code + (1/2) Xtn[uk] Gtl[li,lj,lk] +mathematica code + (1/2) Xtn[uk] Gtl[lj,li,lk] +mathematica code + (+ Gt[uk,li,ll] Gtlu[lj,lk,ul] +mathematica code + Gt[uk,lj,ll] Gtlu[li,lk,ul] +mathematica code + Gt[uk,li,ll] Gtlu[lk,lj,ul]), +mathematica blank +mathematica comment (* From the long turducken paper. +mathematica comment This expression seems to give the same result as the one from 044034. *) +mathematica comment (* TODO: symmetrise correctly: (ij) = (1/2) [i+j] *) +mathematica comment (* +mathematica comment Rt[li,lj] -> - (1/2) gtu[uk,ul] PD[gt[li,lj],lk,ll] +mathematica comment + gt[lk,li] PD[Xt[uk],lj] + gt[lk,lj] PD[Xt[uk],li] +mathematica comment + gt[li,ln] Gt[un,lj,lk] gtu[um,ua] gtu[uk,ub] PD[gt[la,lb],lm] +mathematica comment + gt[lj,ln] Gt[un,li,lk] gtu[um,ua] gtu[uk,ub] PD[gt[la,lb],lm] +mathematica comment + gtu[ul,us] (+ 2 Gt[uk,ll,li] gt[lj,ln] Gt[un,lk,ls] +mathematica comment + 2 Gt[uk,ll,lj] gt[li,ln] Gt[un,lk,ls] +mathematica comment + Gt[uk,li,ls] gt[lk,ln] Gt[un,ll,lj]), +mathematica comment *) +mathematica blank +mathematica comment (* Below would be a straightforward calculation, +mathematica comment without taking any Gamma^i into account. +mathematica comment This expression gives a different answer! *) +mathematica comment (* +mathematica comment Rt[la,lb] -> + Gt[u1,l2,la] Gt[l1,lb,u2] - Gt[u1,la,lb] Gt[l1,l2,u2] +mathematica comment + 1/2 gtu[u1,u2] (- PD[gt[l1,l2],la,lb] + PD[gt[l1,la],l2,lb] +mathematica comment - PD[gt[la,lb],l1,l2] + PD[gt[l2,lb],l1,la]), +mathematica comment *) +mathematica blank +mathematica code fac1 -> IfThen[conformalMethod==CMW, -1/(2 phi), 1], +mathematica code cdphi[la] -> fac1 CDt[phi,la], +mathematica code fac2 -> IfThen[conformalMethod==CMW, 1/(2 phi^2), 0], +mathematica code cdphi2[la,lb] -> fac1 CDt[phi,la,lb] + fac2 CDt[phi,la] CDt[phi,lb], +mathematica blank +mathematica comment (* PRD 62, 044034 (2000), eqn. (15) *) +mathematica code Rphi[li,lj] -> - 2 cdphi2[lj,li] +mathematica code - 2 gt[li,lj] gtu[ul,un] cdphi2[ll,ln] +mathematica code + 4 cdphi[li] cdphi[lj] +mathematica code - 4 gt[li,lj] gtu[ul,un] cdphi[ln] cdphi[ll], +mathematica code +mathematica comment (* ddetg[la] -> PD[e4phi detg,la], *) +mathematica code ddetg[la] -> e4phi ddetgt[la] + 4 detgt e4phi PD[phi,la], +mathematica comment (* TODO: check this equation, maybe simplify it by omitting ddetg *) +mathematica code G[ua,lb,lc] -> Gt[ua,lb,lc] +mathematica code + 1/(2 detg) (+ KD[ua,lb] ddetg[lc] + KD[ua,lc] ddetg[lb] +mathematica code - (1/3) g[lb,lc] gu[ua,ud] ddetg[ld]), +mathematica code +mathematica code R[la,lb] -> + Rt[la,lb] + Rphi[la,lb], +mathematica blank +mathematica code IfCCZ4[ +mathematica code R[la,lb] -> R[la, lb] + (2/phi) (+ g[la,lc] Z[uc] PD[phi,lb] +mathematica code + g[lb,lc] Z[uc] PD[phi,la] - g[la,lb] Z[uc] PD[phi,lc]) +mathematica code + e4phi Z[uc] PD[gt[la,lb],lc] +mathematica code ], +mathematica blank +mathematica code trR -> gu[ua,ub] R[la,lb], +mathematica code +mathematica comment (* K[la,lb] -> e4phi At[la,lb] + (1/3) g[la,lb] trK, *) +mathematica comment (* Km[ua,lb] -> gu[ua,uc] K[lc,lb], *) +mathematica code Atm[ua,lb] -> gtu[ua,uc] At[lc,lb], +mathematica code +mathematica comment (* Matter terms *) +mathematica code +mathematica comment (* rho = n^a n^b T_ab *) +mathematica code rho -> 1/alpha^2 (T00 - 2 beta[ui] T0[li] + beta[ui] beta[uj] T[li,lj]), +mathematica code +mathematica comment (* S_i = -p^a_i n^b T_ab, where p^a_i = delta^a_i + n^a n_i *) +mathematica code S[li] -> -1/alpha (T0[li] - beta[uj] T[li,lj]), +mathematica code +mathematica comment (* Constraints *) +mathematica code +mathematica comment (* H -> trR - Km[ua,lb] Km[ub,la] + trK^2, *) +mathematica comment (* PRD 67, 084023 (2003), eqn. (19) *) +mathematica code H -> trR - Atm[ua,lb] Atm[ub,la] + (2/3) trK^2 - addMatter 16 Pi rho, +mathematica code +mathematica comment (* gK[la,lb,lc] -> CD[K[la,lb],lc], *) +mathematica comment (* gK[la,lb,lc] -> + 4 e4phi PD[phi,lc] At[la,lb] + e4phi CD[At[la,lb],lc] +mathematica comment + (1/3) g[la,lb] PD[trK,lc], +mathematica blank +mathematica comment M[la] -> gu[ub,uc] (gK[lc,la,lb] - gK[lc,lb,la]), *) +mathematica blank +mathematica code M[li] -> + gtu[uj,uk] (CDt[At[li,lj],lk] + 6 At[li,lj] cdphi[lk]) +mathematica code - (2/3) PD[trK,li] +mathematica code - addMatter 8 Pi S[li], +mathematica comment (* TODO: use PRD 67, 084023 (2003), eqn. (20) *) +mathematica code +mathematica comment (* det gamma-tilde *) +mathematica code cS -> Log[detgt], +mathematica code +mathematica comment (* Gamma constraint *) +mathematica code cXt[ua] -> gtu[ub,uc] Gt[ua,lb,lc] - Xt[ua], +mathematica code +mathematica comment (* trace A-tilde *) +mathematica code cA -> gtu[ua,ub] At[la,lb] +mathematica code } +mathematica code }; +mathematica blank +mathematica code constraintsCalc1 = PartialCalculation[constraintsCalc, "1", +mathematica code {}, +mathematica code { +mathematica code H +mathematica code }]; +mathematica blank +mathematica code constraintsCalc2 = PartialCalculation[constraintsCalc, "2", +mathematica code {}, +mathematica code { +mathematica code M[li], +mathematica code cS, +mathematica code cXt[ua], +mathematica code cA +mathematica code }]; +mathematica blank +mathematica comment (******************************************************************************) +mathematica comment (* Implementations *) +mathematica comment (******************************************************************************) +mathematica blank +mathematica code inheritedImplementations = +mathematica code Join[{"ADMBase"}, +mathematica code If [addMatter!=0, {"TmunuBase"}, {}]]; +mathematica blank +mathematica comment (******************************************************************************) +mathematica comment (* Parameters *) +mathematica comment (******************************************************************************) +mathematica blank +mathematica code inheritedKeywordParameters = {}; +mathematica blank +mathematica code extendedKeywordParameters = +mathematica code { +mathematica code { +mathematica code Name -> "ADMBase::evolution_method", +mathematica code AllowedValues -> {thorn} +mathematica code }, +mathematica code { +mathematica code Name -> "ADMBase::lapse_evolution_method", +mathematica code AllowedValues -> {thorn} +mathematica code }, +mathematica code { +mathematica code Name -> "ADMBase::shift_evolution_method", +mathematica code AllowedValues -> {thorn} +mathematica code }, +mathematica code { +mathematica code Name -> "ADMBase::dtlapse_evolution_method", +mathematica code AllowedValues -> {thorn} +mathematica code }, +mathematica code { +mathematica code Name -> "ADMBase::dtshift_evolution_method", +mathematica code AllowedValues -> {thorn} +mathematica code } +mathematica code }; +mathematica blank +mathematica code keywordParameters = +mathematica code { +mathematica code { +mathematica code Name -> "my_initial_data", +mathematica comment (* Visibility -> "restricted", *) +mathematica comment (* Description -> "ddd", *) +mathematica code AllowedValues -> {"ADMBase", "Minkowski"}, +mathematica code Default -> "ADMBase" +mathematica code }, +mathematica code { +mathematica code Name -> "my_initial_boundary_condition", +mathematica code Visibility -> "restricted", +mathematica comment (* Description -> "ddd", *) +mathematica code AllowedValues -> {"none"}, +mathematica code Default -> "none" +mathematica code }, +mathematica code { +mathematica code Name -> "my_rhs_boundary_condition", +mathematica code Visibility -> "restricted", +mathematica comment (* Description -> "ddd", *) +mathematica code AllowedValues -> {"none", "static", "radiative"}, +mathematica code Default -> "none" +mathematica code }, +mathematica code { +mathematica code Name -> "my_boundary_condition", +mathematica comment (* Visibility -> "restricted", *) +mathematica comment (* Description -> "ddd", *) +mathematica code AllowedValues -> {"none", "Minkowski"}, +mathematica code Default -> "none" +mathematica code }, +mathematica code { +mathematica code Name -> "calculate_ADMBase_variables_at", +mathematica code Visibility -> "restricted", +mathematica comment (* Description -> "ddd", *) +mathematica code AllowedValues -> {"MoL_PostStep", "CCTK_EVOL", "CCTK_ANALYSIS"}, +mathematica code Default -> "MoL_PostStep" +mathematica code }, +mathematica code { +mathematica code Name -> "UseSpatialBetaDriver_UNUSED", +mathematica code Visibility -> "restricted", +mathematica comment (* Description -> "ddd", *) +mathematica code AllowedValues -> {"no", "yes"}, +mathematica code Default -> "no" +mathematica code }, +mathematica code { +mathematica code Name -> "dt_lapse_shift_method", +mathematica code Description -> "Treatment of ADMBase dtlapse and dtshift", +mathematica code AllowedValues -> {"correct", +mathematica code "noLapseShiftAdvection" (* omit lapse and shift advection terms (faster) *) +mathematica code }, +mathematica code Default -> "correct" +mathematica code }, +mathematica code { +mathematica code Name -> "apply_dissipation", +mathematica code Description -> "Whether to apply dissipation to the RHSs", +mathematica code AllowedValues -> {"always", +mathematica code "never" (* yes and no keyword values confuse Cactus, and Kranc +mathematica comment doesn't support boolean parameters *) +mathematica code }, +mathematica code Default -> "never" +mathematica code }, +mathematica code { +mathematica code Name -> "RHS_split", +mathematica code Description -> "How to split RHS calculation", +mathematica code AllowedValues -> {"combined", +mathematica code "split At"}, +mathematica code Default -> "split At" +mathematica code }, +mathematica code { +mathematica code Name -> "advection_split", +mathematica code Description -> "How to split advection calculation", +mathematica code AllowedValues -> {"combined", +mathematica code "per variable"}, +mathematica code Default -> "combined" +mathematica code } +mathematica code }; +mathematica blank +mathematica code intParameters = +mathematica code { +mathematica code { +mathematica code Name -> harmonicN, +mathematica code Description -> "d/dt alpha = - f alpha^n K (harmonic=2, 1+log=1)", +mathematica code Default -> 2 +mathematica code }, +mathematica code { +mathematica code Name -> ShiftAlphaPower, +mathematica code Default -> 0 +mathematica code }, +mathematica code { +mathematica code Name -> conformalMethod, +mathematica code Description -> "Treatment of conformal factor", +mathematica code AllowedValues -> {{Value -> "0", Description -> "phi method"}, +mathematica code {Value -> "1", Description -> "W method"}}, +mathematica code Default -> 0 +mathematica code }, +mathematica code { +mathematica code Name -> fdOrder, +mathematica code Default -> derivOrder, +mathematica code AllowedValues -> {2,4,6,8} +mathematica code }, +mathematica code { +mathematica code Name -> harmonicShift, +mathematica code Description -> "Whether to use the harmonic shift", +mathematica code AllowedValues -> {{Value -> "0", Description -> "Gamma driver shift"}, +mathematica code {Value -> "1", Description -> "Harmonic shift"}}, +mathematica code Default -> 0 +mathematica code } +mathematica code }; +mathematica blank +mathematica code realParameters = +mathematica code { +mathematica code IfCCZ4[{ +mathematica code Name -> GammaShift, +mathematica code Description -> "Covariant shift term in Gamma", +mathematica code Default -> 0.5 +mathematica code }], +mathematica code IfCCZ4[{ +mathematica code Name -> dampk1, +mathematica code Description -> "CCZ4 damping term 1 for Theta and Z", +mathematica code Default -> 0 +mathematica code }], +mathematica code IfCCZ4[{ +mathematica code Name -> dampk2, +mathematica code Description -> "CCZ4 damping term 2 for Theta and Z", +mathematica code Default -> 0 +mathematica code }], +mathematica code { +mathematica code Name -> LapseACoeff, +mathematica code Description -> "Whether to evolve A in time", +mathematica code Default -> 0 +mathematica code }, +mathematica code { +mathematica code Name -> harmonicF, +mathematica code Description -> "d/dt alpha = - f alpha^n K (harmonic=1, 1+log=2)", +mathematica code Default -> 1 +mathematica code }, +mathematica code { +mathematica code Name -> AlphaDriver, +mathematica code Default -> 0 +mathematica code }, +mathematica code { +mathematica code Name -> ShiftBCoeff, +mathematica code Description -> "Whether to evolve B^i in time", +mathematica code Default -> 1 +mathematica code }, +mathematica code { +mathematica code Name -> ShiftGammaCoeff, +mathematica code Default -> 0 +mathematica code }, +mathematica code { +mathematica code Name -> BetaDriver, +mathematica code Default -> 0 +mathematica code }, +mathematica code { +mathematica code Name -> LapseAdvectionCoeff, +mathematica code Description -> "Factor in front of the lapse advection terms in 1+log", +mathematica code Default -> 1 +mathematica code }, +mathematica code { +mathematica code Name -> ShiftAdvectionCoeff, +mathematica code Description -> "Factor in front of the shift advection terms in gamma driver", +mathematica code Default -> 1 +mathematica code }, +mathematica code { +mathematica code Name -> MinimumLapse, +mathematica code Description -> "Minimum value of the lapse function", +mathematica code Default -> -1 +mathematica code }, +mathematica code { +mathematica code Name -> SpatialBetaDriverRadius, +mathematica code Description -> "Radius at which the BetaDriver starts to be reduced", +mathematica code AllowedValues -> {{Value -> "(0:*", Description -> "Positive"}}, +mathematica code Default -> 10^12 +mathematica code }, +mathematica code { +mathematica code Name -> SpatialShiftGammaCoeffRadius, +mathematica code Description -> "Radius at which the ShiftGammaCoefficient starts to be reduced", +mathematica code AllowedValues -> {{Value -> "(0:*", Description -> "Positive"}}, +mathematica code Default -> 10^12 +mathematica code }, +mathematica code { +mathematica code Name -> EpsDiss, +mathematica code Description -> "Dissipation strength", +mathematica code AllowedValues -> {{Value -> "(0:*", Description -> "Positive"}}, +mathematica code Default -> 0 +mathematica code } +mathematica code }; +mathematica blank +mathematica comment (******************************************************************************) +mathematica comment (* Construct the thorns *) +mathematica comment (******************************************************************************) +mathematica blank +mathematica code calculations = +mathematica code Join[ +mathematica code { +mathematica code initialCalc, +mathematica code convertFromADMBaseCalc, +mathematica code initGammaCalc, +mathematica code convertFromADMBaseGammaCalc, +mathematica code evolCalc, +mathematica code evolCalc1, evolCalc2, +mathematica code dissCalc, +mathematica code advectCalc, +mathematica comment (*advectCalcs,*) +mathematica code initRHSCalc, +mathematica code RHSStaticBoundaryCalc, +mathematica comment (* RHSRadiativeBoundaryCalc, *) +mathematica code enforceCalc, +mathematica code boundaryCalc, +mathematica code convertToADMBaseCalc, +mathematica code convertToADMBaseDtLapseShiftCalc, +mathematica code convertToADMBaseDtLapseShiftBoundaryCalc, +mathematica code convertToADMBaseFakeDtLapseShiftCalc, +mathematica comment (* constraintsCalc, *) +mathematica code constraintsCalc1, constraintsCalc2 +mathematica code }, +mathematica code advectCalcs +mathematica comment (*dissCalcs*) +mathematica code ]; +mathematica blank +mathematica code CreateKrancThornTT [groups, ".", thorn, +mathematica code Calculations -> calculations, +mathematica code DeclaredGroups -> declaredGroupNames, +mathematica code PartialDerivatives -> derivatives, +mathematica code EvolutionTimelevels -> evolutionTimelevels, +mathematica code DefaultEvolutionTimelevels -> 3, +mathematica code UseJacobian -> True, +mathematica code UseLoopControl -> True, +mathematica code UseVectors -> useVectors, +mathematica code UseOpenCL -> useOpenCL, +mathematica code InheritedImplementations -> inheritedImplementations, +mathematica code InheritedKeywordParameters -> inheritedKeywordParameters, +mathematica code ExtendedKeywordParameters -> extendedKeywordParameters, +mathematica code KeywordParameters -> keywordParameters, +mathematica code IntParameters -> intParameters, +mathematica code RealParameters -> realParameters +mathematica code ]; +mathematica blank +mathematica code ]; +mathematica blank +mathematica blank +mathematica blank +mathematica comment (******************************************************************************) +mathematica comment (* Options *) +mathematica comment (******************************************************************************) +mathematica blank +mathematica comment (* These are the arguments to createComment: +mathematica comment - derivative order: 2, 4, 6, 8, ... +mathematica comment - useJacobian: False or True +mathematica comment - split upwind derivatives: False or True +mathematica comment - use vectorisation: False or True +mathematica comment - use OpenCL: False or True +mathematica comment - timelevels: 2 or 3 +mathematica comment (keep this at 3; this is better chosen with a run-time parameter) +mathematica comment - matter: 0 or 1 +mathematica comment (matter seems cheap; it should be always enabled) +mathematica comment - thorn base name +mathematica comment *) +mathematica blank +mathematica code createCode[4, False, True, True , False, 3, 1, "BSSN"]; +mathematica code createCode[4, False, True, False, False, 3, 1, "BSSN"]; +mathematica code createCode[4, False, True, True , True , 3, 1, "BSSN"]; +mathematica blank +mathematica code createCode[4, False, True, True , False, 3, 1, "CCZ4"]; +mathematica blank \ No newline at end of file diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index 7566495..d01ac89 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -74,6 +74,7 @@ void test_detector_disambiguate_m() { ASSERT_DETECT(LANG_OBJECTIVE_C, "t2.m"); ASSERT_DETECT(LANG_OBJECTIVE_C, "TCPSocket.m"); ASSERT_DETECT(LANG_OBJECTIVE_C, "foo_objective_c.m"); + ASSERT_DETECT(LANG_MATHEMATICA, "foo_mathematica.m"); ASSERT_DETECT(LANG_MATLAB, "foo_matlab.m"); ASSERT_DETECT(LANG_OCTAVE, "foo_octave.m"); } diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index b4009c1..544ae87 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -123,6 +123,7 @@ void test_parser_verify_entity(SourceFile *sf, const char *entity, #include "parsers/test_logtalk.h" #include "parsers/test_lua.h" #include "parsers/test_make.h" +#include "parsers/test_mathematica.h" #include "parsers/test_matlab.h" #include "parsers/test_metafont.h" #include "parsers/test_metapost.h" @@ -306,6 +307,7 @@ void all_parser_tests() { all_logtalk_tests(); all_lua_tests(); all_make_tests(); + all_mathematica_tests(); all_matlab_tests(); all_metafont_tests(); all_metapost_tests(); diff --git a/test/unit/parsers/test_mathematica.h b/test/unit/parsers/test_mathematica.h new file mode 100644 index 0000000..855bd36 --- /dev/null +++ b/test/unit/parsers/test_mathematica.h @@ -0,0 +1,11 @@ + +void test_mathematica_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("mathematica", " (*comment*)"), + "comment", "(*comment*)" + ); +} + +void all_mathematica_tests() { + test_mathematica_comment_entities(); +} From 72859b9b597ea329ab40a13d289a9e68a904d3c6 Mon Sep 17 00:00:00 2001 From: Michael Homer Date: Fri, 30 Aug 2013 18:49:58 +1200 Subject: [PATCH 361/387] Add Grace language --- src/hash/extensions.gperf | 2 + src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 2 + src/languages.h | 1 + src/parsers/grace.rl | 113 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 119 insertions(+) create mode 100644 src/parsers/grace.rl diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index bfdc8b1..d54b2db 100755 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -85,6 +85,8 @@ gif, BINARY glsl, LANG_GLSL go, LANG_GOLANG groovy, LANG_GROOVY +grace, LANG_GRACE +grc, LANG_GRACE gs, LANG_GENIE gz, BINARY h, DISAMBIGUATE("h") diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index 62ca3b8..8b8226f 100755 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -48,6 +48,7 @@ fsharp, LANG_FSHARP, "F#", 0 genie, LANG_GENIE, "Genie", 0 glsl, LANG_GLSL, "OpenGL Shading Language", 0 golang, LANG_GOLANG, "Golang", 0 +grace, LANG_GRACE, "Grace", 0 groovy, LANG_GROOVY, "Groovy", 0 haml, LANG_HAML, "Haml", 1 haskell, LANG_HASKELL, "Haskell", 0 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index cfdd138..2e21369 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -35,6 +35,7 @@ #include "../parsers/fsharp.h" #include "../parsers/glsl.h" #include "../parsers/golang.h" +#include "../parsers/grace.h" #include "../parsers/groovy.h" #include "../parsers/haml.h" #include "../parsers/haskell.h" @@ -140,6 +141,7 @@ fsharp, parse_fsharp genie, parse_genie glsl, parse_glsl golang, parse_golang +grace, parse_grace groovy, parse_groovy haskell, parse_haskell haml, parse_haml diff --git a/src/languages.h b/src/languages.h index 0f23ef9..0049de2 100755 --- a/src/languages.h +++ b/src/languages.h @@ -49,6 +49,7 @@ #define LANG_GENIE "genie" #define LANG_GLSL "glsl" #define LANG_GOLANG "golang" +#define LANG_GRACE "grace" #define LANG_GROOVY "groovy" #define LANG_HASKELL "haskell" #define LANG_HAML "haml" diff --git a/src/parsers/grace.rl b/src/parsers/grace.rl new file mode 100644 index 0000000..daf60dd --- /dev/null +++ b/src/parsers/grace.rl @@ -0,0 +1,113 @@ +// grace.rl written by Michael Homer, based on shell.rl +// by Mitchell Foral. mitchellcaladbolgnet + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_GRACE_PARSER_H +#define OHCOUNT_GRACE_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *GRACE_LANG = LANG_GRACE; + +// the languages entities +const char *grace_entities[] = { + "space", "comment", "string", "any" +}; + +// constants associated with the entities +enum { + GRACE_SPACE = 0, GRACE_COMMENT, GRACE_STRING, GRACE_ANY +}; + +/*****************************************************************************/ + +%%{ + machine grace; + write data; + include common "common.rl"; + + # Line counting machine + + action grace_ccallback { + switch(entity) { + case GRACE_SPACE: + ls + break; + case GRACE_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(GRACE_LANG) + break; + case NEWLINE: + std_newline(GRACE_LANG) + } + } + + grace_comment = '//' @comment nonnewline*; + + grace_string = + '"' @enqueue @code ( + newline %{ entity = INTERNAL_NL; } %grace_ccallback + | + ws + | + [^\r\n\f\t "\\] @code + )* '"' @commit; + + grace_line := |* + spaces ${ entity = GRACE_SPACE; } => grace_ccallback; + grace_comment; + grace_string; + newline ${ entity = NEWLINE; } => grace_ccallback; + ^space ${ entity = GRACE_ANY; } => grace_ccallback; + *|; + + # Entity machine + + action grace_ecallback { + callback(GRACE_LANG, grace_entities[entity], cint(ts), cint(te), userdata); + } + + grace_comment_entity = '//' nonnewline*; + + grace_entity := |* + space+ ${ entity = GRACE_SPACE; } => grace_ecallback; + grace_comment_entity ${ entity = GRACE_COMMENT; } => grace_ecallback; + # TODO: + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with Grace code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_grace(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + %% write init; + cs = (count) ? grace_en_grace_line : grace_en_grace_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(GRACE_LANG) } +} + +#endif + +/*****************************************************************************/ From bba9f551023654690aadbf71c969d394dd51cc41 Mon Sep 17 00:00:00 2001 From: Michael Homer Date: Fri, 30 Aug 2013 19:08:41 +1200 Subject: [PATCH 362/387] Add test for Grace parsing --- test/expected_dir/grace.grace | 2 ++ test/src_dir/grace.grace | 2 ++ test/unit/detector_test.h | 1 + 3 files changed, 5 insertions(+) create mode 100644 test/expected_dir/grace.grace create mode 100644 test/src_dir/grace.grace diff --git a/test/expected_dir/grace.grace b/test/expected_dir/grace.grace new file mode 100644 index 0000000..bdff20b --- /dev/null +++ b/test/expected_dir/grace.grace @@ -0,0 +1,2 @@ +grace lcomment // Sample Grace code +grace lcode print "OK" diff --git a/test/src_dir/grace.grace b/test/src_dir/grace.grace new file mode 100644 index 0000000..0d500ff --- /dev/null +++ b/test/src_dir/grace.grace @@ -0,0 +1,2 @@ +// Sample Grace code +print "OK" diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index 7566495..7fc458a 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -145,6 +145,7 @@ void test_detector_detect_polyglot() { ASSERT_DETECT(LANG_FORTH, "forth.4th"); ASSERT_DETECT(LANG_FORTH, "forth.fr"); ASSERT_DETECT(LANG_FSHARP, "fs1.fs"); + ASSERT_DETECT(LANG_GRACE, "grace.grace"); ASSERT_DETECT(LANG_AUTOCONF, "m4.m4"); ASSERT_DETECT(LANG_NSIS, "foo.nsi"); ASSERT_DETECT(LANG_NSIS, "foo.nsh"); From fcc2afd6ee070cc524c315d8f30fe9d2f97ab7ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Mon, 16 Sep 2013 17:16:29 +0200 Subject: [PATCH 363/387] Add support for the Rust language. Rust is a programming language developed by Mozilla: www.rust-lang.org --- src/hash/extensions.gperf | 1 + src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 2 + src/languages.h | 1 + src/parsers/rust.rl | 158 ++++++++++++++++++++++++++++++++++++++++++++++ test/detect_files/rust.rs | 19 ++++++ test/expected_dir/rust.rs | 19 ++++++ test/src_dir/rust.rs | 19 ++++++ test/unit/detector_test.h | 5 ++ 9 files changed, 225 insertions(+) create mode 100644 src/parsers/rust.rl create mode 100644 test/detect_files/rust.rs create mode 100644 test/expected_dir/rust.rs create mode 100644 test/src_dir/rust.rs diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index bfdc8b1..7bac41b 100755 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -176,6 +176,7 @@ rhtml, LANG_RHTML rkt, LANG_RACKET rktd, LANG_RACKET rktl, LANG_RACKET +rs, LANG_RUST ru, LANG_RUBY s, LANG_ASSEMBLER sc, LANG_SCHEME diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index 62ca3b8..199360a 100755 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -91,6 +91,7 @@ rebol, LANG_REBOL, "REBOL", 0 rexx, LANG_REXX, "rexx", 0 rhtml, LANG_RHTML, "", 0 ruby, LANG_RUBY, "Ruby", 0 +rust, LANG_RUST, "Rust", 0 scala, LANG_SCALA, "Scala", 0 scheme, LANG_SCHEME, "Scheme", 0 scilab, LANG_SCILAB, "Scilab", 0 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index cfdd138..f362d80 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -75,6 +75,7 @@ #include "../parsers/rebol.h" #include "../parsers/rexx.h" #include "../parsers/ruby.h" +#include "../parsers/rust.h" #include "../parsers/rhtml.h" #include "../parsers/scala.h" #include "../parsers/scilab.h" @@ -183,6 +184,7 @@ rebol, parse_rebol rexx, parse_rexx rhtml, parse_rhtml ruby, parse_ruby +rust, parse_rust scala, parse_scala scheme, parse_scheme scilab, parse_scilab diff --git a/src/languages.h b/src/languages.h index 0f23ef9..0b65bba 100755 --- a/src/languages.h +++ b/src/languages.h @@ -92,6 +92,7 @@ #define LANG_REXX "rexx" #define LANG_RHTML "rhtml" #define LANG_RUBY "ruby" +#define LANG_RUST "rust" #define LANG_SCALA "scala" #define LANG_SCHEME "scheme" #define LANG_SCILAB "scilab" diff --git a/src/parsers/rust.rl b/src/parsers/rust.rl new file mode 100644 index 0000000..f11140c --- /dev/null +++ b/src/parsers/rust.rl @@ -0,0 +1,158 @@ +// rust.rl written by Sébastien Crozet +// Inpired by golang.rl + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_RUST_PARSER_H +#define OHCOUNT_RUST_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *RUST_LANG = LANG_RUST; + +// the languages entities +const char *rust_entities[] = { + "space", "comment", "string", "number", + "keyword", "identifier", "operator", "any" +}; + +// constants associated with the entities +enum { + RUST_SPACE = 0, RUST_COMMENT, RUST_STRING, RUST_NUMBER, + RUST_KEYWORD, RUST_IDENTIFIER, RUST_OPERATOR, RUST_ANY +}; + +/*****************************************************************************/ + +%%{ + machine rust; + write data; + include common "common.rl"; + + # Line counting machine + + action rust_ccallback { + switch(entity) { + case RUST_SPACE: + ls + break; + case RUST_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(RUST_LANG) + break; + case NEWLINE: + std_newline(RUST_LANG) + } + } + + rust_line_comment = + '//' @comment ( + escaped_newline %{ entity = INTERNAL_NL; } %rust_ccallback + | + ws + | + (nonnewline - ws) @comment + )*; + rust_block_comment = + '/*' @comment ( + newline %{ entity = INTERNAL_NL; } %rust_ccallback + | + ws + | + (nonnewline - ws) @comment + )* :>> '*/'; + rust_comment = rust_line_comment | rust_block_comment; + + rust_dq_str = + '"' @code ( + escaped_newline %{ entity = INTERNAL_NL; } %rust_ccallback + | + ws + | + [^\t "\\] @code + | + '\\' nonnewline @code + )* '"'; + rust_string = rust_dq_str; + + rust_line := |* + spaces ${ entity = RUST_SPACE; } => rust_ccallback; + rust_comment; + rust_string; + newline ${ entity = NEWLINE; } => rust_ccallback; + ^space ${ entity = RUST_ANY; } => rust_ccallback; + *|; + + # Entity machine + + action rust_ecallback { + callback(RUST_LANG, rust_entities[entity], cint(ts), cint(te), userdata); + } + + rust_line_comment_entity = '//' (escaped_newline | nonnewline)*; + rust_block_comment_entity = '/*' any* :>> '*/'; + rust_comment_entity = rust_line_comment_entity | rust_block_comment_entity; + + rust_string_entity = dq_str_with_escapes; + + rust_number_entity = + float | f32 | f64 | uint | int | u8 | u16 | u32 | u64 | i8 | i16 | i32 | + i64; + + rust_identifier_entity = (alpha | '_') (alnum | '_')*; + + rust_keyword_entity = + 'as' | 'break' | 'do' | 'else' | 'enum' | 'extern' | 'false' | + 'fn' | 'for' | 'if' | 'impl' | 'in' | 'let' | 'loop' | 'match' | 'mod' | + 'mut' | 'priv' | 'pub' | 'ref' | 'return' | 'self' | 'static' | 'struct' | + 'super' | 'true' | 'trait' | 'type' | 'unsafe' | 'use' | 'while'; + + rust_operator_entity = [+\-/*%<>!=^&|?~:;.,()\[\]{}@]; + + rust_entity := |* + space+ ${ entity = RUST_SPACE; } => rust_ecallback; + rust_comment_entity ${ entity = RUST_COMMENT; } => rust_ecallback; + rust_string_entity ${ entity = RUST_STRING; } => rust_ecallback; + rust_number_entity ${ entity = RUST_NUMBER; } => rust_ecallback; + rust_identifier_entity ${ entity = RUST_IDENTIFIER; } => rust_ecallback; + rust_keyword_entity ${ entity = RUST_KEYWORD; } => rust_ecallback; + rust_operator_entity ${ entity = RUST_OPERATOR; } => rust_ecallback; + ^(space | digit) ${ entity = RUST_ANY; } => rust_ecallback; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with C/C++ code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_rust(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + %% write init; + cs = (count) ? rust_en_rust_line : rust_en_rust_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(RUST_LANG) } +} + +const char *ORIG_RUST_LANG = LANG_RUST; + +#endif + +/*****************************************************************************/ diff --git a/test/detect_files/rust.rs b/test/detect_files/rust.rs new file mode 100644 index 0000000..812fa90 --- /dev/null +++ b/test/detect_files/rust.rs @@ -0,0 +1,19 @@ +/* + * This is the example given by www.rust-lang.org + */ +fn main() { + let nums = [0, 1, 2, 3]; + let noms = ["Tim", "Eston", "Aaron", "Ben"]; + + let mut evens = nums.iter().filter(|&x| x % 2 == 0); + + // This for loop works with rust 0.7 only. + for evens.advance |&num| { + do spawn { + let msg = fmt!("%s says hello from a lightweight thread!", + noms[num]); + println(msg); + } + } +} + diff --git a/test/expected_dir/rust.rs b/test/expected_dir/rust.rs new file mode 100644 index 0000000..0d4d04c --- /dev/null +++ b/test/expected_dir/rust.rs @@ -0,0 +1,19 @@ +rust comment /* +rust comment * This is the example given by www.rust-lang.org +rust comment */ +rust code fn main() { +rust code let nums = [0, 1, 2, 3]; +rust code let noms = ["Tim", "Eston", "Aaron", "Ben"]; +rust blank +rust code let mut evens = nums.iter().filter(|&x| x % 2 == 0); +rust blank +rust comment // This for loop works with rust 0.7 only. +rust code for evens.advance |&num| { +rust code do spawn { +rust code let msg = fmt!("%s says hello from a lightweight thread!", +rust code noms[num]); +rust code println(msg); +rust code } +rust code } +rust code } +rust blank diff --git a/test/src_dir/rust.rs b/test/src_dir/rust.rs new file mode 100644 index 0000000..812fa90 --- /dev/null +++ b/test/src_dir/rust.rs @@ -0,0 +1,19 @@ +/* + * This is the example given by www.rust-lang.org + */ +fn main() { + let nums = [0, 1, 2, 3]; + let noms = ["Tim", "Eston", "Aaron", "Ben"]; + + let mut evens = nums.iter().filter(|&x| x % 2 == 0); + + // This for loop works with rust 0.7 only. + for evens.advance |&num| { + do spawn { + let msg = fmt!("%s says hello from a lightweight thread!", + noms[num]); + println(msg); + } + } +} + diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index 7566495..be855b3 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -208,6 +208,10 @@ void test_detector_genie(){ ASSERT_DETECT(LANG_GENIE, "client-osx.gs"); } +void test_detector_rust(){ + ASSERT_DETECT(LANG_RUST, "rust.rs"); +} + void test_non_existent_file(){ ASSERT_NODETECT("xxx_non_exists_xxxi.pp"); } @@ -232,5 +236,6 @@ void all_detector_tests() { test_detector_emacs_mode(); test_detector_puppet(); test_detector_genie(); + test_detector_rust(); test_non_existent_file(); } From cd81878ffe11003f3f88a82c1c8e135fcbe651a4 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Fri, 6 Jan 2012 16:12:28 -0800 Subject: [PATCH 364/387] OTWO-1206 Updates SWIG bindings to Ruby 1.9.2 - Requires SWIG 2.0.4 (SWIG 1.3 is not compatible with Ruby 1.9.2) This updates the SWIG bindings only. This code tree does not build: - Build fails for me when using RVM Ruby 1.9.2 because 'ruby.h' and 'config.h' headers cannot be found. I am currenty working around this by manually placing absolute paths in the build script. - test/unit/ruby/source_file_test.rb is currently failing because the round trip from Ruby -> C -> Ruby causes the string encoding metadata to be lost. UTF-8 input strings are output with identical content bits, but are marked as ASCII-8BIT. --- ruby/ohcount.i | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ruby/ohcount.i b/ruby/ohcount.i index dc6cf9c..08d44f0 100644 --- a/ruby/ohcount.i +++ b/ruby/ohcount.i @@ -12,8 +12,8 @@ %typemap(in) (register const char *str, register unsigned int len) { Check_Type($input, T_STRING); - $1 = STR2CSTR($input); - $2 = RSTRING($input)->len; + $1 = StringValuePtr($input); + $2 = RSTRING_LEN($input); }; %typemap(out) char ** { @@ -111,9 +111,9 @@ } #if defined(SWIGRUBY) void set_filenames(VALUE filenames) { - int i, length = RARRAY(filenames)->len; + int i, length = RARRAY_LEN(filenames); char **fnames = calloc(length + 1, sizeof(char *)); - VALUE *iter = RARRAY(filenames)->ptr; + VALUE *iter = RARRAY_PTR(filenames); for (i = 0; i < length; i++, iter++) fnames[i] = StringValuePtr(*iter); self->filenames = fnames; @@ -124,10 +124,10 @@ VALUE val; val = rb_hash_aref(opt_hash, ID2SYM(rb_intern("contents"))); if (val && rb_type(val) == T_STRING) - ohcount_sourcefile_set_contents(sourcefile, STR2CSTR(val)); + ohcount_sourcefile_set_contents(sourcefile, StringValuePtr(val)); val = rb_hash_aref(opt_hash, ID2SYM(rb_intern("file_location"))); if (val && rb_type(val) == T_STRING) - ohcount_sourcefile_set_diskpath(sourcefile, STR2CSTR(val)); + ohcount_sourcefile_set_diskpath(sourcefile, StringValuePtr(val)); val = rb_hash_aref(opt_hash, ID2SYM(rb_intern("filenames"))); if (val && rb_type(val) == T_ARRAY) SourceFile_set_filenames(sourcefile, val); @@ -214,12 +214,12 @@ static VALUE rb_add_directory(VALUE directory, SourceFileList *list) { if (directory && rb_type(directory) == T_STRING) - ohcount_sourcefile_list_add_directory(list, STR2CSTR(directory)); + ohcount_sourcefile_list_add_directory(list, StringValuePtr(directory)); return Qnil; } static VALUE rb_add_file(VALUE file, SourceFileList *list) { if (file && rb_type(file) == T_STRING) - ohcount_sourcefile_list_add_file(list, STR2CSTR(file)); + ohcount_sourcefile_list_add_file(list, StringValuePtr(file)); return Qnil; } SourceFileList(VALUE opt_hash=NULL) { From 9bd0540ccc7a1d920e9f7e75a38233e6b413a120 Mon Sep 17 00:00:00 2001 From: Robin Luckey Date: Mon, 9 Jan 2012 08:44:25 -0800 Subject: [PATCH 365/387] OTWO-1213 Works around lost encoding in Ruby/C binding layer When a Ruby 1.9.2 string is passed to the C code, the associated encoding metadata is lost. When this same string is then returned from C back to Ruby, an arbitrary, mismatched encoding is applied to replace the lost one. This means that a string becomes garbled in the round trip. The bits don't change, but the encoding is lost. The correct fix would be to preserve the encoding metadata in the C layer. The easier fix is to replace the lost encoding with a more likely match, which is what I've done in this patch. When the C code returns a string, we apply the Ruby runtime's current default encoding, which is highly likely to be the encoding originally discarded. --- ruby/ohcount.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/ohcount.rb b/ruby/ohcount.rb index c9f0b43..2e5e665 100644 --- a/ruby/ohcount.rb +++ b/ruby/ohcount.rb @@ -12,7 +12,7 @@ class SourceFile def file_location=(value) set_diskpath(value) end def file_location() diskpath() end def filenames=(value) set_filenames(value) end - def contents() get_contents() end + def contents() get_contents().force_encoding(Encoding.default_external) end def polyglot() get_language() end def language_breakdowns From 41bc35a75753fcfcb2b342d05d6618f0c6d1f7cb Mon Sep 17 00:00:00 2001 From: Sathishkumar Natesan Date: Mon, 30 Sep 2013 15:19:38 +0530 Subject: [PATCH 366/387] Update build script to include appropriate ruby header file * With ruby 1.9.x the location of ruby.h and config.h have changed * This patch tries to load include the appropriate file paths while compiling the c code based on the installed ruby version * Tested on Ubuntu 12.04 with ruby 1.8.7 and 1.9.3 * Remove reference to the deprecated `Config` module --- .gitignore | 2 ++ build | 16 +++++++++++++++- ruby/print_arch | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 7573c6f..8f9e9b2 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ ruby/ohcount_wrap.c test/unit/run_tests.dSYM/ build-python/ python/ohcount.py +.rvmrc +.ruby-version diff --git a/build b/build index cc696ac..f6d2b21 100755 --- a/build +++ b/build @@ -114,13 +114,27 @@ run_test_suite() sh -c "cd test/unit/ && ./run_tests" } +# ruby header file and config file location has changed in ruby 1.9.x +ruby_version=`ruby -rmkmf -e 'print RbConfig::expand(CONFIG["ruby_version"])'` + +if [ $ruby_version == "1.8" ] +then + RUBY_HEADER_DIR=`ruby -rmkmf -e 'print Config::expand(CONFIG["archdir"])'` + RUBY_CONFIG_DIR= +elif [ $ruby_version == "1.9.1" ] +then + RUBY_HEADER_DIR=`ruby -rmkmf -e 'print RbConfig::expand(CONFIG["rubyhdrdir"])'` + rbconfig_arch=`ruby -rmkmf -e 'print RbConfig::expand(CONFIG["arch"])'` + RUBY_CONFIG_DIR="$RUBY_HEADER_DIR/$rbconfig_arch" +fi + build_ruby_bindings() { echo "Generating Ruby bindings for $arch" sh -c "swig -ruby -o ruby/ohcount_wrap.c ruby/ohcount.i" || exit 1 mkdir -p ruby/$arch sh -c "$cc $RB_SHARED ruby/ohcount_wrap.c $files -o ruby/$arch/$RB_SHARED_NAME \ - -I`ruby -rmkmf -e 'print Config::expand(CONFIG["archdir"])'` \ + -I$RUBY_HEADER_DIR -I$RUBY_CONFIG_DIR \ -lpcre -lmagic" || exit 1 sh -c "cd test/unit/ruby && ruby ruby_test.rb" || exit 1 } diff --git a/ruby/print_arch b/ruby/print_arch index 48322f4..c42e70a 100755 --- a/ruby/print_arch +++ b/ruby/print_arch @@ -1,7 +1,7 @@ #!/usr/bin/env ruby require 'mkmf' -arch = Config::expand(CONFIG["arch"]) +arch = RbConfig::expand(CONFIG["arch"]) distro = if File.exist?("/etc/issue") # this is "", "CentOS" or "Ubuntu" From 1cfa8907164c5f38620e470dccf6f48e0cb088f7 Mon Sep 17 00:00:00 2001 From: Sathishkumar Natesan Date: Tue, 1 Oct 2013 10:21:25 +0530 Subject: [PATCH 367/387] ruby 1.8.7 BC patch - Force encoding only for ruby 1.9 --- ruby/ohcount.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ruby/ohcount.rb b/ruby/ohcount.rb index 2e5e665..a0c3116 100644 --- a/ruby/ohcount.rb +++ b/ruby/ohcount.rb @@ -12,9 +12,14 @@ class SourceFile def file_location=(value) set_diskpath(value) end def file_location() diskpath() end def filenames=(value) set_filenames(value) end - def contents() get_contents().force_encoding(Encoding.default_external) end def polyglot() get_language() end + def contents + data = get_contents() + return data unless data.respond_to?(:force_encoding) + data.force_encoding(Encoding.default_external) + end + def language_breakdowns list = get_parsed_language_list() return array_from_list(list, :pl) From 9520186ad2f012403b7d79408ead313042596dd6 Mon Sep 17 00:00:00 2001 From: Sathishkumar Natesan Date: Thu, 3 Oct 2013 17:53:32 +0530 Subject: [PATCH 368/387] Fix deprecations and errors for SWIG 2.0.11 Extending a `struct` with its `typedef` name is deprecated as of SWIG 2.0.5. We should use the struct name directly, even for constructors and destructors Its not applicable for anonymous structs (of-course) --- ruby/ohcount.i | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ruby/ohcount.i b/ruby/ohcount.i index 08d44f0..38212fa 100644 --- a/ruby/ohcount.i +++ b/ruby/ohcount.i @@ -60,7 +60,7 @@ } } -%extend LocList { +%extend LocListItem { int code() { return ohcount_loc_list_code(self); } @@ -209,7 +209,7 @@ } }; -%extend SourceFileList { +%extend SourceFileListItem { #if defined(SWIGRUBY) static VALUE rb_add_directory(VALUE directory, SourceFileList *list) { @@ -222,23 +222,23 @@ ohcount_sourcefile_list_add_file(list, StringValuePtr(file)); return Qnil; } - SourceFileList(VALUE opt_hash=NULL) { + SourceFileListItem(VALUE opt_hash=NULL) { SourceFileList *list = ohcount_sourcefile_list_new(); if (opt_hash) { VALUE val; val = rb_hash_aref(opt_hash, ID2SYM(rb_intern("paths"))); if (val && rb_type(val) == T_ARRAY) - rb_iterate(rb_each, val, SourceFileList_rb_add_directory, (VALUE)list); + rb_iterate(rb_each, val, SourceFileListItem_rb_add_directory, (VALUE)list); val = rb_hash_aref(opt_hash, ID2SYM(rb_intern("files"))); if (val && rb_type(val) == T_ARRAY) - rb_iterate(rb_each, val, SourceFileList_rb_add_file, (VALUE)list); + rb_iterate(rb_each, val, SourceFileListItem_rb_add_file, (VALUE)list); } return list; } #elif defined(SWIGPYTHON) - SourceFileList(PyObject *args) { + SourceFileListItem(PyObject *args) { SourceFileList *list = ohcount_sourcefile_list_new(); if (args) { PyObject *val; @@ -279,7 +279,7 @@ #endif - ~SourceFileList() { + ~SourceFileListItem() { ohcount_sourcefile_list_free(self); } void add_file(const char *filepath) { From dea2deef2d7f4159e1450a8e4170e84c1e1b532b Mon Sep 17 00:00:00 2001 From: Sathishkumar Natesan Date: Thu, 3 Oct 2013 19:28:16 +0530 Subject: [PATCH 369/387] Update README for ruby 1.9.3 upgrade *** Breaks BACKWARD COMPATIBILITY *** as ruby 1.9.3 requires SWIG 2.0 and the latter is not backward compatible with its older versions --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index edec965..b48ac45 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ environments should also work, but your mileage may vary. Ohcount does not support Windows. -Ohcount targets Ruby 1.8.7. The build script requires a bash shell. You +Ohcount targets Ruby 1.9.3. The build script requires a bash shell. You also need a C compiler to build the native extensions. Source Code @@ -64,7 +64,7 @@ Building Ohcount ---------------- You will need ragel 6.3 or higher, bash, pcre, magic, gcc (version 4.1.2 or greater) -and SWIG. Once you have them, go to the top directory of ohcount and run +and SWIG (2.0.11). Once you have them, go to the top directory of ohcount and run ``` ./build From 77429fd1fd957224412ca0e943b15c8de26c07a9 Mon Sep 17 00:00:00 2001 From: Sathishkumar Natesan Date: Mon, 7 Oct 2013 18:35:56 +0530 Subject: [PATCH 370/387] Remove 1.8.7 backward compatibility patches We are OK with ending the support with 1.8.7. --- build | 16 +++------------- ruby/ohcount.rb | 1 - 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/build b/build index f6d2b21..d3d79c0 100755 --- a/build +++ b/build @@ -114,19 +114,9 @@ run_test_suite() sh -c "cd test/unit/ && ./run_tests" } -# ruby header file and config file location has changed in ruby 1.9.x -ruby_version=`ruby -rmkmf -e 'print RbConfig::expand(CONFIG["ruby_version"])'` - -if [ $ruby_version == "1.8" ] -then - RUBY_HEADER_DIR=`ruby -rmkmf -e 'print Config::expand(CONFIG["archdir"])'` - RUBY_CONFIG_DIR= -elif [ $ruby_version == "1.9.1" ] -then - RUBY_HEADER_DIR=`ruby -rmkmf -e 'print RbConfig::expand(CONFIG["rubyhdrdir"])'` - rbconfig_arch=`ruby -rmkmf -e 'print RbConfig::expand(CONFIG["arch"])'` - RUBY_CONFIG_DIR="$RUBY_HEADER_DIR/$rbconfig_arch" -fi +RUBY_HEADER_DIR=`ruby -rmkmf -e 'print RbConfig::expand(CONFIG["rubyhdrdir"])'` +rbconfig_arch=`ruby -rmkmf -e 'print RbConfig::expand(CONFIG["arch"])'` +RUBY_CONFIG_DIR="$RUBY_HEADER_DIR/$rbconfig_arch" build_ruby_bindings() { diff --git a/ruby/ohcount.rb b/ruby/ohcount.rb index a0c3116..7596a69 100644 --- a/ruby/ohcount.rb +++ b/ruby/ohcount.rb @@ -16,7 +16,6 @@ def polyglot() get_language() end def contents data = get_contents() - return data unless data.respond_to?(:force_encoding) data.force_encoding(Encoding.default_external) end From 717d0a367463f6e30a18ef230d6669a1cfba35a3 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 25 Oct 2013 08:26:57 -0700 Subject: [PATCH 371/387] Add support for the AMPL language --- src/detector.c | 64 +++++++++++++++++++++++++ src/hash/disambiguatefuncs.gperf | 4 ++ src/hash/extensions.gperf | 5 +- src/hash/languages.gperf | 1 + src/hash/parsers.gperf | 2 + src/languages.h | 1 + src/parsers/ampl.rl | 101 +++++++++++++++++++++++++++++++++++++++ test/detect_files/ampl.dat | 2 + test/detect_files/ampl.mod | 3 ++ test/detect_files/binary.dat | 1 + test/detect_files/foo.run | 2 + test/detect_files/modula2.mod | 6 +++ test/unit/detector_test.h | 18 +++++++ test/unit/parser_test.h | 2 + test/unit/parsers/test_ampl.h | 19 ++++++++ 15 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 src/parsers/ampl.rl create mode 100644 test/detect_files/ampl.dat create mode 100644 test/detect_files/ampl.mod create mode 100644 test/detect_files/binary.dat create mode 100644 test/detect_files/foo.run create mode 100644 test/detect_files/modula2.mod create mode 100644 test/unit/parsers/test_ampl.h diff --git a/src/detector.c b/src/detector.c index a3e8602..c88f9a3 100644 --- a/src/detector.c +++ b/src/detector.c @@ -376,6 +376,41 @@ const char *disambiguate_cs(SourceFile *sourcefile) { return LANG_CSHARP; } +const char *disambiguate_dat(SourceFile *sourcefile) { + char *p = ohcount_sourcefile_get_contents(sourcefile); + char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); + for (; p < eof; p++) { + switch (*p) { + case ' ': + case '\t': + case '\n': + case '\r': + break; + case '/': + if (p[1] == '*') // AMPL comment + return LANG_AMPL; + return NULL; + case '#': + return LANG_AMPL; // AMPL comment + case 'd': + if (strncmp(p, "data", 4) == 0) // AMPL data statement + return LANG_AMPL; + return BINARY; + case 'p': + if (strncmp(p, "param", 5) == 0) // AMPL param statement + return LANG_AMPL; + return BINARY; + case 's': + if (strncmp(p, "set", 3) == 0) // AMPL set statement + return LANG_AMPL; + return BINARY; + default: + return BINARY; + } + } + return NULL; // only blanks +} + const char *disambiguate_def(SourceFile *sourcefile) { char *p = ohcount_sourcefile_get_contents(sourcefile); char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); @@ -767,6 +802,35 @@ const char *disambiguate_m(SourceFile *sourcefile) { return octave_syntax_detected ? LANG_OCTAVE : LANG_MATLAB; } +const char *disambiguate_mod(SourceFile *sourcefile) { + char *p = ohcount_sourcefile_get_contents(sourcefile); + char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); + for (; p < eof; p++) { + switch (*p) { + case ' ': + case '\t': + case '\n': + case '\r': + break; + case '(': + if (p[1] == '*') // Modula-2 comment + return LANG_MODULA2; + return NULL; + case 'I': + if (strncmp(p, "IMPLEMENTATION", 14) == 0) // Modula-2 "IMPLEMENTATION MODULE" + return LANG_MODULA2; + return NULL; + case 'M': + if (strncmp(p, "MODULE", 6) == 0) // Modula-2 "MODULE" + return LANG_MODULA2; + return NULL; + default: + return LANG_AMPL; + } + } + return NULL; // only blanks +} + #include // strnlen is not available on OS X, so we roll our own diff --git a/src/hash/disambiguatefuncs.gperf b/src/hash/disambiguatefuncs.gperf index d422213..a6dd1b8 100644 --- a/src/hash/disambiguatefuncs.gperf +++ b/src/hash/disambiguatefuncs.gperf @@ -7,12 +7,14 @@ const char *disambiguate_asx(SourceFile *sourcefile); const char *disambiguate_b(SourceFile *sourcefile); const char *disambiguate_basic(SourceFile *sourcefile); const char *disambiguate_cs(SourceFile *sourcefile); +const char *disambiguate_dat(SourceFile *sourcefile); const char *disambiguate_def(SourceFile *sourcefile); const char *disambiguate_fortran(SourceFile *sourcefile); const char *disambiguate_h(SourceFile *sourcefile); const char *disambiguate_in(SourceFile *sourcefile); const char *disambiguate_inc(SourceFile *sourcefile); const char *disambiguate_m(SourceFile *sourcefile); +const char *disambiguate_mod(SourceFile *sourcefile); const char *disambiguate_pl(SourceFile *sourcefile); const char *disambiguate_pp(SourceFile *sourcefile); const char *disambiguate_pro(SourceFile *sourcefile); @@ -26,12 +28,14 @@ asx, disambiguate_asx b, disambiguate_b basic, disambiguate_basic cs, disambiguate_cs +dat, disambiguate_dat def, disambiguate_def fortran, disambiguate_fortran h, disambiguate_h in, disambiguate_in inc, disambiguate_inc m, disambiguate_m +mod, disambiguate_mod pl, disambiguate_pl pp, disambiguate_pp pro, disambiguate_pro diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index bfdc8b1..4ddd3c7 100755 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -50,7 +50,7 @@ ctp, LANG_PHP cu, LANG_CUDA cxx, LANG_CPP d, LANG_DMD -dat, BINARY +dat, DISAMBIGUATE("dat") def, DISAMBIGUATE("def") di, LANG_DMD doc, BINARY @@ -126,7 +126,7 @@ ml, LANG_OCAML ml4, LANG_OCAML mli, LANG_OCAML mm, LANG_OBJECTIVE_C -mod, LANG_MODULA2 +mod, DISAMBIGUATE("mod") mov, BINARY mp, LANG_METAPOST_WITH_TEX mp3, BINARY @@ -177,6 +177,7 @@ rkt, LANG_RACKET rktd, LANG_RACKET rktl, LANG_RACKET ru, LANG_RUBY +run, LANG_AMPL s, LANG_ASSEMBLER sc, LANG_SCHEME scala, LANG_SCALA diff --git a/src/hash/languages.gperf b/src/hash/languages.gperf index 62ca3b8..16af5a1 100755 --- a/src/hash/languages.gperf +++ b/src/hash/languages.gperf @@ -5,6 +5,7 @@ struct LanguageMap; %% actionscript, LANG_ACTIONSCRIPT, "ActionScript", 0 ada, LANG_ADA, "Ada", 0 +ampl, LANG_AMPL, "AMPL", 0 assembler, LANG_ASSEMBLER, "Assembler", 0 augeas, LANG_AUGEAS, "Augeas", 0 autoconf, LANG_AUTOCONF, "Autoconf", 2 diff --git a/src/hash/parsers.gperf b/src/hash/parsers.gperf index cfdd138..2b4cf5f 100644 --- a/src/hash/parsers.gperf +++ b/src/hash/parsers.gperf @@ -1,6 +1,7 @@ %{ #include "../parsers/actionscript.h" #include "../parsers/ada.h" +#include "../parsers/ampl.h" #include "../parsers/assembler.h" #include "../parsers/augeas.h" #include "../parsers/autoconf.h" @@ -99,6 +100,7 @@ struct ParserMap { const char *key; void (*parser)(char *, int, int, void(*) (co %% actionscript, parse_actionscript ada, parse_ada +ampl, parse_ampl assembler, parse_assembler augeas, parse_augeas autoconf, parse_autoconf diff --git a/src/languages.h b/src/languages.h index 0f23ef9..adf4d93 100755 --- a/src/languages.h +++ b/src/languages.h @@ -8,6 +8,7 @@ #define LANG_ACTIONSCRIPT "actionscript" #define LANG_ADA "ada" +#define LANG_AMPL "ampl" #define LANG_ASSEMBLER "assembler" #define LANG_AUGEAS "augeas" #define LANG_AUTOCONF "autoconf" diff --git a/src/parsers/ampl.rl b/src/parsers/ampl.rl new file mode 100644 index 0000000..6a92d3a --- /dev/null +++ b/src/parsers/ampl.rl @@ -0,0 +1,101 @@ +// ampl.rl written by Victor Zverovich. victor.zverovich@gmail.com + +/************************* Required for every parser *************************/ +#ifndef OHCOUNT_AMPL_PARSER_H +#define OHCOUNT_AMPL_PARSER_H + +#include "../parser_macros.h" + +// the name of the language +const char *AMPL_LANG = LANG_AMPL; + +// the languages entities +const char *ampl_entities[] = { + "space", "comment", "any" +}; + +// constants associated with the entities +enum { + AMPL_SPACE = 0, AMPL_COMMENT, AMPL_ANY +}; + +/*****************************************************************************/ + +%%{ + machine ampl; + write data; + include common "common.rl"; + + # Line counting machine + + action ampl_ccallback { + switch(entity) { + case AMPL_SPACE: + ls + break; + case AMPL_ANY: + code + break; + case INTERNAL_NL: + std_internal_newline(AMPL_LANG) + break; + case NEWLINE: + std_newline(AMPL_LANG) + } + } + + ampl_comment = '#' @comment nonnewline*; + + ampl_line := |* + spaces ${ entity = AMPL_SPACE; } => ampl_ccallback; + ampl_comment; + newline ${ entity = NEWLINE; } => ampl_ccallback; + ^space ${ entity = AMPL_ANY; } => ampl_ccallback; + *|; + + # Entity machine + + action ampl_ecallback { + callback(AMPL_LANG, ampl_entities[entity], cint(ts), cint(te), userdata); + } + + ampl_comment_entity = '#' nonnewline*; + + ampl_entity := |* + space+ ${ entity = AMPL_SPACE; } => ampl_ecallback; + ampl_comment_entity ${ entity = AMPL_COMMENT; } => ampl_ecallback; + ^space; + *|; +}%% + +/************************* Required for every parser *************************/ + +/* Parses a string buffer with AMPL code. + * + * @param *buffer The string to parse. + * @param length The length of the string to parse. + * @param count Integer flag specifying whether or not to count lines. If yes, + * uses the Ragel machine optimized for counting. Otherwise uses the Ragel + * machine optimized for returning entity positions. + * @param *callback Callback function. If count is set, callback is called for + * every line of code, comment, or blank with 'lcode', 'lcomment', and + * 'lblank' respectively. Otherwise callback is called for each entity found. + */ +void parse_ampl(char *buffer, int length, int count, + void (*callback) (const char *lang, const char *entity, int s, + int e, void *udata), + void *userdata + ) { + init + + %% write init; + cs = (count) ? ampl_en_ampl_line : ampl_en_ampl_entity; + %% write exec; + + // if no newline at EOF; callback contents of last line + if (count) { process_last_line(AMPL_LANG) } +} + +#endif + +/*****************************************************************************/ diff --git a/test/detect_files/ampl.dat b/test/detect_files/ampl.dat new file mode 100644 index 0000000..a68b3a0 --- /dev/null +++ b/test/detect_files/ampl.dat @@ -0,0 +1,2 @@ +data; +param p := 42; diff --git a/test/detect_files/ampl.mod b/test/detect_files/ampl.mod new file mode 100644 index 0000000..20037d8 --- /dev/null +++ b/test/detect_files/ampl.mod @@ -0,0 +1,3 @@ +# An AMPL model +var x >= 42; +minimize o: x; diff --git a/test/detect_files/binary.dat b/test/detect_files/binary.dat new file mode 100644 index 0000000..4268632 --- /dev/null +++ b/test/detect_files/binary.dat @@ -0,0 +1 @@ +some data diff --git a/test/detect_files/foo.run b/test/detect_files/foo.run new file mode 100644 index 0000000..644ff17 --- /dev/null +++ b/test/detect_files/foo.run @@ -0,0 +1,2 @@ +# An AMPL script +print 42; diff --git a/test/detect_files/modula2.mod b/test/detect_files/modula2.mod new file mode 100644 index 0000000..89898a1 --- /dev/null +++ b/test/detect_files/modula2.mod @@ -0,0 +1,6 @@ +(* Modula-2 module *) +MODULE Hello; +FROM STextIO IMPORT WriteString; +BEGIN + WriteString("Hello World!"); +END Hello. diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index 7566495..b33770f 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -102,6 +102,16 @@ void test_detector_disambiguate_r() { ASSERT_DETECT(LANG_REBOL, "foo_rebol_upper.r"); } +void test_detector_disambiguate_mod() { + ASSERT_DETECT(LANG_AMPL, "ampl.mod"); + ASSERT_DETECT(LANG_MODULA2, "modula2.mod"); +} + +void test_detector_disambiguate_dat() { + ASSERT_DETECT(LANG_AMPL, "ampl.dat"); + ASSERT_DETECT("\1", "binary.dat"); +} + void test_detector_fortran_fixedfree() { ASSERT_DETECT(LANG_FORTRANFIXED, "fortranfixed.f"); ASSERT_DETECT(LANG_FORTRANFREE, "fortranfree.f"); @@ -151,6 +161,7 @@ void test_detector_detect_polyglot() { ASSERT_DETECT(LANG_COFFEESCRIPT, "foo.coffee"); ASSERT_DETECT(LANG_QML, "foo.qml"); ASSERT_DETECT(LANG_COQ, "coq.v"); + ASSERT_DETECT(LANG_AMPL, "foo.run"); ASSERT_NODETECT("empty.inc"); } @@ -208,6 +219,10 @@ void test_detector_genie(){ ASSERT_DETECT(LANG_GENIE, "client-osx.gs"); } +void test_detector_ampl(){ + ASSERT_DETECT(LANG_AMPL, "foo.run"); +} + void test_non_existent_file(){ ASSERT_NODETECT("xxx_non_exists_xxxi.pp"); } @@ -221,6 +236,8 @@ void all_detector_tests() { test_detector_disambiguate_pl(); test_detector_disambiguate_pro(); test_detector_disambiguate_r(); + test_detector_disambiguate_mod(); + test_detector_disambiguate_dat(); test_detector_fortran_fixedfree(); test_detector_detect_polyglot(); test_detector_upper_case_extensions(); @@ -232,5 +249,6 @@ void all_detector_tests() { test_detector_emacs_mode(); test_detector_puppet(); test_detector_genie(); + test_detector_ampl(); test_non_existent_file(); } diff --git a/test/unit/parser_test.h b/test/unit/parser_test.h index b4009c1..ee1c322 100644 --- a/test/unit/parser_test.h +++ b/test/unit/parser_test.h @@ -75,6 +75,7 @@ void test_parser_verify_entity(SourceFile *sf, const char *entity, #include "parsers/test_actionscript.h" #include "parsers/test_ada.h" +#include "parsers/test_ampl.h" #include "parsers/test_assembler.h" #include "parsers/test_augeas.h" #include "parsers/test_autoconf.h" @@ -259,6 +260,7 @@ void all_parser_tests() { test_parser_verify_parses(); all_actionscript_tests(); all_ada_tests(); + all_ampl_tests(); all_assembler_tests(); all_augeas_tests(); all_autoconf_tests(); diff --git a/test/unit/parsers/test_ampl.h b/test/unit/parsers/test_ampl.h new file mode 100644 index 0000000..bcd028f --- /dev/null +++ b/test/unit/parsers/test_ampl.h @@ -0,0 +1,19 @@ + +void test_ampl_comments() { + test_parser_verify_parse( + test_parser_sourcefile("ampl", " #comment"), + "ampl", "", "#comment", 0 + ); +} + +void test_ampl_comment_entities() { + test_parser_verify_entity( + test_parser_sourcefile("ampl", " #comment"), + "comment", "#comment" + ); +} + +void all_ampl_tests() { + test_ampl_comments(); + test_ampl_comment_entities(); +} From c8eb3382a1852a0346ef1a5ddcd8f0009d671967 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Fri, 15 Nov 2013 18:05:32 +1100 Subject: [PATCH 372/387] Fix Rust numbers and update keywords. --- src/parsers/rust.rl | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/parsers/rust.rl b/src/parsers/rust.rl index f11140c..e3b17c3 100644 --- a/src/parsers/rust.rl +++ b/src/parsers/rust.rl @@ -97,17 +97,33 @@ enum { rust_string_entity = dq_str_with_escapes; - rust_number_entity = - float | f32 | f64 | uint | int | u8 | u16 | u32 | u64 | i8 | i16 | i32 | - i64; + # Up to and including "the number entity" these are almost verbatim from the + # "number literals" section of the Rust reference manual + rust_int_suffix = [iu] ('8' | '16' | '32' | '64')?; + + rust_float_suffix_ty = 'f' ('32' | '64'); + rust_dec_lit = [0-9_]+; + rust_exponent = [Ee] [\-+]? rust_dec_lit; + rust_float_suffix = (rust_exponent | '.' rust_dec_lit rust_exponent?)? + rust_float_suffix_ty?; + + rust_num_suffix = rust_int_suffix | rust_float_suffix; + + rust_number_entity = [1-9] [0-9_]* rust_num_suffix? + | '0' ( [0-9_]* rust_num_suffix? + | 'b' [01_]+ rust_int_suffix? + | 'o' [0-7_]+ rust_int_suffix? + | 'x' [0-9A-Fa-f_]+ rust_int_suffix?); rust_identifier_entity = (alpha | '_') (alnum | '_')*; rust_keyword_entity = - 'as' | 'break' | 'do' | 'else' | 'enum' | 'extern' | 'false' | - 'fn' | 'for' | 'if' | 'impl' | 'in' | 'let' | 'loop' | 'match' | 'mod' | - 'mut' | 'priv' | 'pub' | 'ref' | 'return' | 'self' | 'static' | 'struct' | - 'super' | 'true' | 'trait' | 'type' | 'unsafe' | 'use' | 'while'; + 'alignof' | 'as' | 'be' | 'break' | 'const' | 'continue' | 'do' | 'else' | + 'enum' | 'extern' | 'false' | 'fn' | 'for' | 'if' | 'impl' | 'impl' | + 'in' | 'let' | 'let' | 'log' | 'log' | 'loop' | 'match' | 'mod' | 'mod' | + 'mut' | 'offsetof' | 'once' | 'priv' | 'pub' | 'pure' | 'ref' | 'return' | + 'self' | 'sizeof' | 'static' | 'struct' | 'super' | 'trait' | 'true' | + 'type' | 'typeof' | 'unsafe' | 'use' | 'while' | 'yield'; rust_operator_entity = [+\-/*%<>!=^&|?~:;.,()\[\]{}@]; From 03adc2fddfc3acd872a3d0a14fb07c1cdfcbeade Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Fri, 15 Nov 2013 23:12:37 +1100 Subject: [PATCH 373/387] Update Rust example code for Rust 0.8. --- test/detect_files/rust.rs | 17 +++++++---------- test/expected_dir/rust.rs | 17 +++++++---------- test/src_dir/rust.rs | 17 +++++++---------- 3 files changed, 21 insertions(+), 30 deletions(-) diff --git a/test/detect_files/rust.rs b/test/detect_files/rust.rs index 812fa90..03906b0 100644 --- a/test/detect_files/rust.rs +++ b/test/detect_files/rust.rs @@ -1,19 +1,16 @@ /* * This is the example given by www.rust-lang.org */ +// Line comments work too fn main() { - let nums = [0, 1, 2, 3]; + let nums = [1, 2]; let noms = ["Tim", "Eston", "Aaron", "Ben"]; - - let mut evens = nums.iter().filter(|&x| x % 2 == 0); - - // This for loop works with rust 0.7 only. - for evens.advance |&num| { + + let mut odds = nums.iter().map(|&x| x * 2 - 1); + + for num in odds { do spawn { - let msg = fmt!("%s says hello from a lightweight thread!", - noms[num]); - println(msg); + println!("{:s} says hello from a lightweight thread!", noms[num]); } } } - diff --git a/test/expected_dir/rust.rs b/test/expected_dir/rust.rs index 0d4d04c..2b5c276 100644 --- a/test/expected_dir/rust.rs +++ b/test/expected_dir/rust.rs @@ -1,19 +1,16 @@ rust comment /* rust comment * This is the example given by www.rust-lang.org rust comment */ +rust comment // Line comments work too rust code fn main() { -rust code let nums = [0, 1, 2, 3]; +rust code let nums = [1, 2]; rust code let noms = ["Tim", "Eston", "Aaron", "Ben"]; -rust blank -rust code let mut evens = nums.iter().filter(|&x| x % 2 == 0); -rust blank -rust comment // This for loop works with rust 0.7 only. -rust code for evens.advance |&num| { +rust blank +rust code let mut odds = nums.iter().map(|&x| x * 2 - 1); +rust blank +rust code for num in odds { rust code do spawn { -rust code let msg = fmt!("%s says hello from a lightweight thread!", -rust code noms[num]); -rust code println(msg); +rust code println!("{:s} says hello from a lightweight thread!", noms[num]); rust code } rust code } rust code } -rust blank diff --git a/test/src_dir/rust.rs b/test/src_dir/rust.rs index 812fa90..03906b0 100644 --- a/test/src_dir/rust.rs +++ b/test/src_dir/rust.rs @@ -1,19 +1,16 @@ /* * This is the example given by www.rust-lang.org */ +// Line comments work too fn main() { - let nums = [0, 1, 2, 3]; + let nums = [1, 2]; let noms = ["Tim", "Eston", "Aaron", "Ben"]; - - let mut evens = nums.iter().filter(|&x| x % 2 == 0); - - // This for loop works with rust 0.7 only. - for evens.advance |&num| { + + let mut odds = nums.iter().map(|&x| x * 2 - 1); + + for num in odds { do spawn { - let msg = fmt!("%s says hello from a lightweight thread!", - noms[num]); - println(msg); + println!("{:s} says hello from a lightweight thread!", noms[num]); } } } - From da830741b6a77952b8dfd80d2d566f2dc5c56df9 Mon Sep 17 00:00:00 2001 From: Sathishkumar Natesan Date: Wed, 11 Dec 2013 15:24:42 +0530 Subject: [PATCH 374/387] OTWO-2506 Update lang detector to prefer extension over emacs mode line File extensions seems more reliable than emac line, as a javascript file can have a java emac mode. --- src/detector.c | 132 +++++++++++------------ test/detect_files/{emacs_mode.c => emacs_mode_c} | 0 test/detect_files/java_emac.rb | 5 + test/unit/detector_test.h | 7 +- 4 files changed, 77 insertions(+), 67 deletions(-) rename test/detect_files/{emacs_mode.c => emacs_mode_c} (100%) create mode 100644 test/detect_files/java_emac.rb diff --git a/src/detector.c b/src/detector.c index a3e8602..ded98c1 100644 --- a/src/detector.c +++ b/src/detector.c @@ -119,79 +119,79 @@ const char *ohcount_detect_language(SourceFile *sourcefile) { char *p, *pe; int length; - // Attempt to detect using Emacs mode line (/^-\*-\s*mode[\s:]*\w/i). - char line[81] = { '\0' }, buf[81]; - p = ohcount_sourcefile_get_contents(sourcefile); - pe = p; - char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); - while (pe < eof) { - // Get the contents of the first line. - while (pe < eof && *pe != '\r' && *pe != '\n') pe++; - length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); - strncpy(line, p, length); - line[length] = '\0'; - if (*line == '#' && *(line + 1) == '!') { - // First line was sh-bang; loop to get contents of second line. - while (*pe == '\r' || *pe == '\n') pe++; - p = pe; - } else break; + // Attempt to detect based on file extension. + length = strlen(sourcefile->ext); + struct ExtensionMap *re = ohcount_hash_language_from_ext(sourcefile->ext, + length); + if (re) language = re->value; + if (!language) { + // Try the lower-case version of this extension. + char lowerext[length + 1]; + strncpy(lowerext, sourcefile->ext, length); + lowerext[length] = '\0'; + for (p = lowerext; p < lowerext + length; p++) *p = tolower(*p); + struct ExtensionMap *re = ohcount_hash_language_from_ext(lowerext, length); + if (re) language = re->value; } - p = strstr(line, "-*-"); - if (p) { - p += 3; - while (*p == ' ' || *p == '\t') p++; - // detect "mode" (any capitalization) - if (strncasecmp(p, "mode", 4) == 0) { - p += 4; - while (*p == ' ' || *p == '\t' || *p == ':') p++; - } + + // Attempt to detect using Emacs mode line (/^-\*-\s*mode[\s:]*\w/i). + if(!language) { + char line[81] = { '\0' }, buf[81]; + p = ohcount_sourcefile_get_contents(sourcefile); pe = p; - while (!isspace(*pe) && *pe != ';' && pe != strstr(pe, "-*-")) pe++; - length = (pe - p <= sizeof(buf)) ? pe - p : sizeof(buf); - strncpy(buf, p, length); - buf[length] = '\0'; + char *eof = p + ohcount_sourcefile_get_contents_size(sourcefile); + while (pe < eof) { + // Get the contents of the first line. + while (pe < eof && *pe != '\r' && *pe != '\n') pe++; + length = (pe - p <= sizeof(line)) ? pe - p : sizeof(line); + strncpy(line, p, length); + line[length] = '\0'; + if (*line == '#' && *(line + 1) == '!') { + // First line was sh-bang; loop to get contents of second line. + while (*pe == '\r' || *pe == '\n') pe++; + p = pe; + } else break; + } + p = strstr(line, "-*-"); + if (p) { + p += 3; + while (*p == ' ' || *p == '\t') p++; + // detect "mode" (any capitalization) + if (strncasecmp(p, "mode", 4) == 0) { + p += 4; + while (*p == ' ' || *p == '\t' || *p == ':') p++; + } + pe = p; + while (!isspace(*pe) && *pe != ';' && pe != strstr(pe, "-*-")) pe++; + length = (pe - p <= sizeof(buf)) ? pe - p : sizeof(buf); + strncpy(buf, p, length); + buf[length] = '\0'; - // Special case for "c" or "C" emacs mode header: always means C, not C++ - if (strcasecmp(buf, "c") == 0) { + // Special case for "c" or "C" emacs mode header: always means C, not C++ + if (strcasecmp(buf, "c") == 0) { return LANG_C; - } + } - // First try it with the language name. - struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); - if (rl) language = rl->name; - if(!language) { - // Then try it with the extension table. - struct ExtensionMap *re = ohcount_hash_language_from_ext(buf, length); - if (re) language = re->value; - } - if (!language) { - // Try the lower-case version of this modeline. - for (pe = buf; pe < buf+length; pe++) *pe = tolower(*pe); // First try it with the language name. - rl = ohcount_hash_language_from_name(buf, length); + struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); if (rl) language = rl->name; - } - if (!language) { - // Then try it with the extension table. - struct ExtensionMap *re = ohcount_hash_language_from_ext(buf, length); - if (re) language = re->value; - } - } - - // Attempt to detect based on file extension. - if(!language) { - length = strlen(sourcefile->ext); - struct ExtensionMap *re = ohcount_hash_language_from_ext(sourcefile->ext, - length); - if (re) language = re->value; - if (!language) { - // Try the lower-case version of this extension. - char lowerext[length + 1]; - strncpy(lowerext, sourcefile->ext, length); - lowerext[length] = '\0'; - for (p = lowerext; p < lowerext + length; p++) *p = tolower(*p); - struct ExtensionMap *re = ohcount_hash_language_from_ext(lowerext, length); - if (re) language = re->value; + if(!language) { + // Then try it with the extension table. + struct ExtensionMap *re = ohcount_hash_language_from_ext(buf, length); + if (re) language = re->value; + } + if (!language) { + // Try the lower-case version of this modeline. + for (pe = buf; pe < buf+length; pe++) *pe = tolower(*pe); + // First try it with the language name. + rl = ohcount_hash_language_from_name(buf, length); + if (rl) language = rl->name; + } + if (!language) { + // Then try it with the extension table. + struct ExtensionMap *re = ohcount_hash_language_from_ext(buf, length); + if (re) language = re->value; + } } } diff --git a/test/detect_files/emacs_mode.c b/test/detect_files/emacs_mode_c similarity index 100% rename from test/detect_files/emacs_mode.c rename to test/detect_files/emacs_mode_c diff --git a/test/detect_files/java_emac.rb b/test/detect_files/java_emac.rb new file mode 100644 index 0000000..e9c0abd --- /dev/null +++ b/test/detect_files/java_emac.rb @@ -0,0 +1,5 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +# a ruby script +File.open("blah") do |io| + a = io.read +end diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index 7566495..d422b9d 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -196,7 +196,11 @@ void test_detector_brainfuck() { } void test_detector_emacs_mode() { - ASSERT_DETECT(LANG_C, "emacs_mode.c"); + ASSERT_DETECT(LANG_C, "emacs_mode_c"); +} + +void test_detector_emacs_with_extension() { + ASSERT_DETECT(LANG_RUBY, "java_emac.rb"); } void test_detector_puppet(){ @@ -230,6 +234,7 @@ void all_detector_tests() { test_detector_xml_with_custom_extension(); test_detector_brainfuck(); test_detector_emacs_mode(); + test_detector_emacs_with_extension(); test_detector_puppet(); test_detector_genie(); test_non_existent_file(); From d6cca3c87511aee67d90b502d97b362a8cbad8f6 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Fri, 13 Dec 2013 22:50:39 +1100 Subject: [PATCH 375/387] Disambiguate RenderScript .rs files from Rust. RenderScript isn't implemented, so if a file matches the RenderScript detection it is just left as undetected. --- src/detector.c | 29 +++++++++++++++++++++++++++++ src/hash/disambiguatefuncs.gperf | 2 ++ src/hash/extensions.gperf | 2 +- test/detect_files/renderscript.rs | 32 ++++++++++++++++++++++++++++++++ test/unit/detector_test.h | 2 ++ 5 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 test/detect_files/renderscript.rs diff --git a/src/detector.c b/src/detector.c index a3e8602..608d7f1 100644 --- a/src/detector.c +++ b/src/detector.c @@ -864,6 +864,35 @@ const char *disambiguate_r(SourceFile *sourcefile) { return LANG_R; } +const char *disambiguate_rs(SourceFile *sourcefile) { + // .rs is normally Rust, but it might be RenderScript. RenderScript is + // expected to have a "#pragma version(1)" line at the very start, possibly + // after comments. To help with supporting future versions of RenderScript, + // we'll skip the number part. + // As RenderScript is not implemented in ohcount yet, it's returned as NULL. + char *contents = ohcount_sourcefile_get_contents(sourcefile); + if (!contents) { + return LANG_RUST; + } + + char *needle = "\n#pragma version"; + int len = strlen(needle); + if (strncasecmp(contents, needle + 1, len - 1) == 0) { + // "#pragma version" at the very start of the file is RenderScript. + return NULL; + } + + char *eof = contents + ohcount_sourcefile_get_contents_size(sourcefile); + + for (; contents < eof - len; ++contents) { + if (!strncmp(contents, needle, len)) { + return NULL; + } + } + + return LANG_RUST; +} + const char *disambiguate_st(SourceFile *sourcefile) { char *p, *pe; int length; diff --git a/src/hash/disambiguatefuncs.gperf b/src/hash/disambiguatefuncs.gperf index d422213..0014d68 100644 --- a/src/hash/disambiguatefuncs.gperf +++ b/src/hash/disambiguatefuncs.gperf @@ -17,6 +17,7 @@ const char *disambiguate_pl(SourceFile *sourcefile); const char *disambiguate_pp(SourceFile *sourcefile); const char *disambiguate_pro(SourceFile *sourcefile); const char *disambiguate_r(SourceFile *sourcefile); +const char *disambiguate_rs(SourceFile *sourcefile); const char *disambiguate_st(SourceFile *sourcefile); %} struct DisambiguateFuncsMap { const char *key; const char* (*value)(SourceFile*); }; @@ -36,4 +37,5 @@ pl, disambiguate_pl pp, disambiguate_pp pro, disambiguate_pro r, disambiguate_r +rs, disambiguate_rs st, disambiguate_st diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index 7bac41b..0d87fb4 100755 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -176,7 +176,7 @@ rhtml, LANG_RHTML rkt, LANG_RACKET rktd, LANG_RACKET rktl, LANG_RACKET -rs, LANG_RUST +rs, DISAMBIGUATE("rs") ru, LANG_RUBY s, LANG_ASSEMBLER sc, LANG_SCHEME diff --git a/test/detect_files/renderscript.rs b/test/detect_files/renderscript.rs new file mode 100644 index 0000000..12fcd96 --- /dev/null +++ b/test/detect_files/renderscript.rs @@ -0,0 +1,32 @@ +/** + * We could easily have a comment of significant length here at the top. + * + * It might well have a boilerplate copyright notice, which could go on for + * quite some lines. + * + * But as it is, this example is boring, containing merely a self-referential + * comment in that location. + */ + +#pragma version(1) +#pragma rs java_package_name(com.example.example.example.example.example) +#pragma stateFragment(parent) + +#include "rs_foo.rsh" + +static int panic = 0; + +float away = 1.f; + +typedef struct __attribute__((packed, aligned(4))) Foo { +} Foo_t; +Foo_t *foo; + +rs_mesh gears; + +/** + * This example is pretty poorly written, ain't it? + */ +void warranty() { + with(pleasure); +} diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index be855b3..1b02ede 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -210,6 +210,8 @@ void test_detector_genie(){ void test_detector_rust(){ ASSERT_DETECT(LANG_RUST, "rust.rs"); + // When RenderScript is implemented, this will, of course, need to be removed. + ASSERT_NODETECT("renderscript.rs"); } void test_non_existent_file(){ From dfee05bea377d71bd56497eec31d1c7db24be513 Mon Sep 17 00:00:00 2001 From: Abhay Mujumdar Date: Tue, 17 Dec 2013 23:59:11 -0500 Subject: [PATCH 376/387] Adds a Javascript test file with Java Emacs mode --- test/detect_files/javascript_emacs.js | 7 +++++++ test/unit/detector_test.h | 1 + 2 files changed, 8 insertions(+) create mode 100644 test/detect_files/javascript_emacs.js diff --git a/test/detect_files/javascript_emacs.js b/test/detect_files/javascript_emacs.js new file mode 100644 index 0000000..3adad9c --- /dev/null +++ b/test/detect_files/javascript_emacs.js @@ -0,0 +1,7 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +'use strict'; + +require('./external/shelljs/make'); +var builder = require('./external/builder/builder.js'); +var crlfchecker = require('./external/crlfchecker/crlfchecker.js'); +var path = require('path'); diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index d422b9d..e67e4e6 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -201,6 +201,7 @@ void test_detector_emacs_mode() { void test_detector_emacs_with_extension() { ASSERT_DETECT(LANG_RUBY, "java_emac.rb"); + ASSERT_DETECT(LANG_JAVASCRIPT, "javascript_emac.js"); } void test_detector_puppet(){ From 5eb6fb12993b39c80f247150f61bfe90c25c838a Mon Sep 17 00:00:00 2001 From: John Keeping Date: Fri, 27 Dec 2013 12:31:14 +0000 Subject: [PATCH 377/387] shell: Fix identification following escaped newlines When a string contains an escaped newline, the internal state gets out-of-sync with the source, leading to comments being incorrectly identified as code. Handle '\\' + newline specially in order to account for this. --- src/parsers/shell.rl | 4 ++++ test/expected_dir/sh2.sh | 5 +++++ test/src_dir/sh2.sh | 5 +++++ 3 files changed, 14 insertions(+) create mode 100644 test/expected_dir/sh2.sh create mode 100644 test/src_dir/sh2.sh diff --git a/src/parsers/shell.rl b/src/parsers/shell.rl index 0010381..567afa1 100644 --- a/src/parsers/shell.rl +++ b/src/parsers/shell.rl @@ -50,6 +50,8 @@ enum { '\'' @enqueue @code ( newline %{ entity = INTERNAL_NL; } %shell_ccallback | + '\\' newline %{ entity = INTERNAL_NL; } %shell_ccallback + | ws | [^\r\n\f\t '\\] @code @@ -60,6 +62,8 @@ enum { '"' @enqueue @code ( newline %{ entity = INTERNAL_NL; } %shell_ccallback | + '\\' newline %{ entity = INTERNAL_NL; } %shell_ccallback + | ws | [^\r\n\f\t "\\] @code diff --git a/test/expected_dir/sh2.sh b/test/expected_dir/sh2.sh new file mode 100644 index 0000000..af6a968 --- /dev/null +++ b/test/expected_dir/sh2.sh @@ -0,0 +1,5 @@ +shell code var="\ +shell code Some string" +shell blank +shell comment # Now a comment +shell code var="some new string" diff --git a/test/src_dir/sh2.sh b/test/src_dir/sh2.sh new file mode 100644 index 0000000..2e03cdb --- /dev/null +++ b/test/src_dir/sh2.sh @@ -0,0 +1,5 @@ +var="\ +Some string" + +# Now a comment +var="some new string" From d40e04bdaa41e0f782cb5e82e489de45ca9b6e77 Mon Sep 17 00:00:00 2001 From: Abhay Mujumdar Date: Mon, 30 Dec 2013 10:37:11 -0500 Subject: [PATCH 378/387] Removes whitespace from expected output file --- test/expected_dir/rust.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/expected_dir/rust.rs b/test/expected_dir/rust.rs index 2b5c276..1c6b0e0 100644 --- a/test/expected_dir/rust.rs +++ b/test/expected_dir/rust.rs @@ -5,10 +5,10 @@ rust comment // Line comments work too rust code fn main() { rust code let nums = [1, 2]; rust code let noms = ["Tim", "Eston", "Aaron", "Ben"]; -rust blank +rust blank rust code let mut odds = nums.iter().map(|&x| x * 2 - 1); -rust blank -rust code for num in odds { +rust blank +rust code for num in odds { rust code do spawn { rust code println!("{:s} says hello from a lightweight thread!", noms[num]); rust code } From da4b6d6ffb5d0b5dde0ccbdcfefce568f6941d7c Mon Sep 17 00:00:00 2001 From: Peter Degen-Portnoy Date: Wed, 6 Aug 2014 10:50:52 +0000 Subject: [PATCH 379/387] Update Ohcount to work with Ubuntu 14 The most significant change is that the perl script that generates HTML, especially with the " 2610225 bytes src/detector.c | 9 ++++++--- src/sourcefile.c | 3 ++- test/src_dir/{perl.cgi => html.cgi} | 0 test/unit/ruby/source_file_test.rb | 8 ++++---- test/unit/sourcefile_test.h | 2 +- 6 files changed, 13 insertions(+), 9 deletions(-) create mode 100755 ruby/x86_64-linux_ubuntu/ohcount.so rename test/src_dir/{perl.cgi => html.cgi} (100%) diff --git a/ruby/x86_64-linux_ubuntu/ohcount.so b/ruby/x86_64-linux_ubuntu/ohcount.so new file mode 100755 index 0000000000000000000000000000000000000000..fffe1b68924712a07721faaf5c058d314e6d351d GIT binary patch literal 2610225 zcmeFacbrqz*8hJfVg%HHa2e&Q2Stq70=BW<3@{Lo5~`!3lQ0v=$doVzf}+MA6gBq2 z8haE=>|>8T_NZ4KtWi`((QEXojQzV$_F9vb4|AU9_wVoZdXDZ%@;)nTt-bcz<+N~m z<@CvY`}8q*>t`HgSf6|W%{;WD{Gc%`Vt9;lV{7$ycf%~mZq>7A%QtIY8(M(;YN+p6 zo27k#D(QFi{`9-!Ev!E4S0h~bXmq#gSN>jK_0jrXCw;Gz*gfEIb_c+E}nr}kYA}f zg}Mz>yZWgzW#)Win=dar=k}}aJa1ITzR&Ktcf+SIO}qXv>ziAvFSMywk1B&z=`-N@ zeI}__hmjuG_xx>~9<^iez^K#QJ%8X4jy|)Ullq$djmkM)rpHu1`nECNF?=zz|Cu3g zpEb^^Vf~G>ol)b6e$Jt1hK)pp$9TT)vwcIyc_PN{u2Bx-<>+Mh@NCqW_F_dkt(^3X z-nRb<%J{&cmC?9k@SL%It7?ri3-*;6W3bmAWXE=rgMO<^D$B zOI~uGGk97!e${{p#x^58#-^p(CbrFyjU{OE)+!}^bRjCy8N-vLfl&;E`w zBi(0cUsEOa03$lgv6~qkHG0Cp{@Y9#x7C z$DC)R`x@gahB*wUc>ga!lVeaN}8vU$XSfR?vs;pAwG*!+}#cGqYR5@3b^HhncvRV~uJ71LxRJmA{ zOH{c`mCIGRQk8a9u2tnaRjyYhp~_9FSli92+*)|2|J<%#?xD~3sn`2ed4xW9sMp6; zc~X_MD#~%=IaOX%w?)eaNATwQZwb2h;m))vHsL zp{nel$}m-U8&2;>(Cbd>b)+gg(`Qq??ykxns<>3yTNSq|2dHw8Du=0JZAYlrBUSOJ zQlZLZRlKTL+jR9hOO?5*%u{8)DhpJpQssD6s#Wo;Vh!!Jsw`0@q{>OEELEjml?GL; zEv#ObsnSfJE!L{uN9gmZ>NTp$nW~(v$~mf>r^;$o)~I4_7pm7w>HTHu^$Jz2tY53j z)v8$AHR|;SRT8S)qRQ>6SX)xP-l58!^m(0ny-St5Rk=r%dsVqll?POLNR@|Gc|?^C zRjln%dVNy8KBdajsyw60bE-VA$_uKzs7gka*Hp2#*VXGAs$^ApSC#ivd0&C8*Ren_EXH~3ivwHnal|NMZn^@nzdS5^F z+MnJJP_J97;!tIUygj`Roj__uHP z&@n4^d0>~|>P%PJyNiDO$@WV?VIAW};YE9>F!C$;_Ou9{=I0*{`ni z$5&_mI{vxAk6(Aru!o+!`KkKqy(WKrZi^>7VQ~3dx6Ge4{pacXh9if?LoZD|X219P z?0Ws8DGPTtXWVemrXRnZ|J1Vc`oA6?;-7i%VVRHr&i(e>wpZO%Svlj|8{Rzsyrl!P z-j6@I?buzeU-jg|*r1xa)tSLhA3yle&mO$3`I`C#KeTL{|J>L;>HYMC;s0ui4eERQ z)6S=FAN1Sg^G4R*zG>A(Tid4y!-*aL{NvGEj<|SHQ}(@+h8+FX zV>`_l^g#99$DCz8@M6_=Uk-V^V}10cQRmMalbO11yB)jE|9#UQ6JGlE$j5Ko^SR4E zywCSg=+X7@ht3$jpk{UE_vP13`enmD&s;ro?C3|IJl5H@{FLlzKR)}^iMM}w(O>6o z=yR5;)72Zk+Wfj?6V-*P-Y!hi15=7Z%o z{5t)mDVq;|{HoJ-dS(57*DRiWNT0bcZXP~h?~}$pyZ)r<4_^G$KG(hU{Evg8KM(k7 zMf&tL>vz02HfYf9xrN+8GyVg7Jv2Q=D_~pGlR*zKu?LQCoHE#RvhJRlf zxca9zZ(FtghJk%vyWp%`pP{wGuU;7Fc%QcAHD?s5*Sq(c`Z=r+mr2<>PGdbSK5WIBqxT9u zX-;_ln|Hq7E?B)flm2?e*=rx2c;Xp*tyuTkXX*79T=u{n%U|yI^bIfkwB3FKJja>y zrrvW_pJAcfU;W^w1xH=?MdyE0ZI&J*ABTl;6U;e_ZJ3pKL!PVP6c;DyuZ8+|@ z3141)R^aAGFZ^M=_Z{bw`t^Zj&I%K=EK701dPX>K_@}-*x{B`+|N8g`v=Cxbjv*6SV6MI%qh;7{a{Ds@@ z`uY?3x2CNdam(1R9vM1t(7!sDRsHjhYoAU5{nYxzuTOer?*7M`2Nz#|`~|nIYk${!_wXwgyxj8q zf+25T&^Gkc=uVy+@40(*CbOXXs-HI0R^5Hx>da+FtUGVxr00KmaKN&iKRog9?HevW z<=mZ&s#RaBd~JAk&5?8JuU&QQo?{OUb++zx>Sq@py6cD`Z{I!im36N@a#QQ0w`{-U z-^-o%ZHR}zTXgM=>#i8M`q@`stzUiaMc&ggI~?(0^sifvxq0hbhJ5tjLtSgWJZi|d zfwR1?XCJ!%lg;<+8Q=8o*_%G!f6*(a&VJ@qHJ&~{>F*yunly3s&o_?vF8SwApS+yD zb>7=c&11hvA3kpWRc(6=u7BmLf2+?Gzn|wkXZQHhQ``Pqb^e6!cisN16BfVQ_k}gD z-aPP>n>r?J{^`BR{~21pI&;d3V~y<(JL;Q@;wLY?XoTaFFQbQVKjV7_*BQ@%~Li!wBFtQ^@hM}-7CV+uFl+h z-`HQqZT(H?2G!@jS^L6~11`R5c=DFjnbEIaxoSgTb>_5-cTWB~e&G(?s=fQ3`^hh- z51kRaeawoZ2VZ+!bN=IJ)*tlj$`daddeG=QKfiw1i}x@6>d3<*vyQoR(sVt;+W+lm zY-41tg`3!{wGSU73T#Bxhu(NUb#SMTSf#XDQ*P5cx7O{w={eX&Pe82?dXvA>#?QUX z-tF#Y!)vzgUH+fSPxX~8w$IdYcyIN+d)MCiL+aSBH~-JJv71*Gdy{|LCO+re=y}X0 z{#Os^UH>a8p1sxU6&pR@+Qi{1)n2{nvDV(b)$25y_8n-W|5Tg$TE~~Y=^ttK?oZZ6 zeu0fYefssT=PsLeZ?b8xYm}be{QT3VzJ8myy<^iZP8++Q+xU63jr>5l_#;?~!uUU3`!<81oH(KhY%o{gTjZ1n7I!^>4<%q^m$&lmRA zziv~qz3~fd`0X}vxZg&8j^ewif?L|Az5{K>haYX^Yi;Duvhni}8~J~#cn(1))#px? z550|7D{S;%Y{RW{o4v)^J>1ei$jE-75>jpT+ZSGpe<KwlBfCCDEuiFHO=f;=v z3zd_W9?vMP=dW$G9?PhuCqa5l!rl>@=SG$4c|+x=r6*yX7*ks<$q!e4S$fh3mdaP| zqDu08jucarqhvrJGuwAeGwd|(XXuEfAr}?{zTk>Xksh*d1)I7ac zDgTc2#FJXjyQJqh6+laW?lc{k!^!U3R4)VSwY|zWOFrt>dS;XSFUqdP%`Vl@Y8yk1 z>NRzJebY+)@r=}dMn{+OLBvzLl=Ab48@p-lE?805B2;@>cKuH&$JBNQ)$6S?&GY+f ze`b>W!77=pxOv>A`j4f2^ZZnrC!bUPgpbnvTGHRHUM)R|gR~x#^gp8xJS>00r|Wo5 zCLS-$BZCa*aXN0d5Z}Cm){~?5Vm(z<-z>yuF6C_;@;pi0H?Fi^yHGoJKs)YM=qWP}|}q`U`8Q-}#~6T}k03-nnb3d?m%rv`&bt%{tz&w&$t;CZPZBUYM_yKQWyT z?9WAHH~WQFu#d85ZF8u;#=fQPxRBa62JQaCKeYepn2s~+$&y|71={X~TD|cF=}ANW zUrX(4gmwFJe2$}dM%R|+^Oe+&{_}JqjJZP_aH(<6if6i8_q)rI#Hl}qf7X6}rPUc9 zk^Wp%16^ywXrlOgApU15KMUg|%p*V1!k1Vv;2*afDZI~7}exNu+C+UQ0I$7@sn3g{y zj0nlI|8FbqRJ?<@me$wz3h|^1F+84puM8FHwP$I){-AlsL)=Y@?&kjJ)bZbe;(sLR zF<|@|r^Y=?e{?^s-%EOq-GTZ`jn0#KG!Cq$e9Kdwv!8#GKT#Ub*`KE<{=U&V{x?wk z-!H6t2N~`Ibo^Di7Pez)JoN2TTHmv&KdOu41v$T3PgvVM)W3|MG#^TSR#3gNR49w}6NZ#1J)Svfg{5Q`i&BIY@7%7Z1#CO+fjF+jt ziBq-wLFE7YJ8SveIht!L>e{rbhm}7mSU(&^{&--%i1U00e%?)fx@n#|i2S*$pkK{v zeYM3HCG_nSXODFOP;DzozKhz|bd|jo&b zR(mCAy}`#9OUa*q(>Tw0yN2SE1U>JQeh=lFs%Bw3pXP-G#PdVWLpWZzgW{R6ZU#}? z*ur0RKNj`hH1yvYYCg66Pj9U~e4NI~i>aSRchzw)Nza))Zo~MtT7A#bldscuuOoSt z3$E<*XuDxr zPwr0s{7c2b@-zFIw)-IY^E&BIgZ}>(=F<^I0_N-IXne@Q`fY&%F^PXp?Q6pL`Ied=EdRrFwB7)owId5{Da~-nDj(J&wr^u`f0o}3)Cg)O!I`wk9z@IMa7YXY`x7yCqFUE7U&h$0u`H}UkB0qEFr&;)xVZ2K6#>ra#QEK-} znx}klp5ZI%r^aF0PhJPE<#7Y%i($$yYy2svICDOqq8zYz74VZtPa5=8Q$Ni@ocq!^ z=A>~fNcBolzc8s^c!+nV@`5<+ru%Mfu>nr!*fPrEw`u=Y`mA1&u!*TGx3BTGV~W6o(wu z%Orj(@2CB|T;-p&ooZ@s(s>M(HigYWdcu(B_fdQ0 zPtXZ_1`SL{@^}d2-s#lua@6l8lm1<(A33RAlzWA3Bh6EO$n#xkz3QQQc}V^_id%GS z={Wo_jWeG8^?1VP!J15+w|>l9)qSk^WNDpKN&1hVdU;@7_c-NA0`g}f^{*Vvn|F|( zaq#nS8izfw4!?!h542u#lRv7vD?bMt*Iun05Sw+n-tymbhHe*L7yXOcD+}v{Y8943 z-okk#YyD#JG@X~W?n$<`YbbwGJL>$ojPmDs&O?|t_fh?^;Lkjr|9qZgZ{?oFvy^YI zY4yfb>KA^RuTA1ZRUTUM?rL3Mp4ZM&iCyrMj#KpLXBcIqCjojMqVdO|{>Aa!hWfP| z*0Fizzcv0R;CS{`%0mN=Pseb-hV{nP6rU*dQ?6G%`IDeLXMg_Y`RhDg-vcQQ_p2}# z;z{|bzFyeYbG=}^RqiYKE$;_AkMb=+dBx+yX>?qWhVw$-Q~bj;zt1JRS?Z@AIIe$~ z*0&j0r#UFj2K1MYsb7SlUreEK)xTQjTOX@JYV*>3=bxfmoR7QzRN=DPD@XGMkB3uC z-QT0s-}Pvq?u%FLWyRBcPm^1ef7W&d#otZw-(6!PtNgU&{ct{fwu*m&->3(|+K2TQ z22%eG!+QQ#ii02WElc$^*6aH6JaQ-HPXdnbex>}+pRM!cYx471$_F=`AE+WdCaq^U zJ{2^dMuU3Xs31MJ()z)(TI(+-{sfKZKC(NNcv#ifibL*QeE_uTKD}coiF|I=SP}1Q{U)uV-B^;m3(|hc{rKu-cEVzhvV646n~S(CGKAXsQ)Ht9x+MJ zEE@k4OLQD6^^5Tb<%x42oo_sjy{Nuuou9|^276F`rVlI4&y^JC>|(8$$GuZ2f3nBu zo*0g3hlW$VOt^mZB*iEFiH^?(I^KMr@p}g|IdUdcGk1hRix=_sH z=UY5pL4Bv2T7L+};hALD0sIlN8-@AkBZ{-ft@H4&qjh|SP&@kQI`2x2jVZLwaUZ1P z@G|jTXgo>KIHp@oJ=aS4Y(RYk?1*Wl+g&d(}c-^TAF_HiYV%o2C7EN2@n3PODbdC5vr5&gp4e;lE>PKd~jt|d+`>STM;+&)VYW!5M&q#mnMXldM$D5;Q zeDMg4j_>A8mHeGjbLFI4lL6^C|c_crB#r9Vdcx!qUMy21_f$U>5@2l-3r_{&f0 z_Cv{^QIxl7pN`M&diiKvM{!8NdDJmL zV7~Z_+TEc0$5eF+TQjW(vQ0YQ_98x&^e1TEcN2e<#uGn`C*!EU=V5;7p!`YGb>u53 z4ngXt23)_MP5GRK>*iOG|2a6mXry`8fb+eFke&qS=|lB(&d~Mc^N@S0k5-(+bRFRa zs_#M?H*$3R#d)%r#`!p%f16A4pHh6{aD4X%)i(`!<)^%jLf-yFJO|^_RI0BD=S!a= z9;Wq%8rBNie2Rb6dYD&js|tVBv(ePPd6@5NXgoAvJ)figZW_9u-b3S3e;W64blhQ* z{#MGv1RbX^|5Dkt;+*xU236Yus{dQtlT=@m;=pl!pW4x+b|JII&#Jww{+ok*+n4N` zaNhfD^~FN_!u>^4Y5d7A()Hr}|55cjOMim;JGp7>%5ivB$CJnNZpt6`{+jz}oIH!h z`LOlSwzZAXFP+pbPC7q)k;cZEG+rfOyxK(dGN8X7LgRJ{#_gS{Kc*o*&rg zOXId5#_iW=yfrV>@*9=k*7g|r6W!~8!e>w6uX=`Gjo((>;$&C%GWGibq(2Aa-ffg` z9+(%5>gpv8O^wwpt%2s&>T099uCcDws9vmIjOwZLW>nV(n}bX0T3Un6^JYw}Z)yzA z3oNP+>V3WMsji6xECqr3x|5aQwB^-vNW;YXKub%o#b{nsy|}HhCQx5*y{&6(9lxk< ziS;&E(Y&Oxxw)yi@L}G{aIpAk>a61XnN2f-4aJXB8*77+;>Y8H%}tZ)mKVXCK;sgj zY3|C#)_{dm%?XPZWYHO}hJL-eg^(rvc zi<^VN-gXwas#L8~U){9mq+m^JwW@Mcja9jp*5>NQ;EL)R^`;Pn<<%|0R>O*k7HAIC zwFIp_p+HNhI?xtHa7mu7AOydKJ>P zz>=VtuaiFfg$2bN*P+MDFTi2{KG&QgMAEm4YV-MbzyR+g-sRJmVbMm0ip zYm=20Tx*LIn!Bc{w%FW)HZ%kqTZ>uJvuBYC)zV(Lje5(?LY`T^2AWrLJgv9kww6$j zLn0EYEv;5|j2wlLS-_%( z62A&!t#wU>5ry`&sPUpc*s5le;+JYB2kKjbg@NBvS~IyWqJ|vnZDAOp)~U0csP9QskyE&6au?WE|*SpfDs@19M|dc%`wpNeykr;+9}=sj;{6>1bR)I~ry72hrrKbAYoO#S1yW+6AY3y1^n6nf;pmQ5 zA)T_dQ{o_~EsRH7_=u@dFjJ~VjI^bz3CloH-kKB(sZ^NLt!z>=pGqQ?jq0_!x;~;N zO|^!w^2j2bNriUy1`Qky5a@skyZ|(5Q^nSnGu9 zMTHhDQKg2IlFycBTDY~TzG+3Ux$u=jO#&@JYZ+4_9%xag?n{X3_@$t(v8EI>lzt31 zHUC0G zZK)XdUcEOMDNe?{EV6oLl7_&Nx|(X;(YYt`a;&gVEdnix!g!TXwa_1eg*A9ftE!jPe2c|WG8j?E2dedIsPP(BT1{D4c?KJ5Fo5B(5w2-g z`PI}Aw$@*T55Y(fq93j|NTOODQv@U77K4``4S{gA(!NAZz5?}xky)XaSp9nOie@#( z8^Ok9ZNau+VL@%p1G*boO$DgcT3zZvFHmDmXe~9(b>UVcsMdx$Ce~84SpjQETxqD` zyV0m4?drHd4Z+qSf|eYgA0C zsGeRia|-*V7N`yCpsU#kv@{5*xidtMn#8O?YO$~vis=cfQV|8G~QlsLSqeA^sF)|!Evm0;J-Hze zF(yo(I`6m{6;*mCsHv%lC(N2vqD~zfH7;&bllvlmCuHYTOr1G-{zUSY zG%i+&xJdmGa+7^NskDabsyehWk$26SGj&RJNn~nTLV;!_G1pr$r{w$UI4NK(sF+^T za!Z1ZbwOiF<;TQ?-H`1&fu?wJWUrRDajQ z+QbPYsSc-U7U!zf2UT;{)h}0>G?7xIrezB$b*MXWZqM#5_Ma439w4_)+G6LjhI(W6 zjOp5gLiDDQCUUiDnK5zJZ1S*a85*x8S8HqP4ONP}Cru=!T2JjtHFO$Td@TgNBlPf09n>9!JZ_TzLwQf{@i{F_%YtB3` zN~t+{aa|->Ygl{dRLq<_wW^Y8ytuHV_KTxOsiN>G61M)DXiwL7BTSX?*jR6785Q%USI`inQBesA23rG*)%0h~sGL_ZdDcvFKphhn zaBt$_Cbep`#C@~o3ULdgcxy01V?^NqIWXRsF>BKN=@sL3W)Q@0X?y_59w228K-tEY zx)#IwQ`|9g?$nZDtZ9)t#n@=fnov1s7L7O>6~Cfmp-=nOEmu>%lAcE6yP{(1Mah#a z$!Xd}C3(^oI%@)Il$|xPg2&k=3v4OXYGw1RiSv3gxv9oNC>U0wxjN6~tC%~nqNkHu zXbZtQYeAs?6nFTh9$k`mYUQmm%g`@EY|bo|U$X0l+thi!R>L>n=j%z(0xEtj=UCZrmScV7ET^me~aRCDkse9shhQ;X%0pr#+=G38U(D5MQKvl zW}O^Se{hEtn}AXHTij&@ucYU<)YMtsMZZY7sXg6C+i9`R*cLkF+!+m{76;u5Sw%stAesrO6kv=EWB4Z&7Bhw`Y>nzJ%3k#_*}N3lDkDP^%hy)FN2D6lK+FcpeW%ET~Sas{?tp%&eH}qeM_^O$!#k zr)5LdaOUk9&8&}Gh*(y&^hs($Ri!8~jb~52zaebR5QV=*nHfGSBSp$IM3h47kC3S< ztwLj6#89OuFmq~&if|zmJ}(~yl!nA7A`%kbYA2fu-` zF{)ZNVg=FqQ^(VD!8b!ZW59mLnxO7Y>Dc zj>-#XFA7$h^{EYOxo2H2GE`qJ>M5*u=FI0QzwmL&tm4vIFN}-we2T?7hehYIdQ4i( znzEOvL8Sy1&J570xh;37QwD{T6KV-wvXjp$TIcrRdXL=I%SE5!?q06^6nAcU`A6^L zb99AIy|`qZa|)?wswR2lKNk?>3IInx=7}K(bQPDX47lC7V4(=+cs{GjBN||NZ2(q3H(pVR}d*2ps6*L zx^QJI4!5ZbjN#^>>RCbS99(OYy0jbA7kqV67_ANA!X+o&?bHb@b^1<8*0zO>hNbE% zzB=8?Y14C>T%Y7ur!1EmVSSB4br)qwpB`*$R42HWDmCg{U}KYY@-|So?o(YY&I;C8 zCjgaai;Wg_9?@ti95=MkSwXc}HX78)L3IsesZ}X;hT8f&t;dtXNFgpu>Ppuwvd$Ln z*V3eJd8w~kR5&wfeHv$dshteY5A? zeh2ovA6I-^d^di-gXrE0>&3c@MBho$SH1E(=9=ig`hFHB`ny}oOKp}6f42VRl%iJV z`uo-=!`O$!+X`gS@M7X{a*zBF9QERh=A3P`>3A# zkXigq#~teG)Qw^TjQ5GP?pUX8FyG4fj6Pp}$(5?h_cy+y&%+Ax{fut<+_sY?uSStk zMq%TB_lxfbG=uuax(xmMUd(f~ntQ&~cLX!%&r#sU*IF(HJl&;v9C(y?J8%#21aO0R z5_o!})}I0%CEfwtLp%-KAf5r9{z~i50*?~!1nwc818xxKSB__z;>O=&ZhWKdM(KOZ zJ;c+%qr|x$ET1OM^=58tBK=fv<{si{;8Eh-4lJK0&h5tB_?GljyD|3=PXmt<=R9Kh zG;t5b3Aq+u0+yH&sq((eb(^$G#!ID~8Ia#hob|DM#Wh;qL3Wt`Me^(y^Q~^z@?Mb7BsGr$A4&2t;5U=q zH1NGhJ_Fo&ht|*WW`8DNkcrE)6JWldy;1Tv8_!{zu z^O5~IoBgLeW!^~f;k;&k0s9Z~S@s|J_3S_J|-&;A&6-?9hz z2kW%F7kKL}n)`qsbC>2-zz<4j?g#!k=??+_<9aP02L3I{M}YrG{zQRylY9&~>yHE9 ziu`W}&i*HWZ%6V;;0IEDQ^0p7`3~Sa+@R~52EG@`XMi`{q~)`~$B}#|aF)*jKaAwN zfO94fg}TiS&nn-$*) z`eO=sisUxsvKe?+_;_(B@b6Tt7KxFv0P3ixyyS37|7e31s8 zBY!f$IUlmXCy}3>HarLX3)0^OoYxO|;2TN48#s?Y#t)_Wzlr1>z&U@Mz<(h5GT?dQ zCh*&6UE#9fZs1)szLf)a(EQ~Aei_;I0>6dVKfuSHpvTWD;BWH!2l!88hAg_p8?MK zlLfwv);XQPdHtLN?jZeLzy4x>#J@XZv3}2|2?GN0sJ`{Kb^oQk$f5O9OpmqsU+_LzM78r-N2`l zd^vDFp7j84zfK>&c!9r3{`i3VNPiV@9&i1?InP5jJPdpu>5l+EkorXwcooUVfb;ke z2fmQx+kqcK?VbQ$P4Y?LtUm?3hU7bdvwRwO9m!{ahlpo^*Awpq&iR}J&d2p#HarhJ zO!~Wlb3PkCmF9md$vc2^e|G|pkbD{NdWydZd=<&NfO9^(fk#Qc95~0{1Nl1kU|21)Rs>4jY~ZzLxZ7fImR78!UBD0J@gMm8Bwr4k*Lxn|JnwjIxDWU>l+RVb zYkB<-{9*DZ1f2Z|1AmOBp(CL^HCi5GbG;*oc&1vzmUd(qzz92f1dPr z0Dqj;)oI`vlFtBtgzRR4zee(%z+WNx9Pl?uz6SVC;2TJPIdIN%4{#@~E4((`2fT~)R{`ho#}E8l zk`Dprc!q)hK=KjbeEb*%zLETo+3+~<2Nn(0=Rbi@Aw3D;Ka)R6;Ou`2_zvIb`K|-_ zvy=~M;J=do4Dd?Ihb-{FNWK#|pMS^!=XU9`;d$WPPrGfnvAHz=@1Xp20O$BPf%hT# zGT13s2`l@0d;|AG2x2>3?gVc^@4 z{}JH4o{R$DmgHl=`Fuhg_z0432hPXK3E;bud=fb4XA1c4B;Ns?+cyn-Pm<37XZbAf zeMr6&IOjVT#{!ZXm(eYyrIFDmpHarjf zMAF|4oY#TIuci4PBzXsL9K_tTIK4+B4$>Kn1)QQ*tSpBV5k@i_2S;_blM{{-;a6wf4ZZr>E}m88D| zc!YQw_(!xZ%GmHM@KvOz6Zk2_bHGn0-UXb`pX7lLuhHwnZs6b3`9R~h()>T0^gDo` zMcfH|9-Xf!1J1|GCh*my#|1n_+ztFJ&VL*30nYbjd2P54_|-I?SJ`ks@C(V$5b#~8 z-NV2yA^8Y!&d(_DD@Z;DobOkO17Az>?Z8=o0{C?#p9IeGDd0Dfd7|~7|FYU zvwk=5r%1jWIInL#z@H^~FYvGV`Y-SoNxlj=`{M`x3dx6nvwRr%8zdhA&hk;#67@c z#C^b*688h&m3SEVRN_(KmlBTy&-4AIz^@_s6!13UY2Y^!&jP=Pcn)|6@jUQp#Erj7 zgA4WV6{7uqt{9PLVNhI$CzJRz1{3z1n1|B8u0p5@F_<#q9`+@(L z^n`&gCHW}uxlb-r-_GwA4NP0{AJ>C;924c;GM)%z&|IR2L2!7 zS>V4A&jIfso(KLXaidRZ{QKXh=SL^-!Ng7AYiXV42L3(i_W(bgxDWVO#Qnfs#G}CZ zKK3|pJ|0g1=lkwb!1?-Y8u(RoKVB9%-%p+c&iBdZf%EaH(YG|teBZ1SI3Hh|!1*}T z4V;hnJ;3=n2p@31zt<0(?*j<~Z>Bgzf&akwD+0glbDcj);N4Gao&tU?$#($1pLiGW zEb%;WS6b`u2ELx;jee!^uOfLj@E=IN9C(D}J-`#hy}&cXBfz^!e-t^%$AJG$@^Rp< zXLNnjz(;J*JOeyJ@>$>}$#()zk-VdSY1|GZc_;8Lk}m^3ndD92WzT9qeZUuyd=+pH z$@_sXCHWBWRm9tYUq(CuJVN@Dz*EFiz_Y}2!0#aaUBHd!bba%{UBtVAhlsnjDvkfW zq~8rZM)KvrA0T-T@HEMXfj>v`5#WyJwf|AzuaJBU_;z{5QpHtof zkC6Tj;7Q_X;2Gk1;LnoXZs4rn7+4xl*6#rBd`0_N2HZ=$9QZS2*8@C3@?PLs;y&Qr z#G}A7q(6rIRqbaSxbd3i?Z92cGr(UW{aN5~lJ5kbA)W)CC+-|n8t2zYe;M$q*R`J} z@HlZ7@HFu%;O~=uKk#mn4*~z2=PT`J61e9L%~QY!lY9s8U5R%AKa6-D zc$oBe1D{Uv#^BO8caXdr_+pYT2c9E&5Ac;F?*;CBQ`a{F{Bn|y0xu`|81NfOJ`OxY z@@e2tlY9nvoaD2>GsHWA=ZQPEEsfjjq~8hL%$^3#EtDs z<8vx;2k^3YbR3+(y~N9ahlqQDpF{e6z}rc_3iwqd?+2bC`8e?VNWL9-p5zn2&3{wg z0{0T{1pYMX&jAmUd>8OHNj?ueN%E$%H2&X_ybE|I$-9C7PV(izhji(Bg@Er*JPh3N zu9lAgKb+*Fz^4#T0Y8>_2k>&zp9UTx`3&$C#Jhp7A#MyQja!KHJAfyNJAr43dw}0g z`n|x7_jG)G!0#jZD&Q{@j{)C6JPzDV`rCo~i6?-^h-ZQSMfy8|caVGzxbtgWuP)$S zBwsePG|pp5-URM^U+ZxJ_Yijj4-xkRKZNv$fVY!;7&>cnbK*#5;gr zNjwcaOaA16KS=W3z#W}BKE@8E@hm6q03IS<4*XTp?*X15c`xwyNZtqhYvNJh{lC$E z#(;N{{y1>QdM)1$+)X?Kd<5yw0{4@AC-6A&9Pl)8=djXv?oRs4fEyoZKTY6n;x6Dm z;#I&8ApL&eVUiC4KZNANz$X$<0H04h2|PjiQ^5Ts-vPXnrMBu+%BN=5>DW(zYO>|(r*IKl72Vv+$Y*kAMjJiZWVC0>jz#z zc0<6OpKARP;PKBiZwJ1R^dx|@-6Zf@l1~A5lK-9&rSatZ6@9?@K72oL{+*UE@Y537 z|0wXcZ_zvsoUd;tfb;V#Dd7B^V;cDVbRTRMIRAc54mkg=Q64xy*J+fM#)qGqa{_;d z?3%#&cZA%)`957({JeY|IN#@=0M5Ttkpj-oU8aHa z@7rX7^L>Lk;61-b1e~93nko=ik-w0O$L|eZX(HQS0#o z=li0=!1;G$qQLogRN}z-cUls_`S+<(!0)?B`;!LF=i#%!`MI7PaQ@wuJaB%_+SsWy z{`|b86FC2Fp$VLyhjjzz=OR78`8hiuaQ;0OKk(SCIu2prJ--_OobNY|1LxlzN&x5I zgGvGC=Oxp?yQy8W!1=!S9B_UvCJ&r{2f!Fv8h?H+#tEFCA2EURb3kt3{Je|@c+c;j z03S}{wjVe@PaOu%&%Z>0^Zmwg;C$b80yzKfUkW%s*PI564I6p5I2mTBB zlK|fHdyl|-?&}85zc-i#&c7R$13rl2lLy|1{4sVejXysx?*z`j3uFSHL;cYWoS$d( z0O#jPeZcv-5h`WLFJnjL`etLnkpFZI1XBBYv z(+`~e3;}09!@zmIjsj;tW5C(ZIB@o}9XR`$0M33UfwP|};Jn^T17|-oz}e3%aQ3qk zIQy9c&VF_QXFv16dEIX8YLlP9*-s~MzAv;4INLRWbAR*z=lFPmvt1u>wp#_9?fQZ9 z_!9-rc4NTVZX7t~N&{!R8Q^R;3%n;EfcNAB@Sc1C&VJ^B^Sox5Hu(UY z{d5B7_>=)>yC!g+*F3;EK3?E#*9V;KRsm=W)ga&f|;=IQ!`a&f`oua9)>sfOFiuz}bHvaE@CQ@HDM|{J>u#9s>R*@i6cY zh(~~PeWSp+UJ2k_uOx7;R|+`Ss{=UOO#|oifjQu8w+lGi%>!q<-N4zdv3qI0@p(TJ zINNmrXS;6TY_}XZ+w}nF^PGO*Y&Qg)?S_G~-3V~D8wJkCO$p#^Hwm2Wrhv2E4&ZDz z4V;gUa=_Vc7jU+l2hMi8fwNs>bZPtYakL4X?Ye-oT{m#HTMnG?1U zO#)}TDd23k1324F1Lx~9IpA!!3pm@&182M4z}c=brnG(e{GJJ%?Ye-oT{m#HTMnG< zdVuqF5I=CX8v@RD!@${Y1UTD`0_XE@3E*ru37qYwfV15W;A}SyoX_9pfV15$;A}S! zob7f4XS>FprS02u-2ph;Ed$PWP2jBG4ZP=kAaK_21iz1 z7&u>#ivnjqW5C(ZIB<@CJ8-s}0M6I-(!kkn1~}Wz0%yCOz}apNIA8BGT&4NIb{)Xk zt`j)hEd$PWP2hYz&I6q7dV#ZDA8@u?1)S~rf%El(C~&qL1I~8iz}ap)aJHKO&UVwl z*=`0n+sy)JyPd$(vFE>y-!2 z_38%Bc8#&6dBWEpP2ge(rR~dh9l+VH6FASm zWx#pjKVxx`FfYiw8LS=>^Vy`hatMs(^F8`GIr3g@ALug@JRvMSyd?qQLq7 zfdp`_R}whaD+QeE)d8ICrh)Ty_8f4w+XbBM=7F=_Zs2U!*rznF_`0wOob9@Rvt2iE z&bM;loNpfBoNr#>?57Vn=bIlm`xyexeujZ_d?LWvZWK7*|C0dDc9X!_ZVEWt?Eubp z)4=(@og8qs+XbBM=7F=_Zs2U!*tawv_&yL5INNmrXS;6TY_}Zv209<>0lta27x=Hl zeZc#FtFOyf0q1)8f%E-TQQ%y!7;vsv95~mj9XQ)f0O$JsgfwvWCj*@Q$pUA8 zI)U@}nFGEZ#jOiCkE?m$Jg#;F=W*58uQY!+4o=`)UlTaj*9DyG>juvCEeFo^^#JGk zdVzC&eZaZCRlvEve&Af+FmS#vD+-+J8w1YujRWWUwgcz-CV+E&lfb#YDd1e+4&Yqh zG;pqO7CGIQl>^T8?E=pA%>(E9b^~X-#{Q-G#`mL|z}c<~INNmtXS?OV*{%n8&wXgX z*=`6p+YJL}yAj}QHwv8Zze)gSyGh_|HwB#Sb^vF)Y2bXnZVoux?E=nr^T63|H*mIV zxJ%oY?|V0avt1W(w(ADYcFTdYT@P@+-^>r3?S_D}-7s*r8v)LCqrmyT1809iz}apXINOZ?XS-40e4k_jINMDEXS*rjybkXG&g<|ra9)RJfU}=j z;Jgmc0cStEfU}=@;2fWB;B40zUz#WU9Eu5??Ye-oT{m#HTMnGa0D{6zvd`xv9;URPv+^SYuF zIL9Feoa<{GP?`^1F9&e0mlHVGs|@%k8c$5%dl7d5AJ5|t@N(kiz>g&E0Uo4(=g|wC zeE`44myofV15waDHAa0i5k7 zfwSEdaJJh4ob9H8^K)T2;B2=GINQwwXS?0N*{*R&Y5VeXUM6t1>jKVp-N4yyIdHb? z0nX14`hm0E5OB5|2F`XPzs7X^ZkS_8}0_aJ?ZfP=k==BhWmi;!ubQ7pGOPX@G$V1^!o!* z;C%mi%!bE-zedjmCxG+$fus#j0pEw}l?KkwWn^r47Py=ANS6)I13#Gb7>AYS z4?ln8u;EVN9rT=(3H*WW|>->-n4+Eb<{zQTE z`YmR|VT$o*Zy~F15>s=Yd~E&yO32m*x-O zC+V=^PT*IP9uqj<-|MpBZs3ckULN3l|D@N3`+zr+9zSqC?hD!QFz^+mCkmYJLyOt) zIPgQ7WjFjCkLF5FS=}a9(bJe7)O-m4?l12u;EVN zYe|m@obUg4*>E@TTS$)wIIjb}Hrxk%9qI7{=kui@8y*IJGtE0u;C!E0%!bE-KScf{ zfb;K}ByD&Kc+dI=IN!gNvEfL_?J|#G;n^tAY;R`z`r3qIpCX#cLC??8hPOT77Z=@J7mUDrTN46?Ko_>6S$M~ zn7}`y{_C>gZs6Qr9^m|3w%3OHfDb2s{K)C|SVA^D415gfi2~>6ePT8|4tzh-lK{@o z>m_Y?3ix59Ck>qMW6ap_EbxDko*Zz#zqiYV=YdZoJ;uLE^M{Y49X8wvd>ZL7f%Ew* zmkoCVKY)I}&I6q9@AcYnAMj(yA3tzDuO71DVc-i%PZT)c{~xpAao~$cPXajKcb&B1 zDd2UaCk>phBV=rN7Wk8NJ|PF3?+fa(;d$W8$REQ~nm>GBy~Bn(fuBoyOyK-nfXjxv zfnP*=Jiz(BGOrEy0l$>=_<{5NJRut%27V{$i2~>6ZDTe(4typbzXQLI^e2Jye3Syt z^G+H#pa0C*@GS6$$!-ofpC|9K;d$Usk{+X?G=KOxL5B@@0>7V+zku`a3c75#8~7XK zj|Vv4-|MyEKHzVW9zSq?t~_MJ!@%DoJyGENyB{$d9tZw0=}7?R=X{ekJO!NR_cU<6 z-ymbdv%oi!KRMw199fqQ&jbIF^cWLL^M|irIBd8R`0u301kTsxT{hee{5$HW9^iak z*lWXm!28p2fgd>k&P>RLhk2;d$VDksf1WY5wrCkF(#Gf4?macu;EVN$CDltIRBoT%Z9sw52xz|9^m}@Y+f7g171u1 z_<_Gi$I&6+{QG8M;LAu)6gc0H9kbza;AfGZ1aQ9JIBCOEz*m!=G;sdCzKjje0*{lP z9B_UvtjmVyfnP&3Dy9;k?TL_4g8e2Bz>g zE%*n5X9O?rTilTqd`H1M1&g!S@n&jm~1djui3^ z!M7FMDfrWZmkF+~plREt;2#Kim*CTcKW@Qmg?zc-w->8rcm(e+^mqloQ0Vaqex=}5 zg1;g3`vp%5`HN(_^ZiUnh7>@E?SpxZrmS`F6o~75*m#-$BSH z1%FrYl;8ouI|To);Az2I1C9-4;J!y!Pg7k zE%0kS`a!TgZC^-(PUA z;LC&_pWsIeUM2W@LXThY--LWf@R5Rt1^-6qi3qNbeDuz!;1h+OnBa#99v8e^=x-N% zThYD=!A}u-l7gQp^rQs;S;%(?ewyHE!S@w*GlK6UcvkR>gq}{pPZj>;1fL@0y97U9 z$ma!LE9AQcUoE)tQ8EA91a}Djkzvz_X_S3+$VU2@TW@fp9J>{e!Acx!IujCVZkpJJR#*_1n(656QL(3_;$k2 zF2PR{dh&u#5%S%FKP%*oPm1~P74ir z3LY0cB=ocke!uWDA^72fCk3w)dQyTPDC9c??+`pKc&FeQ!FLoqEBGUVcM5)l;5osk zia2x$9v1%R1+NtH-Ga9W`B)!)G-jC`AmrNxe@^(56#O&6I|P4C=+6i~SIBn?zMrt$ zCHTJt?-u+Gp~um;=>IN4zD)36guF}e4~3uQg6|;ocm=;r$X5wIUg!@A{-od$!Pg2s zF~M&V+&iLJuW>?8mEea8KSP3lDC8r8-zIoW@VkWFcERTf`J~{p1@932IiV*b_}_we z3O-5r-zE40p}$-3--I4VSusA}3HdU?s|0rm{+8h7f}bb!dj-E=@G8M?7Ca>Q9fC&$ z?<49P6Z~Ew-!AxpLOv<@lR~~j@QVe{2yO^Hor3Q#;?O1d1A=!8{)N!**s&P@KZJal z;9Cp3F2T+qtMeX_*B7@f>#LMA@~b| zX9PC|?-cxd!Mg;1K-9Ne@VMZPor>|lL+B|J+$*?C@SNb~f)5n&@e2NwkgpQ_KEXqR zzan@<@D+l`1b;&CcEN8IJSq4v!8-(hQN$-B_*a5=3jX~6Bks)uqbQp9@dSv5b0ZQB z2of-2Kv9CO63t2i1SYUikV6y@5JUu2j*Xyz1d{;kIvQ`h(boeNeE}5#55gJ1D}V=} zkboewgiBOz$nUAD-r3#_fj8#+;m05BR`t_8Rn<>dcTakDw00~_KULEo(e$5b?L=P^ zjQ@`sK2FoWqTv%YeTk-Tr|FaQ_-p!iG<;u8AFW+?xTZg@;U{SN1Dbw@rvH!D&P+}J zi>9Bg>04;}g_^#xreCe;Pigv%n*KG-9!t}|q2Z5c`eB+rx^Xc6DO%j(H2owEpQ!22 z*Yxc){S%r!hNhpT;rnX(0!=?$)4#2?GeOfQX!seLzDUE*)b#T-{cKHtSko`m^jVsI zwWhycyY5C!pQGU|O}|&uAJO!MT07BAg7IIi>Eks0bWNYA=@Yd6YNzR6*RE@5`aG?j zzM8(8rXQ~9cWUiS(Dc`8_!*jhk%phC>DOrb*_!@dt(}FM{yPo7TGLO^^cyvOs@9IB z>EG1waV4@pJs&zPY!UIAzPg4_)buqpeH%@`LDRR>^t&{BQZ;>)hBq{Qu7>Zf>5DXd zUrkRw1pW=u^w9w&K8I`inwoyJrmv;xCusWGnm$|8*U|JdH2vjTK=U>I^P2rLHGPbx zpQY(P*7UPAeLd~Eb2Ys_E*5HfhlVfE^wTu`YE559yKa%Dzd*xp)bw>Ue@isIOVeAL zUf*{d(DaM6>mJec7i!my*cRk%fu@hv^!k1JH`x7;NtcGu+ z=|9ujZ>Q<6*V;+d^cQRG7@9s#(|6bOS8DC|)$|QD{2)!=NYfA3^p|M*(VD)ork|kc zn`ruMO@FDTpP}iSYWjRlAFt_WYWgoU{VYx2T+`3i^p|P+xte~WreCP(6EuB+rhh<- z=W0!VxrQ&&^n*0~Mor&A)0b%a7Fs)&rthrr;ee*Ers zAEW78Y5F)#f2F36*YvrXK2g*AHGLaRf0d?hr|COu@k!P6tu?%%>95xG-8Frz7N5SF zzKw<-r0J71{cue$5tPEwn*K4(&Iy|SI<1{-O}|~k&(QQ`nm%9CJGFLZYWnLn{VYv? zgQlOY=}k>PSJUg~78YvyWDQ@S>2K8Zt2KSGrZ3X;pKAJzn!c0fZ;7VANyA&3K3&5f z(DcnT{Si%{qO}w8dyxNQHGH(Dw={i>rvF{j$7y<()_%OEuc6@+HT}&RzKy1Duj$)q z`czGys_8%1^oFK?RnvFZ^c^&PUrpap(+|@0oizP$O`opmM{D}dntp<&@1p6mHGPJr zpP}iyYWjRlpQFWdrl#+v;b&=jx2B)1=`%I`TupzAreCP(Z`Je#n!dZHU#;nTX!;^e zzem$=)byE}UnQFUTTO3i`kq=l2Q+kw`?YqWHGMBlAEW7eYx+1% z-$=V|yr%D?;S)7|Urpae)34I>?KJ%Xt^HI@e}{%QG`&y5ch~eMG<;u8-(S-Y()0r~ z{cufxm!==B=?7~137US8rq9;&gEjpOO@Fth&)4*KX@1Sr^dD;aS(<*a*3N8A|D&d# ztLaB;?JU&vA8GgkO@FVZU#;oy)AU7}ev_u(sOd*&`Vvh)SJPXXex#;9py_95_8-yo zqcnWP&LIEq*Ywev{!gu)7)}3xhL6+qO*MSHrhibwCu;gJn!b&uAFJuxX?l;QH*)qw z8@{N|a+4yAyaG>@)eXB~BWFeQasib&>wA+T$}Vq!{~b+J@r`8ui=@A#4F4{#MKW3J zFJieG$&?}d1uP$%0hzY${<$n4B$>AC{#h*VCYiS0{(P3VlYAb@*(`4+nYPsa(JZeg znYPmYK`gH&xhBcoSzbmmZJqt8EH5URw#@!EEYByo4$1K>e?W3wl4DqYi)7l;`Xg9= znPl3s`VX9f;__!mjv={(<;O{;t*F0<<;O^_PjUgvkC04TM*m!v$CBKDlXSo&0w59ULu-u$v+DiE&SZ+izZK3=JPLluiNscGEgymW!HzT=-+9MAFxB)29xhUK?NrX{~Wg5{SvfrljC6VEGY}uO)dd%VSBtj^tS^k06o?n*K(sr}tq?m#jvrTwWa-$*hoef@1%ZcB0s$?+_=BAJ$) z{uq{S>8@EE&cr2EN>>6mVExvEUzcoAbAkWYe~)^xjW0tNbX8@&_bmk{rYGTO`xc%^$(?%Ou}Q@_}RA|0L5=&0oUu<0R7(&0oaw zVGlH7~rSuBqrnU+HSe3tJfnU*^KY?kjN`F4^=vwR!LwB+#* zV!12Hv~=-zXSoB(caogS@{J_-Be@OBZAqpjia(y^RwUEX#2>?QbCPLE;*Vgt5y`X^ z@gF$K{ZH~Bl1o^wMe<;hi&(BkGA%j$1uP%SgFJ-fxhx+fc__)VSl&(YJtXI|yq)A> zBxkd{nPgfT_(!w6o@APU{DW9tOY(grcV~GS$szm#kCRMOu)m1q$4I8B*I&T$BP5R_c`nOi zNv0{-Ka1rNBxjMF&+^?QKSXji%XgAIp5)Oi-$wETk_WNemE?y>?#^-tk{=;CmE{{r zo=9>VmfMm%iR5^eTai4O87?$56`AL!^Sbmx0r$|0&xh#(*`8kqju{?t0=Sj|I`EHV5AUT`mJ4t?#= zZ;*W8AMSsWXOUdOaxIeIB)N#?Y9zl!askW7av=YQ8QUXF<*>JJQ3E`(KDt zQgX`v_KccxaZcH*j@&W6|o1@JDm$2~Ybe z7v+>4^K^N%7YeU^ND522p;L~$jran6KUHaih+iskg@~6c@iP(oOpr$26>TZJ*IHbkiwX^MR6>m5t&w0g z!YD{LI|ER+J^`{BP$Pj)OBmk$sDD10 zrm58x;FjSnW{iP(Myju}t`hux2Jjpz)y{JoK9RorU|pw#=tHaGvto>;yX)m_Z))Tm zyVUWAaons;=2}6u_&i=aod5sVioo*?t4k`lk&@yK8yAVMcY|#uVy+kKRVhBZhaUk#nTp_-X@|quX=G zp%5Flg9FM+XnzKLL&4YA@Jo+WH@wRbruIf;k+JSb7FUkF;t{I69+eI6sZ#&R?qjB{s}p#@c$Yne-kEu5hi~a zCchFU`@-ajVe-gO*;q(c;$JH7lp~K!XlFcBd+Bf?bg91VO ztzQpN&o3?gewd?aC;00-7~&sB=5fO}Wss3q1`6zBaB)BXKi~r65&oYTL;LhRv~*Ec zY-xvJ`-ZPyjFI=N=NcntVsu2-0mD}v?2nJg`or)|h%?O5@rHM|wE#g@$gH2aT{5-b zfaUqUlMeNidjPGQZASl8&nxShb&28K@O3<5wuFX&bq5V;Z$}uiu^&-339RrQ!{8g9ipG5HkU%=aZ;6jx zKh>_^Fs%Nc<5m4cyZ(9Q>&M&mH<26K_2&iZTkQkaU$wv7^@H_a3adXRP=B^vf7+Sq z-w{?nDNuj7UB7er`f;}X4a4gHiD`%9muS~NuYCQW{hPqJ5dQ=9t($HC_m%VCu&@78 zSp6}9`m^o&)5_NmUjL4;`bmNM!|nQ=?fRI#dZ+aQ>reLlq6SO=H^J{RPlnsqJj44B zlCUE;4zx=1bxMfOE6D0%cu!^cdL_hUAiF26v97}K1z$5jTdRlyXF9J-BF-)YZLLR1 zld}R-2RN%ztne=5Yg~-}rDjB)a?GGdy$sVs)KML>Oteh9`Y?q$8J3h9QlT z0vGcn;VR#^p{o>HzwQC>a708rH848HQ^W9$j$?BM!?e5tNA5%nM%!e}sxKj@(#$yq zB+kq`ga&ct){%}GB{0WWjQ{9gsu8)_F@x5rhS}>9vTGgEvo#5g`s)SrsoU4WjXCBW z1k^AmL|LOK_-5UkVO^%T#3)<_CcF%s&hW0V zZii1vYm(N(N@{#H#lpMX|01tMiVd#^GwffbR2$zAYX4ohh{TmbvJp1$%`r#Q2nL*7cayc2%tGJQr=Im)X!zP5UPaOMB>2Xn zBMYsDG;jKxcW)uP3;P*npLqXgxOF3WZt1>yIe#=Q{TYd8A?8XRIF6J6@xQ~RL*}ov z+YRp#At9DdSUBbEi8H)dLa6x)$q{*YjptUkc^|Htn4VNtS_gi(&54nj$@|CO(9P`c z0yj$CKF^kj4Bz!e-XTwOirU?X8s@@lAO4Z@wZmUR7OHb-Ew;WjUCf(mZ$?{447=*+ymj@(!jxqa6r?alDj z*yr|jhjzUq_aNaN3vNu!Epz1VgpitDHp!7o_pLL%MWrp zbAQd+o0(kX$c+RB=y5_Pu@9&KooxDpswOohhjg~*R{L{O(^o_JHXy=`@ z2JZiL6?Ku5K1z%2{zR^$>E3g(wS6~t*n}oL->&NCPr?AmUr0%@U$FnJ<6t`VE0&Kk0anz)D>Q~Q#W|E|>~W+XD#T*&FHbDKM0#$ebf_BT_2c0}q@yydCw%AU zlr+sb5|y<@me9}a#f50E@bba{$ z&Yo&PdtRha{X2WoZr2Ap)?zt(K%TN1j@)O6sT`}HJS{0!ix3y^{blHJu|)6c(~U<% z;+N$>M{)(v2F^pi>Kx5Fj=Zj@|8*VoB7$k{rPP_nB+>cwe_Fr?A3~9o?>h8AAn=GgQVDr{!2-)wsP|YNY;+r^|++lmlcO8 z#*w=cLZ-S7DzfjnpKbeE zhT8YYj?>up(I{o#j_U&UEhC)i9FMIlW{w$rVP)U@n7YF3>m>H=zCyDv8!c31-`_vk z_IYu)L5tsFic5I>>IUrVWZTzV?5jbBnJ$Yjtn8~<-oCeK?3m83x_u?TS8QLepnZOH zgJ$1aNiL!Nd;drkzqe^a#QpmiTE`Xdrz@H+L$~if1S>3lHN?ITT4?c0J%fFp{%FT9 zBhKwRHPtp@oY2w?WXp z_c8fs@$0(lH1@R)*f+FoAbuUhzU#!kXx+Y+Q11emPf zIqY5w+g~ic?z~Th{At>6FeM(`#zq#1OGDXKzYO_4h;PpEz>r_*NI!1_ToZ`xFkB55yg(M1u6}HYifv|jdo7w#Oy`r$wb&+{#ojqZ z!Tt}mw-sI6=N!iXiSLWDepB&%bC|MsBW)U(3k$Zg1&7H3)Ab=6qU?PQ!3>LUJF$0b zGtFKPTA=u1FHd`@cqbI9Au4ci_S@FHypLbw?%lu20eC3=?WqfxJW91u~i0!fR(@^DO z9qf9fFL(dOR^QAPy5_R+sxQ~Up|HLj#fwO1eci{|Xd$rvDrax98s9;C-^cwrwzr+K z*ZPj^ZO22qafrDs0_F~&%@9-XCNcLpGQe~_tDD=ryt!Y=qH0J}txJyn%8Nl+FP5`c z#kW7%B+ zE*PZD-Ak)zHusy2Y;J~_o35KXAF&KGH&e|0>k`deFIuqgUsN>S8U*e2V)hA%?~ygk zhZv6Uahj}cgQEflr`QHJ5`#adh?%bEIB+Vyk>w43RhD2Kbb~kka&|rpC7Xl~oA|~Z zW}86%HN;;0bp`pMTZp~A2dV%+LF<1G@CaNDeE6CyFkL&?5M^%k=_Mus%Od1jp@&i{$1P!#<~pTKR_$xxK}U^v?z;U-!^roPAyU6Tqgkn)teeolyNV z4~~WT>Xwzjw~=zUJ#}5cU763U z+NbfiP;CKey&UTA%KpmV6SPKVe>eZg{=P|$ny%@(zf0jlkZvfbI z#)`ki7gNWn{#^&>!u%b@>p5qAhN=55v(duY{N1y{?%($@LxlK?4W;69y)b|8qP0V) zzgN=O4D)vvO~R-3cjukT-^R43;Ql?fp8Z`&9+UC%Lw@%RCHDF|jzx)Sy_V;Syn&$7Lv=#{Uw;PSs zFn`al(BG(lzbUkQXMY>PTJZTd@&Nl5c0~CbS>E4QW%bmdf#&bVqO<$kV42;&o4`oj z-(bFKPodZH)l)Pz2i#TpsvnKjFn=$mRm5rgH@2_pUpFnM+22;M7XBV04@}oz?1=LB z0(53r|IU%s*KHSS{#rkr-QP}2ZGZh>+25|P7XIEyJ!ZNNvm>g1lhB!A{(dW~ zsj(Mm{zm@~{&reo`&%>I-{AOtfMT!t`!(h3P=9^I-7tT<(4ye9{-*a<{!XHWHT!$# zcL1Bt#^k8!x=i;s4V@Y0?{Bgadn`utHx4bFEkD2dwe4?1jKGlo4d&-ZDfXJb-&4L0 z_4gIxZkWHf2bW=l*49_OdntdPpmjO>JK|gRcL#Z3x(2c%s(*W+GsFDdLlMUxZ5^7w ziD=<${?7Tz_O~TQV2HoL{(X{Sulc)`@^z@c9};)N{Jl504h!@5o}S9zS84gk{yy>z zdr*xSiv1ruqWm3<&J6SSgsjHis;Bwe4lSI`-!H$k{Y}OQ)cp6*fhD1XPGGsFC?BmT~>tNCl7 zg|qpa`-Saq21cOnZ{Ohh>SKz%*1xAHVFw(ReDw`+H_YGZ!DU#Ozj-~BzhBbwk^Oyn z4f{Ko95r1-bbqJ9xiEhl%j$Dk9nIgqXyI)Be!JNA_YRD}5PyT~=dUUDn!okR`}-?# zH_YD`gUhfmf1mHJ{QZ^|{Os=stJ&Wt$OEh=x#Lv-J`Lx>{Jlz6W9w^c{tibAXY=>B zMYg~9VFZTw8_ZYVQ|vW=FQxe@w0}#9yJ7ym7hHyg`TNeT%HQ8;`N;k*E@Xdy5Pv`C zj#K`=3FpH6O_9~u_F9_16VSrh{N1zA_V;0ozz~0f`D!c0Ui0^Anx8`bJx<&W^Y`=M zIxNiJ&u&rv?xA%u`@41(`#VMUM}^#R%HMf#F3exIti}%3)cl=+7S85xouI#7jKC0o zao}hIy`@4B1`}-g{YPx=4N0h%y;ar%% z{be;)P4{;uS~#n}pWFTW5=LN%zin)PPf_eOe{Z4rDb(LfXsm|y?=Qh+SeU;*xs|_l zY=3vJV1LgehMKNjy1(n-T$sP3WHnYlTI=80XyI)BHeO)+`#wgX?r(5DawvBL^U*+> zp91cx`RGa-t6~1`3NFLK{N342`P-P*$=tukmb1T0$pfq>*%8&h+u&T7zmsG&*8F_U z--T$w_BVJwy2od5Q9mDDK<=pX(L-fcSbZL~gPTyxtoo!WcRpG>Z+-OBu=Yl4?KP10 zCIs7CM!Dcj?Y$Y^UcA=c3d!P$!S=?Ut-Xx!_KIlaD1SZD-o_}~-{xm)&;Lo7zu8)Q z3DVw-V0-H+7o5r8r^DN8qqX;=Wbt;v_8vQ1dp*M2E1{7SIR7r~Sv72b+n%jG|NJn2 z^R@P_llEo?+uKgPbw+=~+e_8j+d;KWrx9%LnX|Q*9Nyjm8ac|}=cK(O)op(}oW4Ci zA*-F2QujL>Q{!^~{3Xmrfqa1TQjM14DtQI?gQ%wiZaG=UM4k|7CalX^K zgvNeYKKLcL%t6HT{l`yT0{M^j8JrJxFX6~sKuj=Q#q5yE2kWqW3d;whWZczfSm6F2 zTCnp$1^!+&&-V9y%to5OJiluG)(Z3YPT^6&-z#Z>9Omz?;4&x7-<_QU`Hz<0lK;MD zf3GGcn6CZR@DaG*xed;R`8!F*U2}#7?*E~MfWK+I@R$4EJss2O$2D>5-jTN(cV!LV z)ky_bckmC#!*PBw3x9(j60c6xquWyH(u)v7%e@TNcvsQi_Lu&F2eZDfXWdaC9yXX= z-I4nxTB8&7f8$ftn@;r_l&{xJ)q8Gs^{iCm{o`e2Wm)I(nf%9mF?jqd=h*pAS@2&=4{8Y&tugbxi>(OQZH+s|7sft zH}Au+AUC}m$w@v<5d8bSvZEH+;mExi^@6svq4s^Q9%9Q_bgZ&vJSgC=PuIu~xqjIx zzW!JKL->Ld3+Jb+-o2St-Q2s4zd|kTyrOzuf>;@&ow0D_EvIhcqfbwNoD_kx?CN+$ zZG;5uT<)0h1rQm&s}kIFEYo*SMB3pM5%D-zKPqGC9>>?wR6l2BOj^#4>S;Jt8fgqE zvz|m3WO!Gm=k0j(nzWofk#2A4t>)03(ONvv(R73=XJxcCh?wr}cm(I9vvy^A9~cDk zs3Htd`WzzWd{Gq0;9Og-FDY&noq$wKzxNqAvk4okJp- z1#=u?HMF<6j&RginEriaBLiZtNrTL+G0BnlzE(_#>(dec_E8-ow^h2b^QcFnf zHt&x~^A@J%>;kW+Fs(mFSTnq<((}q5O-#$#4_g0ot2yZup80@3;PcAp4B~VC*JO4& z_`55puS-mz=lVkPzyfw7BH+e*B+|)jD-%uNxDq9#YKxHsOq86a{`H~tudwUa z4c5O6M*Hj9_4Pb<_@v4s`|u@jE?UcT7o%1RPDS4V>;1JL1p6o0CvBlm%{~bjJ=@^F z4F4e>8NNE8xbs3;U7tExTb_NirXfiN&M#Y6Q1UjN-yK&2jt&P7S;+OZ@m{FLJMrJm z<9(I?VO#}6zFw*t^7qhnc*tKS^=X9CVKR`2*y=kE2ghb(bk<17a;rYL!`dbHy*wjM zKOmzqX7T8ln@6Ix84V*b#TzsE_;x=`U+B--ky#71-0b-!n~>ZdPkiRw{?%++b_9;jU4#9cIyzUx(W!1Azf*WHrk@a>ijjwsExYQi}Q4W^#S5ESC7+w5T`eSae7W@-v`4L zoG<+Z`JPVOts-Wa&Rnd?D-PM-$O799Q@bu zJ+vq^zQZI;)A1qk-Gz|a@tr}vX*#byqQ!T`rySn`(wWX%n4&7a9|r1%$9H&&itiFy zYjS)iqnVKN%4do1Kkw-AeGudJe~It;v`EJqxg!2v!R=`AZ6Ra)U&r?as;}|)JfbF^ zEX9Y!cRE69$2Sp~8KvJJ(&9Vx6OQko!(8z=hhD|ETcB=ue4}qt@f}FJ5sq&YG*g-Q zzV@~rUkAqh{}SK#XiIX2_!ffSA^G8=D)RSw%7R*a-<2?BVSOj@y#gV%g#X}o@p2a+As<>+-IH+$Pb22id$W+MCW$SL$(O(mY+%3^Y=5l?@#EdU zH9t~d0I%Z?FFTIenVutC@0lOWSAplqvR?l>@C@1e2tJ;R=4Z$*%fNG0xSv|!xn4a) zHj+XMxdlH&mIBiyE$H|_iJ+0|{_AjD@YZgA_ak4u= z75ltmdeUBhDNGE^XNI>ZxCFWZ1=+{20-A;|{+9TUrXUKB=}c$#sT&D1u$Ei$DqR+j zMJEu>7uEF!#jdHe?_hQf{I9S}-@l!OUn^!+$gjp?$T!?w$`E?y&>knVC~KL{&IdJq z{q}LC`IUj3Q!&443nN1Lm2xJ2z5OTIQ*6!qh|CM+S8Ga>Rp8f244-qwuO#e~5Z-Ia z9n+PH58>BQ>g52RD$lQU>MqmyH}{(A)QDWIU!BqoX-|gG#7FaE39p%))Ao|3>fU5ym{3W6d6Due z=2tgiL}>nsKNG)p>>+!Ktv_d%=hywXR#o`rLf@V%evOe$*f?^>bYA)>g9hwKQ`g^ocHl4RP$prdNQ0}Yg;RRMbbK)`BnT*rTJCo z#R~Z~Tnrh>^ihUPK{m1Z6_3dR{90vc{OS)ADw)65yniNs`Dm64=U3dB_?5u+6kADe zm*>|s8H5q+-uJ|=i_E(?mVty6iL-_SD#!VIY^)!XYbUx>&UQ^vV8)-e9Un8zm z{Cbl%7|gFJ|EV;;K7Fo2e(hn$oDFnCnvx-b`LTeKf$1Ff2U)7-#}jW=nqT)Jj`$u`6bgw5q$}=iOsJ;m@HuF zc{|8b#jjUqRhnNlk@70$*EclFh3Bs`uD^!}?^Dmg#CkCaz2zeWlpLi1OHGtG}R*dE;f zdaXRaOkArf{2GA1Jy-mCTJ~4ZmJlCYv+yDOx&z~;3j7+*?Kz*Ik3hH1Kw1yySJwo^ zuc@?BV}1?9EwW1HueZ$#`Bhv@jyYH9>-#cf6PsVNkaz&-Ot=8QetV_T{K`PetC(N4 zg%P3rI^+F`x3`i#xc~KXd49FVwW`9elNdhdieE{x(Yu!1!Tm3M2)~X}FaP`e70vBA z_v`EXMD%1hzjilM{Axz)aOPLpOO@tVCtrp9nzDr)b3RKS0iwTwY+~~(6_W)3fBZ%O zmA@vzgi7WwKk`h){Q8h)x$yb1&YAL8C$8q%8+7Y6PsVzm@L4r78^BwefeCa`PC9BuVQ|c(kvIAzs|V+%Kb(7 z_4Kpl`BfL!stUihVECLXeqA6Ny$i`5-2cLd@M{zG^1q)S&!g@#o%M8nMWZLf`L(u@ z;#VYX2$)~R&s3UUSLIg7ugUC~^981l;@1>p6PsW0m@HuFs-LJo)%@5WCR8$it$E>0 z{PNK(7tXIUuD=r49^C(Wx;(!=!nLZxugU1!bH%TDveEnGN9I=nK7?NnW874MU++?Q zOy`oHsn=Au&PG}f=huih#jiJMC&2ugl3!_leLJ;6el-z8(sV-&`J3FPyrnnE5xsU0ih`t2b#OBu^Oct>8yme%$;@7KYrTJA8DX(IFeM7Tcc>X%$`fF$r*@OFE zPn74^Udm}zSl@qz5qz%r^`~s~{`vv#;Qkl95`HbBUjFy<;~x|r(|IwELe;Gn25~sQ zKDbcvYa1=VnO{qMmF8ES$rbWzfEe-`(?=OHkPHdruLxd1JKz1D`cv^M1twH-etaJ( zuVQ|U6h?&Ruf}Iu-`8M!aR2M^^87M!t*Y>A0Q&Y^@#|^Y2V?*K9eucF;Y0X!2gXem z_%)5fgH;XDHjuw&AgzbzwjaaI!e9#@AFp+>MqlnMZFu~S0Z{coL{@^DSkDhbvW~@Y+9xHHFQFS z{Q8m|a~@^-sQmQ?vWd;FR7@7I^p7=Usp8ipm{7_5{zvKHm4}%w0kD;QUuM znHPFKx-PC&6@G2O@Htofx^)Sv5!Ae14MmfoOX6*LSJg*ShZ*JVcXo63=(nLs9CXmDN24{>PIZ zmlD+LhkJ*GY_YV9fil9%LSC_%b`hox^z4_*$YzzvZX;vzjl(M`-DRDRr|3PO4$H>_ zto(>!ovioN10MUW)j32kyd)?KFA2(^UmyXWZsF%U_FF!h)#PAJ3M1-~jV0S|+m=9NNm zh?(1a*nak7Rp8kVdW0U&empOGuNRjx_uj^baBl#{l=ypiImMmcb0u$PigM%?b6pHL z>s^>j&EqlMZiugcB}zb9dd@fJINo#R{}c+A@pd-9j|KVtnhdHx#%BDh)Q~S~ zV-3al2WjodjNdy+7;is+9eSSj^n4%wz}fkJz8I8g88ze7E4I^X-6K3t#T zL->CG1EN$ZDI=;Gk>d#fQKicYcN7K&+LAww%*o8_sL6tVyLk^q7I4-BZ}`qYnz zmwN|X7xnnw9P|v){RVz~FOw|uwVpl#zv$tcj33PJ9Zzo#Eu=N9_CyRn%qRH>_Fc#J z6z)vYSa%&>#*e{4Xf#gGv^EFVvvu@}0-#IItPw%|O^L!=-bznWA z-V*meJkNL9x5OpT^I z=cC_I;OF@s!WVx-{D+pfe@*AT93{04S%@TKv#kN)d{K{-wUM78nMeB(X4_Nag>7ei zo-dSd-wv;kZ!5oI2N#or0lr;BhR{SsfA1*b1)=ky#RO1%s{<1%$+w3o--W+(Fu=DI zAw($OE{4(I8(!EUe7l`?ITiA4#Uio~fB(n=DvWQLeC>bFwZy`&zxO# zLzYa@_%`TK>Okjt3pKvI>Zvr}Y9b|8$hU9Nq2==1F1)Ep=i4q?<5tMGUY`r!29G0i zL-X4f%6WPJo^Kyvc%37@ZI>Oyjs?uOKk*@a`+z#V3i)j;g$KWt#8Faw+lWyf&bOD3 zDZZ_veE{?Azhf)MH#`r&120IbU_NauhLka#lp(j0A%XmMfRY2=lJ*((r^;_v!GucY zx0fC|-G02Yno#=*BRtphgzDxA)j17TgK+YSs)uP>4`o|0{;+Syr(_@Q|BNorxBGGJ zz`Bv<)8O;*$1#hX?)i8%pJE!P`P7BZ4)Cq2&&Qu_LLDPZ_;KV8?*HIJ2$zg;6tX}6 z6{i31^Qn`%&veG=d>f9Q4d+{{BZ_Z>X`RJH}nMXns3MIZy3V{te&0!|*y+e2e7GxU)LBW4dDSA$(gyy&m8ft=}rgx4PV( z^Ky=o>gFRDpR~?mzWs22rTJE8V1;~(;(_G+;}mt5GUP!rB#_@?FqwdF z3+56)sAPUyH0Dfvn<$J3<=ZWI#S{33xc7;-UZQFJ4Ee1F+lRmZjw;VL6W6W^ z-v*$s&lTUE=FPD4+5a-%X5mBlb_d2$75H|k@U85G*3C1J_QUzs^)JP@skGo@z6~5% zX}V8@(&=p(?lGGrT@Z?lk?z_-pH6F~9pw-J@*TLw~M#rdtaFd~$1=fP_5 ztuOPfCH9DC;@fi{k$uJ1oA;IHTN7NnDtz0E;dQR~){J(Lc)>ThW4hYlL-^*WUjO&` ztu?pje2}B0(n=h9Hk@yp4=BD}Knr^2+y3E|=34?@C{@Awt-ly@gU+|7kZo+fwZUY9 z0Q~$R^{3+7D40;m{I&^sr((XnLbG7_e7Xv+Ndn(enQx0|T0cX6OJMtO{u6gu!{^hF zDCbpSKAnudK39C3C;PWgK488T;6wQKFvd|8_?AWCF`eCYzRkuU59iy6eTr{y(vF4s zHf31l_=a0qzu^T)74R*J9dmw9AA$VVlne>Xrv;Q8aQ^ds0w}(nxTn&5yALU`!u{!0 zLWt1&Ay>d?(9OR8)`ceaP{swuJM8;(HrZEfEgeechOXaSeC>a~Kdp&`2Jf5 z*}iomZ%kJYdyF6;fJ5(6e=5E`F{ILbJ4$({qWf=O(j*vuzxVTA z%s2b~+b=Y+SID7pL+^_hybY6gOZw#(9-~PU>LcV=2hU}w{Kz?gah6M6k2_*-d ze|cNuTVt3|$@$calvp9(+(L-Z{MH^u>-p_on%FDk+mHVt`--h?1IzPm0AKsx^Q|>H z`yBD@Zdun4C2vgE7<>rdT45Mfg>OaNp!0n0Ma8$i=-F_-HQJ^4)`J#UoZqfNL@S%$ z@B*g_^4mSaHz#+OGUNxO8=G&Vu~q}$E_zGj+nl>9&9{a~i52qgH*{$E{D!wMfp2)B zviyDFFiq?g@@?pw!nZL4$lTEUwwH2V74G+bh2eFM_;ygXZ-38XzD2?*;oD;B^eW`H zM}=>@#=cxhS>Wm_=*u1xbU)IK&9{6?Os4aC!Ug#D?H!fo zTQX8&#rxCa=ut{=A@_T?cGdXS5PQTk@h$gNvJdC~`jWY!`K>OlT@}7+KA2YXkVZ@=M%P8H<0hh_biMGgk? zn}ZAq%%^iHIhf8qGYO#hwx?I6`F00VVugHbEQAQ%FI)km_4V5gG_hC6x3^y;`|$iv z&+>e0&DZ|-d^?HZb&mMfR(Nq8d1JcL@F9FVMx9=T_1iPDetVLmr1+MIo(<>Q?#+sC z&8PzNt?ah{fp1fT=ijh?>(q((_H)Sjw>U!JRlYBfXHLIv$QwvEHs4Y)nE>#|^VFY; zZEP>-|Jt6p&7mbbjI0{+lKyl4HMzgOkjI)|F;L3ADZtzq8zC1{~kRByX@b$ryq$w-QVvwKp#BkJQ6TdI!b^8ar1;IpFGC|EWn2l@L_~QpI-y<$}6IJ7?$A=9Z-K+pU6(# zv(+%W$0Mo~#0P2Z96F9e&eQ#JQk|!3ftLMiAb~ap+vA+iQC9pNj;vwxcLm{mQLQ#A z{tl)E8}qk)_cQZ%xRK-9jWmms_@5^*N52C{llEGNFziwGz|J)!MX!d$ovq(TcAtt&IV zB}oNe!=MPOGYv9d?0C8oj>cwrGkm?#mg`Ycn9iB#OY1RQnqDOo)dNaL?v>5?#b0?% zFT=%ij^OQiNeBquDwR8#G`>wqmup62{3x7(*OssG z-0n69BRYwAj-a#-y>HAM7nzy-$N2W$%*NLl>q^0gEqJJ6azticnWq)KuPNH?J!Qor zcaZ^G;v*s+{)XNsT+eL|DMQVNR;l*!G7P3&AS^LiK7LOX+%$ZB`K7$zB{}2mh`99y znu~goraPYCMG+hgdYczdo#%@>y3G!U8*KrX8j08AasBQ_GDOE?!>Q|*mf-zUv1(N2oKuW0Zag2%=oBJ@op&VDe8TnD+b>| z*7aPn%-Y1`#q|?ax?d3c@TMamRw=~if+!$FH$i+Wh|d+`c|nk9wG_k$g7{D&#tC9J zAJ2RCWvPh;u=9bLx|;q=p=|7g{Uit$%J@Q5X}YQQHW9s znCT+Xnj(k@K@3xfHG&vShyjAwiZ>G>9=9pPdxCHi;wC|SDTodVktc{WLNpY_%YtaD z5JLoU*sL8PIjIBnzt1&JU=0*3MPPNPp(48Zg7<3*qJ}~=5=0asJ{H6^f{0LvBf>1I zU_Bv-x`H_QG?8hU^|K(#AX*~?QF3A&51hh-b7mS_tAjK^#<987+u? zbd?%{$PD2+>s#-w5JVzA)%HK^%u@(dr#MeP0j<6k@C( z_7UPdK};9KPKD?$2okLw1GtTQ1hGjWt`@}4gjgnsj)GXD5OoBxk`S{5(M%9a6k@mJ z(Pe~qR1jr&brE|13x!xMh_49IUl3aaF;5}h6~xDcxKR*a2;xnJ$Q8tEgoqQwOM-Yx zA?_B$qG$ZH2f^5K)BqgLd6M*S&%`{FHF4jUWy}v{ncrT@bq!qMjg13GtR7E)&FW3b7}X z+ zUG7B?QWgSRbVNEiz7nIO6oB0~^s1(B{0&kCX=A+8X_Y(cbB zh%th=o)A%jm?nrsg}7A^ml5K3x-;T)4HZNKg=j5^dW2Xihz^2?P>9-sIQ}Gpavs)R z*6yy{&?N%f4L!|xJ1A6mb16h?f;4pWT6VcaA(jbZJ0bcA;uk^ust~gTv4s%V3F0$B z6e+}`g7}sY^#$>)APN+szaYLM!~x!wxW))#oeKg2_i=jZ56^Th%3n3659OvT!RJCP$60g;sR>pYeBRZM3h2A z3!)k!UKK8!`@2G{5X4qO^cBP=L9A1Vw*>JWA+8t1 z=Ym+G5ZQuQOo#@8cwP{56yh#Hyhn(Gylr%i6U563ks^o}2vH=69)fsWAsPu{Iw3w5 z#5IDLs1QdC_I3gxo)AP`L5x(0p9OI*Aw~$I6t62n@86{mp9+FR%MipGLG)6HX9Urc z5G@4po*;TC#AreEB}5HDwM?!4JttIsS5J6n05LXFe&f`E72qH}omncLn zLBvuUuM487AZjUu)rI2`O^8W?IC%|wdkpEA__0b5|4??mQxLxjVz)xPEeMMc?F6w% z5Sta^F+u!9h>HaAq99f`Tw5aMszxcFRIf>@*wHw)qmLaY}=PeFX75RC<~-3!EA zK_m&{d4)LEnZ13A+IUhB4na&+h>e1nM2Jy>*n2g{W1K=PAcU`fLSLA;UW%TgVEQh! z`caWL>N(Q-qQ2w8*l8?HzyXKR@m5R9$UfItsW%al)gql$0|hPX3ui1Ywx|sMtS%k7 zI8}->MnS?09;OD06Q#JB6fYjj#Y^qtno?X%ihq58i(j*gcX!~%f5+>R3^R7m3tard zV}ZuMk>WjE9JPg0No*fpRXSgU&upPl81-KO=pTHai?4-IA1j4*A7B4MxcnYB;;d7I zz+Ou(d!w!*l`rZeE{VOAB^9SgO5;9PEveLTA_8$rTseFd+uEJyd*@zoU*gnMY~3iu zV}`LS3$p{o5mLNJirWt7;(WV!TN+>QWhwsaJ}%C(i^iK9y@#h{X9rwOy2_KvHTJe*kEVUgCV%)%pt!db ze=o)FE#u-@j|Pgbm*W3Qaa;ixzhf6)EXDa!yk;{OyX@j4?V<1yAunRd~v z0pv`c5pZQB8{>LgiZlOUTeECi-BO$<#oxcm#T$Hq+O4H{m=rtS;NoqQ0>$;DxQi5b zf0K*9v5WWL4292?D8&~DXFsuvi=?=w6mRGI2+kpP@jNc3F#f=ZsC-I&rqeT>DYZ2* z5XK$q8$$OJzFO@lBHpMm_>M4cmga}Bq{4U}b%@V(E9p#U--i&!>e8nvtcrb};%qt( zP78RNAhtG<;ssl{_!T>hQBr*B3TiO+mknIp-FD><7hkVfij8$#+}kcLl;Q#@=Jmem z+&eLF?b%ZNrWD^Pak|FNN?s{`Op1S%VwYWegcJ{v;{JU1%6Wxd+)au*N%0mb-ug)3 z+E+>OZ&UD} z-_b`cB&<_dQhju{%vmEzXF7*^&_@F$%6(ZCJ5T6vOJ2a%>=d-=b0tghSV_;1+nx@V z;zm+D;J;>)D?H!0rv9v9cQi)%>nS5o}$EG}MaUwh|G zQ21Q0OYyyPxcH!5yh@6vNHM)l2`;a&i{Im7it!tYCJGk-RCj=UQ zor@_DUvj9TGAU!4&N>o^+NdUhxIle_^VRUxx}13Gje7ku4#W>!IX0gq6^OrNKAA*1 z)7g6r0&ze*y^mF~%OvK-_R8e~v9+rdcYKg7`M|dIU@{aK7gGGAba@?n(0JD8;u)@hdr8{El6GtQ{0Q`^9lDM!iIt6@UJ~dI2fn z3RIImYOTJZUoOR0Ybu4?8@0F@_tCXnId%?9s*i4!sct6eOy^)k+;U4NgtwKJvoJSpD4go|(V1T4Q= zig#VgVTtd<#n;)z4k=zO#ZRx`;ud!C0Vfo=FE7Q*WH)i4ZQ431eq4$-JS>gd#q*_j zq!c%p$i>a=;%BAUEyX{{uImZ=+8!xxEyXSPKCScCaRJAAOL09Zo-VnopI!TUDc+A) z$bb$TC3ihwU;APyE|TK=r11#5@gvu<-}9vSm=qry8@To+DSk$ZeSAyZxyLSEEXCub zxUuX6H`~RpNO3PI9)LUzDlWFKJ&B8HhIpC#H0n6bW;iJ@nX^wzRFmv;jrxXx7LTu1 zb>gr$>dVG(*%!4^@r5Nd=+?=+_%i8CXGhT3`d$JtomH`IB#d9#i-P^vav+9F@zcH7 zlJ>SMMN*t0#m_9{;!Et}c~aa;imUhL;&{9G87ZzU#m`Cc!ZCp;kCWm(mv9$meZ;j# z+olbb;_sxm^IR^z+b&L*;*X{HuyC`pU3`%gKPANrv$*y}cJbl1Q21PD_dej^mTSOi^i4ZzFK5N@MP>NcZ$Mgq`B784UtQu(6po=@A;cK($RgXibys6ab9PmyRO$KY%UEHU!d zJ94iprb>6xF$TlCB`el{GZcKj;rJToI^Z)Ml?psK@PUI5d6$nY;r1r_KT$#|j+m4c zz;v_0N=Ex?;4ly!7NG+r{;$Nj&*qAA7EeO1^AIpAjlyEO$`E%1@4`hmy>Kb4gz8UG zMG)_6lgb-)0yOg1{uP}5KnB?F3(+DSTiJ@zRS>KmDDc-~*P=2%k?T#M>-nPIog?CX zeEF#HU$%)z{S1dTqSD#&sCT)ssP-bo(T6vx89w}9@TBUx9~RN+r%Yx})B_&^fxn`W zoxV2YXo_8b^)i~RMYcx4cmD-q+|iH4xNqTI zQh|RBMa(-2v73tWwAyhUq76}`88`> zQi0X{s_(DgXkv&t?BtI`)IreC%qaZU{u6`h=DQTZg~vhNgL?D^h!ReN9Tr2 zS2b$6rrmOHX*u4J_ZoD8^V*eb{}gsw+VeNTf8>Ae-S{#r-+w=S1jlb$ z@3dYS-V;lPqjqoVw`gk zzKLaJUCkO-;+WkkL?Y(^+H&Ae@P>D3_OYuSxf>y8AG^lWF8f&jtoYI-IydK7Fa|%h zdJ3hBQHpQZcpBpW{++SJ+jqg6?xmpVj26pwBucst$XP4DxkM#8na_ zyd&FyT>*cH4_f07qVc_+`UEh%mhxH7J;FQFc?#PWT;6bWy2%;?ZXiqZZ&l_YOi73M zr$LD!hcJ%Fw!2!{)Vhq!oE)iayoUkX$i~HV;t_+F>b*{e<{XLibT@nx6Rig?hgjH= zJF&1M&XN*vmle%H8;PTCa06!Y%(h&e_X~ylku~J}Gu(&g9D&ls!SUeh(uP8tS1=)} z-*U`XR&AKz>)58BYLC*J;XMq@Up!cTBMZI7IE>r&YIfh_z^T4y(23jtYuib1(N;Fu z>+6y#?R#*zuS+|+2J5YH6g_Xpc7+|eX5e}ll2Z({bKE2LAQ3iXcVm}*K(oLmJ__8? zkTY4AQX>?p^aOlSuA`}-e{^xHkmBg;X!OJHnS0k6-h*7*Ujm|tj2}(j0DDBL@GSbck6FGia_VtdW3A;`{_inRG~*`6hc>oPo>z zLE-eVrCE*qa{&$Hdv$S@r+imZgLH7U0nEig^AfkW%$lv$jw!uNo&V&S%@gbP-9*>( z-C%74l~848ruS5a?;$LDCdXu$nRPPE-qF@dgbGTW44s?^1r;=~=0fR9M|k?ABo|G& zyydbqFV;&um8qf1zgaKytM?!OXmGz}QJOcsap|Uj{b_xYFk%nU;n{J@!E5P>L0^b-R(WdzXRLGdXPsg%@oupQ!%)yPwr!W%EVoSUoEy~Ywf`MYzj5E zgHW}xUM4t56C3Eq9sLHly(O|bT^@41GCO_H^)67?JBqlKE>rC?SAFfRPR+>ni7EqM zFOtfXi6R-2H}9lod=qirm2&kc8qdCopfO2Xn?v#z_w)Y~Posg>0m!*a;^BZbpOA&* z3ucYfX!RMRK4oPJE=mHopEse|ma=!wlo%e>*I+=;MoYvS42|!|G|a3RowTM!(jCe3 zJ_cJZwTwCwaZq_83J+Ve7>qN#IH9d92uvBl>)mcs9#@^ZXCVwU%sC0OxGkJkMngk! zZu)Xcs)jc=VKxA;sRlg9Y_TYU@LnuqdC~Q#Sh^~=G1b4uF#9)&wB9E(RNkkhkYUo% zW~@YLo`7FgB8_tb6nZ9Pnh#zG_E>MDl6%Mj&hy1!lyxB@OiM9j-a9z)b_)NuTKYV6KL}b0f$F5Pwx|*%tWi6l)$5+gHGO)hdWff3w z`ozVd#Y&w(z2&qh}DOSrgl2iO|6%}dp{_TzX!uCX}5P$0aK0^ zPWe2}`@#2>l+xm5p1jF2nxYX3;414o9ttuxc2KI~S#^0ZKL--&K+1|)bxK%-fsA?erV4TqYWSSEz&S^)$>T6Ys@trXv}FVb%n*b~oO? z6j~3;(8FHxvtgLW9qAkKbN4h|1nUQu^U+qdfEUZH>2&3pM&w4U_{KT$?83XaHR@P! zt=Z>->|>eZFLNwdZwzVhv=OoM?BmTGdA~rNk-T?&gJJol zcS%2IAFu1V5LfZsY~nX*2 z3YcU1?ch*o99AO!8Ucgx&n-w>5(RUz&P(GFflbGc#H;M%wLCd=@!Uty7z`WtPP#ch z(rw;D#zm&(oQit%TKs=r)*X54vwD-0`%~gQeN@~%6{e$}B_M%?@gvbnYR6=CB`6z0`+c>U-_&d~P)6liU^2cB7KZTkgf#ho< zX6_zn0`8&J9V{N6qOiD=NSpSDEyvOE2?sM&m89s8e`DvsP~ zCy|n7b_l`IgT$p{V zE^X6l(Kc;)q&xYqEbK`(FYJMs8!Zpwxuzb5qf3!{$gxGF!X(iN_bsBWT9_C*;jT_} zhgF?YVxZsct7YUYt6@$pJ9X;R;dRYcU!IMB9=~^~VUDe~)F1PHb~bG3v=j;LU_^nD zv$eWAd7oq2Hg46D{b%;E0gl}NLet5+-Mc?`y{BGkZkeZMI^FO(1htVn55o%?^Ne1@u5xY4%Z<=lblU z{ctTF#ETG^2uJ$KG)Jc&9i9B8*}?HnwA@XWR9#I$j zvZ(aD9a-IEz3lHww8?iYz}=9oDYddLkopGLPTf+=^A9r6pVU>;-JnNOL1{x=E8mfO z8|vYyCqE@6WaJBJCcun095ZAJuL`p0ZIlzV?1Vl|Pby1V@9&9*tVWj1~aC_)Zj{) zYLfFG7rcR(?x7%me%Tek^K<0DJeKDdZ;@xti&(F|H!?mOi+Y;uZb03_@|*`0M9o?l zTik*R$Hqd>H~yS&N4AU~LdgUkg*o3?lPcI~H0y+$zz(#XPxVCTv4YDrtD$5qiFMYj zz#?CCRPF973$ZEEdAq-OUt#ndt8njbe|SGmTBZ9sFY-~x`!?1YjYG@H1>7yMCx}!u zH{G9eU{w29LxKup&Ez6=x-XImLH9)JzdmIEruh9OThY6@?MiNBK86tA>Y!iS1$JQD z=r1>7+bEr=h1X-_3x>eLbPzBC$t0kxtq=fphl4M?i$qSwP&axEINIkbl#E`#<}znv z_=<%9|47BN$a@^zMx}}k34LH^bK)v$;TS$T`oK9<1kT%ATG?w%uFO_qT>4gR-n*a) z)U}c}6=!hXFYgsSUkbH={pscgS`a-d3hR?JfqW44HYnr2OkexuCGGbvz+-7(ZRy>f zli^_*ehpB!@)xj<=nf#n4h{!HIHLbXQ!4=njZ(njwLZFxtDSe zVn5#f(R9oq3r7`#w!XnVfkIz&kSFh*+5leBT-L3^oaLiWvC6^S1s;|-37c7cO7P_= z@4whqc(p&g4A9UqU&y`!bR4KSeSxQU3)C}rAHbQPu_q_``aa?xx&7*-X*$?3hD7Xa zVFtL=r-!Wr7hrwK#N`PUtyPXo#~y(C`YJGF21@OtN_ssdp)(1D?uJRK^VgVmYfo5N z(ynyu!7e4AmySJDT=Hq@*s9`^rPx#Kh<4H{Y{9c^f31>#Bfm?@t5$j6s@&mL@Cyt~ z)ty!)HB$0;-rjZjFvUBTUDvUrmj=L+re@@&cZ{8jXJ4d8M-C9rUVqLZtE>b|oK@b% z7Y%lth6er7%R6>M>$FJH@Y~M(p2}bDWoJTuq~czPJHFS1C1;yHVbS>(PrmT>iuTF} zt9-aei_~?Cq~Qq`rayW$j&dF-`357D#bnt@tVAn(#b5iw8_Z(Vs$*>8F`y#Ss^jAP zR^3ql>mx2h`Br(LV>f^FrsT!QZxw7!n^#!2u6ADOA#6tv0`vU*xYRt1V=OOq0=uwj z8~C|&{|QjO&~K&tkGFzv5s0y)B7lWzYz`33!+px9lA-}xfSIGvf$+bYd7sSgDTTRks1-It-GWVpP3pJnm zAC@?tm?f~0Zzk3&$_DIQD>M~4yv(ayFS{VQZr~SY2DTOE?6oG}2OSGaNIM*#J=MDJ zpFk07_X%kwC6D;bzA1|Smm}G9e+)PT5_hrPo3#t{G!5*8qh=V(6 zT_s;J4vVdj?*J6I@_~m+_m8lG2Z0$n8{ct5tK_3ciLCr~{T-p{wv5|2zI@e-&a!lJ>F;o5IdJ{B+Auk!xC1yv!f|&>ybfF?JTG z)JXk~qFDl?qtVnm4bcMiyrzCQi(2+u9IVgDAnli#fl*Gmeb=H~6HUC*N!-K4`kGki zByM9OeKoR|2m%T)p8$(a@#{rdhOBI^u6bg-$Lk3z^JU)YBzjjC%2PcWgI@^Hsh;?& zCD{0(Lzb2tJ5pd_T<@&&P8-W1K&O5+Zm~nbVqpy%D8LE4x~uQ}7TU!nd*B zPSD>%6Uor?&>CeB`q@o*6cMcRE9@V^19FO8r0#2>f?bM4AhQdL%sZJ5G9_4_24-TK z&dh~->J$z}EK62-Ek|9*?F0kaDxc>8LGkqfA^sxxnXBT<@s>ARa9mI+ux}yk1fii< zQ3Ar5!7*5e6+=%DiL!YaF7b)Utb-LAPxx3ktWZFns%~`~Zx_FYz+@e?E3Za7x?aot z)gM{$T&*&~3iSXs@LyezAJ7l+Kg9~Q!%KV+GaUKH6aiU&c0X(eZd0y_zl_K55;IWm zABug7Xg{)i82%(JGP1bDJ0UR_0{#j6fCk#MSTERjN%}#O{?h&;7+aRWkr@#)D5VLwjKF)|!J|&OEMb znSo(e`QVO?k+eV)e9;0=przR_mh~NZA0n^FlUcIOUAwSK=|?Dp zEy-YR=B*ihBF0shKs)G$74>vK<}SR0HCv&Se_gVp^YXHNwF5nq)xFtR02^Xlr5cS^ zh_g3(KiP0p`JaIWQr4$UkZvEu{jubPvyc!;PB;+>ods1S@na366SC0v7QS zKGQ(mgW2(H3}IwUzW^DRBO`WeJ&xw2@myUVv9S($j5VuEDDeF(iTw@xPQKzbe$TIk zIUB69AjtAZPuPXUeYTA4*_;~l7dgnqKGjClX1YJ;*D;Uku5?ORKzsvGb^0}G zU*@#3gUeHyHeIBN@6e_O`$qtqz9xxt6p~|2Xpl^5fuv3;NmghS*g5BJ#!@@cxa$9p06#xPnI`a*jG z*vnrM`xrIUsS&#XvQ~&;c(qJqXI~w=x}g!O#j#n)^M?<_hk?$+(q|lUblJ4T(Dz3s zG)kHz3zl}DN4{SvC|uOCwCC`Wv88u;(n>}`RIvlWsH*7M7H2Y-n!@mRu~&|&s#=`h zDh)PF)vdUA3e&^d0Ne^^kbpC=(qwXGg#N=vUt|=l#yx@KNd4L9FKoVSL8o4Op=<`k zr$9WgDL{A5_kfFE`buxYqwlezXse@&a@JdAqoBR|q9Mkj_``dOIH!kXf{KRdkHi~j zp!R@pr%(*z)##C&zYEcTnZJAEk@NSN_(hzN``t?n9_+818N3i%^F=uaOSYmH52M}r zBQw~tvFNtMUPC7=4z?z0pkq^{v9D}?dh{={t+=xNa%Wp{fmQybpdY=a*8Hu`?&1Q! zRj`Q$-8Z#Me}$#?ID4s=G+<2{ikH|#bhkeOXY?!EISs+E~ho{}D;0`>%q1D}oIhEQkl`Cn$FHP;!2r z^;XmVVu#TN3q6k9(n{2L5D$eAgve}i+9>8bi;6cx2adhWVHlYueGs)@f2>{_H18AG zGa5z3sbf03&@Iyuv#h8#%o?APb+;c`oD`W=oRYN<3W=NL6PciSxOa40v+h}Qnj1cZ zgh65{?i~aE{N#@a&-@W#r1Ut381^_DP~Wb$zlrs49yDfO)ayS7v;KGBDd$tGJcPBo ziu&-KSpIww6+(!ev+h>2!!hNJ8Umb?6yMh9xKzcr9=p;}wd*K8sfu=oKxS^P71}H) zjReKJtV!dEQ+Yp6Zf`3%63@9E3d7q=8pns>8Puia_J%^zAyB6f*cIh$EU75M)^5k-GVjCkYAQ0dyHwerxhz={j#S?5$bl53`C@zSAo2(ap0XFFFb@ z|IX6H^lqM|_A7v8O{OHmNw^7hpe0*#(mhxzri3KbK4m7tShznLNzdrn2=iBDHfI5x z#KkV;%2l<{Ncq#o#)H2Dk@&# z4@VW}mB3!m9>5hLqNx!{%EMQ>Fv^+6tkCOSD(|w97`k+xZrj8!WP4q+ToOE*D3bm4Sp#f;Fcm$Or`HeD5 zv$187hCDbYV5seZ#Z@}C7M^~Tr`l;&a0vP;z7DU{h9+3G!spQEQM`wu*$t6jm-(Wn{q}^CU#0wQ3@2@Vpr7M$<-~)fJBrk7T@3^ewPc@xx|@@K*9jH0;03&@eZB1ekpuXqf!h>NF%Xdl~xtFwEBV4~^Hd z-m32dqbWbrlIbw~tu*}2uqIEUeDtp>+gE4IFrd;EOIa$LkCXHkuvU}Uj2Md3zI(7b zipgv~@$e|-bDqDrE?W8k%b#KQRN;Rzp2_@{_)DLLP{Rf12Ie4w8@}1w;9Ew}jTaHI z>qd2mZNQA^3vVTzklj>&5zV!&u=A%31TE0e%2+lhR#Jz0dgv3Ge6u9ToUVv>t)%6_mGN6 z2_oF+kAkT)5pYpFaKpRG+QlT|{ryM`Z&;k)@qFB;2%VFOXE70BRpe)V_3@5UUV?Vu zj~1le4+21MNo*hA8ITLMY>2&!ZDiz@Oy|oz2bl%!#C!8!FhHWsPCgI!7(s%7S~di> z2;ItZ&Cs$&bo~mVz=?avi46eUy(*UN0y$BEd|#9TBojci@*GsAxs;Gk#~yTz!HGYv zk=CzjnKXK6FAg|V}v_Lbw*0MqrI;(sXrnSI` zS{~>(z4}_^d#$&6jPUFXW0vc2hODv+Chpfob|#yQdfQ@@`-)fkt+_o07KHX#Q>G%_ zAGM#qzgt@2{2$WKjr2IHZ+7pJyL{2Rv5+kGgriivV_VR3p?MK`DY@eO$hfmId7bDW zD1#ZfFbtN!TF-?8=uQ0kB1KemwA=jQeO8F>vue6dfoo(Z1VXvhJ_P(36TMaH$p>>~UC*R9Ybs+ZAOjlh%c^Tg6Y5bH0#e=g3DZGina zUm;sOVz|cc#;Y-o{KfNd#^oq+O+H5n!n`ami_59ADD4bT;jr_9Z7`s>SpQD+z&BeKFtFw3DtzK}=gAsLu@3 zy{1YAHtuc~9e-$TI1mtE;MA`cZ;*8%s=W&;K*omHEMX`kMHZ%4U;~T$2OhIdU<+$U zZqL9rnJ;5Eqm{z&I)9{FMO&21?S)I3qgfuo;pf;oEO7A91)9;6NADvN7HfzYhV25d zpMMgD_@l2-@h$AUUYG$g3(F2&fc*!IwIMm6#ySU)r8{Gv0V@DM8%c%5i;?eGIkAg& zivR@a%gGNT;v2z6Vg$!-<`Ropw1FR2B#S(ZMwy6oc64Y}8Da}3GbRXuY!K$15av4A zT@19xd#ykNDCnxLLnAqow!Xv6BkNsbi5k1=>tmp6G+TrH73{!Ub94I@gsR5&Mbh;V z&LCUT2Sn0)`oa%$yk=*XoLGnx6tt9LGcZUoCu3{0Sx*!_FEXyDBL5E5^7EtPvJh_f z^XN9QS2)#jC5$Bo>H`?4{+xX!+tkDdFJi-3EQJYo0FKc9w-nkNK)d)aXb0u3*@H5R z8p`v5`+Bg_9n51-_eZmCxz`!U>1{x9TbJTDG44QdLk!dp<1Nf83b`i+zPR$ZjNoI^rJjW%l5UiCTE}!@Vg57s#wsi zJe=!x!10B-F8qYUqCo4kp3SY$S4c-YwK(Qukv%%qEn?yDmb|LLt#MXvN&Me<$M|Do zwZMhup7|A%%q$o`L}bec)kTx_u@pmbZR}YP{}A({?5uCY&iZJ`L#!?6kmWeB-Z*}p zOa{=O>|u0=2{@se3F#|vf_0qz7Zdke4W8)3RN%8?6P2ylZAIt_q|hJ5 zAvk(|+F`Gz2UK>%BhJCp#l1Xe#jzcrd`_d2xcP81$$hyfdAiX9 zzkuLgu351*ng)vUm}2F}uz#=i&bEq|NnZ_p4X1BnkAk|wXsdL@q>Vf-z5~d+`Z4uu z#OPVUwMZ?!yQ)jcHsDYg{yugsD&CM)JRGk|T>2bO*e9=;D4GecQ zy4Z2Tz>VD8~>ir-!{i{Fk==K z@8WV7?GH}{VrIotVU#sr`1+->kAH%o7;SA-o7im8PO#swF?GHd#Z1|D7oaBCmWzcr zfEeimwRn)NXsK0xfluaIIMeewXy>B?#4}9#CG@)CQ+W|7zPzSrh?xb!_!G<$t ztrH#!IgWHM*1_U5R|_Zhm!FAe2=Sv>(Y@&)JRd<_I5d*wkJz(r>87DCg=Kxx0u~ZxR?5K z#QOy5z<8jt=_|${Ne>-Of>aRw(Ew&81iD5;1ErVYl?Q-qJVRpB{oz-9tQQV-;!nhU zumE6(g46h9#{{;4_9vr#gy#y*`vyeoAMXoCyP-;~w=)ff`U(U|wSv#1-g(h+?Ql>T zhX4;2hCg%X561tOy#o~CG}RL#u{fr9?pPp*-_!51fcI2fpyC(bE_hDn|{bSuFUVe$ypO6*rF9!5Aah; zrIh!T5#7>+q7QuJR3t5DxivM7T2v&&zRX*a{uF)^>uUOAe67|FAxEUId=bHe-*$|> zj$;v6YNr>L-LoCCJA>rsM`jPkj}^+tU(-ftZ9%x>Q~BZC$E@Iul01v@6FnDG|3buJ z!mA6po~m*E`Mr8hXyIU$->V%SA4lP;amS9&gJ6} z5uFj4!7-YL^Vs28912UMtH56R}*aGs7Pzr*zz61-#u>yZ-WyU&jg>#T{>xtS+{;V8KjB_*&3UKC{yKgOJrPkmTmmdGhX83{Q8G$MW*~_}vQipRdL8l| z!n=j`ID}W=V4WfS7*tOs9Pw9GF5%5nnhZP#EZ#@uBwmCtO;rgd{Lao1FhO9tFh3I= zj!S#U{1CyISdQ@t4Ca-59e)OZa_fR{_#L6Y=fZz#1;s%WUKPI+DZ{48J{!*T#6vVW zB0AAWbd^cfT(IfEZb)23k#q}1kB;$?XbasKzlq4}sig<#1dVv}&{M#(1B|eDp`AP1 zg_*HN&|T&NWL0c6W+5}q!uxQ=0al`_K#M^Y>C>=0_##(j#;*GwlQxn3Ygomfe8o z%?Es8s3P9yZpO=kR{oqNz9m?HD5_i!p5$yVPaj=RGFbE&)H8ZU#G5-j>7@m792F$u z{R&9B<;JCC{e;%sEKf?--O05YqWN$m=*SqQ5IJAe+vK^k9+r`_R&k=?$^l0Sw?8&$0H1tLLdj>=U4dFuA9%!cP^E?k+vM81R8P8JvjEdPY z0<1U8nsXK`)SK`I$6X^>?YWKf!oP&(jlZnGn)4a5KHFlYdFB;(mLVRcco`IlLVt8{ z-T{BkiZR)R;bj%|hE4NF2OcQGdnbQ*xxe#L-->zgNp~-&#|@M^F2rzFH_UYMtNn zWr1fY!0!d;$hFX(@kP<}Gof5Z{pTF;<$N{=UFb0 zH{tJ4Q1*j>ABYw4!_lkrJXlA)kAG{W^#ecAH3)=5r=(}#KB*HRM)_epjl*Qiv><}L z=2Hwk+p*&dg#()+`Hc|6gBW@Co4?mMJOuxWA`;40I-%;gFHAovaadBEL#E{j^w+hzB&u5AY9{|_@j$d&ax)5TW9|4(&<18#*o+OFZoZb{f zUo_C$)4hrzuNcQzG9ia`T{*-_LC9dBKOjxJmNSDLmLDnUBdhG~95|6ag_yz+RM-yl zlpkn@JTeX1n=#aVy)vxeC0Kb7q{*RsWwEMvCAb`<^~CG&QV-uCYlE*Z2980>?M!I` z1tGK>$|Mb>C#h7rdlWJi0Zi33f{+i;cyt$ig1b=|V3iTSj(m%F*J+8>@`I};yscOk zLpjJghFC&`Etl)MuSyoxw3LT@M7Jy1F{(;`^jB$fBY`a74U!Aa@BnJ1zc{t|Tph zqc$4n`3#itDqZI#wQTRW8i26f<_os~0?+b|w@RLcQ+f>Z74Ow2z^(|}QpMc>WXe@6 z(qlUwi=;FzME*Q}vbLc0?H{Ef!UbCiH^ROVe(84{BinifJrF+Hs~Nx zxB)Cuo1}u^XjXoAjJ@y*_`D+C+k{e*hnG!g)a}A_z;<6Y5FNwln@2R4Av0!7TN%bUI{+XQBzUiU8*Z`6P*-Gk|H?{6A)3kKV zNvH?9_94qi=tW9)IetvXU>elM-!(OJ7Fd&Bl_YyEDoTfZ#9lm z1X(n_^JLdV?<~K9&5Q6|0f5Ht@V1w(k#X>dC~02OogZmL(;-x*Nlnp|4i>PiEm7l8 z3SBR`xH819$24@*Af#}g0(t{eBK87l6?rmiXm55=pwEjumhHow!00|}>bJlG(@^jm zbSJ~Z+Jd$?`Y?V_c9-)>b?dlr(R(uCMzh}UQcr2Fhpb7aFWHOp*`t^zE+-b*oYdg2 zceYaUu5#9iNbBhe?`sq!^P*YB0Lke)()!G5@G4%#iWXkW$}>JnJ#klGHZe1@W8e~wCgZWQ0OPb7IQTE%jKX+KG5#!GwlT!&?x=yoa_7b43D zO*_f9C*sGXOl696$mf7AI&xX%A^4r~#=(9W`r#(2)xw8^rGC7Q0z8qOE;QgG_PM|Z z?|52q898>A75tgQUMIC^)_JEm+p44d5XFC?qdRG zL!F7dE+I`YS6IPQAu3APLjn-evkPO`m7eBqgXbDdaYyHCh&7GRmI>6p+(}MMUEiFX z=*wmTRrv9YQ13lOQtW>VAF=#`3X3DY^ZYpWfj|f+Kp{kzrd30Ql*t6Dj6GXh?gBLiV6t8gGp5mL;IdTtV0<59v4g>N^2nC)E5QdxMJw%aVx?nfx34cy=~ zFe#Z=zjSswr)>g!kl-2ESc9#e8v*sUAs!3p*(mO@cDPzr)BBP22iT{> zF_@F>(@t#Pg7pbpJ|+=rpgw{}+H*{PPM_64Evjyyo=F3>q3RpIZJ(~=K&WA#<^cL1 zVxO)S@JaS5?a%!1JjX1Z3h6OsDSE(|rMyt|@MbCW5o4F$hcb>`+ALw0PGyMt;q6l1 zUPOIH?9o*#!POLdG{iZqnmu|4(o*fwtC&*V9z99dxdjm8|F=Dw;mTc-J(@O{^PpWh zh(FLX#PUPJ)iMRwutyu~ym}#r5$#c4B4X^(PXUSU2C+wXT!fbtdvpU+#2&qfbzqMk zgkoRQ9=%;Kv4_hKwT4%TVY0PZgxSGZoB5DtYwCIegta*ezhZ65QND=4x?-^(KPIIuGF7J&i*p|fP%8@_M5};N1%SrlT%>lxj0*+o zPXbD24cD@MMoW}wiH}i2=4wU9zJyAQyL>U5Q!9Q4JT==#0#R(z#)LF>MO0;jX|wp%x&7lXZSI?lWdiK zDaoSjT?il>0VF@t7CuKS)Lb}bKZz1pE3FVuKml~t1%?eNCg}VQTrqV~(|$50=#{AM zPTms%-hH{8P3v1cn@bw(6`*ZWPSlhPvfc7`RxvoYX^QrT zy@X}4#p`Z@l#?ZDINqqt|C~(57DWYbD(crv095;~JCOnE zR%ov%n%?ao*R>IU6+Y2M{K{2ew=fL~>=G^if^>+O?z1%I5lKN;r^R{XUfOA038sOn zo4FP;Zz@l+ zPKEc#&R(=af&dR?DwfNj9{-`RfThXi<)k%FFl?LrkNgJkCnQ1)Q z|0|JY`ns!R+tcu4Ql4ar7<_jFdi+UriWq#i;*AF1<>=!(rIr|cMR@%S;q^g4YOs-v zCHoQ}q=LOy`G(X8>(kU%|EhK=1F=qNw>fZo8F`n=FDyumSMhc5%9De|QX zqsZ{(yH!x2zhyUw=@2!w{BEt*ZmngBTCcL!D;%P!IL_ni?wxD5k{revDvFhLdJQpa6{#^+eZojtz6Wy1+ zYEEI|K5^zXy?hb~)`5p zx|Cc_(Z~OH|Iq1>c%zRaf@XP=B>skfsLtW^@ew|Zorry-{9qYy^zr2!Q%CdMEE;T%Dz6QIc|R?|N;TT7J74>k4! zL_S$#e;o6P(b&(y`eaSr$0nh%N8u+btITlyL(eE5Q#Vcvq-lGSVTr7x?*MzS>0Y5x zQnn}-K9n-+=&j6zvq|)IrmMbw2yFt%^O0-x^(Rza+udJa_D*WY-o!Mc5teANPqkQ! zj!uX(tGeWx0UirOt`hwM1Q$C9GAa(K)OH zp~d%$^Vv6PDNdtY<#z{#{E?JM(*55hU$tl2Y9FpaU#0FukJq|$9js*kU$|{AM3(86 zc9LyR#E<( zP!iF*R@>Mi9fFQci%(Lu{UpJS^FxUy`~c!zOJD~%A-d|tl1oi+9n+u*@)!fy`ILYJ z_^S9BnsOgf5Pn71P#H`VYbq~XqHBnk9hB|Ew!#i{6YlS-jq++ItPm0M9u0b+J3ZGl z$xgUUIs?=v?1Y8Fso$~_CMvuI{ggkr<{Ti^PH0mNUd5}<`Aet^)89|n3&uZm=4{tL zG?%)B`h+&3p!kH~A9~I_XNrGFbotIny8J67O8g3=smqt6{m5A`y@ET`ev1NE)jXR3 zUD4&=V2-1+PHVy*rOryZG&*ayWunXH2yA-*e%x_(5lXo)X#!IE>tWI5y=~B3ja`%Z z3a6I*urylB5-!_E5ntUkDHdS%BK(+?6-*KNI1A9@YcV*)LDX3tL{@O9nzeW4kur|H zzZ--o<-JsSe-5pRR1Z~#jD!3rLuyGi7&k41A!ZkU!qEv4e;aiTOIk05LN513h{19u z8-kc_R}=0e0!?upeIl6H4Gls64?@JO;8);-z8@_}gEjwfSpys&CIlG(AA%aw z+g&kh#`kj>sqQVBL6W0cmn7O@JnI9r zTq-S-BTN|+W}G;30#f&CCf zZD5Tp6eM|zh6`}T{=o$Jy^8>T0R=d~m zp(wn>=Q)%&q!4!*A?orA`Gi#2k3NV?064;6EjVVGKXSrJg79fCNRPLUgFks?oA5a$ zhCVHX6J_^dZ(a;(d+GmZvjO)t&D0$Y=MhHVU~fGgGo! zVuZU{r=(=f0Euo^HbCTuagFV=dcYv+?NrWrA4eMy$%V-FY$AquLTBgb#W$FZxHlBN z!aUQj)ZILH!n2ppktPFR6=wQs`*DTwobJA89%9V=-8~h}lj7Yp&a6S9mA@Qu>Jslb zbQT+EGAz%Ula2E@yY#-JuoAHig5fwNEOE!+;AS!UR#ybKk zPWLpWQGS4gL~{q?aUvdhr3#a0$@841nFYa>A9DRk z1Cg|IWCznej5fqO_8-LI z9}5_NvK6tfTH&*l#oJJxI+C>2n^BzL$ z)HHC#E0V6^mLG-}g7m$GyCb*w=g|G7ttW8$v z0Zt*2+C>O`#UvBW`Yf|vnnWD#0*a#LK+*8tj*4cYcR4nSt>|0)EftDxz|Ex0(3Cc3 z5eg)WW^{f>E)JKm9zSN+s4#+$izZnPJJ1J2M2z(MXR@Xk={LHl#LrW(OC-~7Z8XsleTXyk zEkliT#GBeVgOTP)$40=Wbf6=wAT$MzR==r3mHG`NX@~TLWCCCdWU?EA7vVk8GeDnw zh-PJHnBG8;JIX_aTphm^K-5n(9~dl26F1M9R0ks7e`N`t`-DcrlgF86EO1MUO_7S| z`Ly^!sD`-kI@=Tf1y9bR8UI1lP487GXpF@;lzeOIU-6g5;?t30ZQRqlMJV#98+^Prg!uYC-!u(E&sFl5ZGS%xHp|S=yT>A zMZYYvdLavoXz`1(h-(<+Go&tRpZ|)OxwL7qh}#=cgwO5p{8#e~MaCX(o;$_Y6IR6g z88B79d6F=XR3UlOVJ6MVAC$q9k>&_<6Mbgx6c&|k`xJ2F`4nSDLC(V)Wu5UB0R}o> zB{0P^)>i~QI1_>*f*rB@0U5FkV-r?Ec)sYy-upPTqFKIlauMsvt*8+D8Cz^8x0V1>E%Zk%S5C>`J6WKMX#>Lnmz7-tchGn^GV)D~WGGPqjc+n=FLLy=1gAaEkLKSI?&fik-- z!9=q*)lz1M9zstN%ryL>=oACSfw5DuK+YsoEO}3Xd`(%2X3bC_fw}P_sm+NNn7)r( zMKh=c2>%_J`NYo!jQT^EE%sGdgij{7Y22DAUg6F|5AG#moF>xQp_nHAhEA?dDxhTo znyg#731DZ-=7PPoyBYRa3morfoF7x7N6)?Q??1%TUDQp?BRTK&6#%;aynjOi$`&-J z?$3J#!lM4XwOxrgb*av%=PsXq(Br) zEP*(Fy;^9hnqRNjocnqn1&`p@>&tUrO%na{-<<#IL_Cat?-mlN{yh&K9sgdIKL1Jn zy|=)@Kg++j_UR-`sFCB}I{{)WZ>|Dc8B%vwMzK+F71aw`v36neMpfp{yo?~ za{BCOD4(!{LN{ZYz?zuOlVGwaF6N?`Z{@F#4@8!8-oCSI?>OhbAm+xu*YbD!_h{$n zImD!RyJ@FlnBn}F{9r|M{CnFukZSt(Dn;3}H)H6FfA3D36XyKaX`JMZe{W(JyrlT| zZfA=4_rAvfq}3C}Z%zMR)hU9I573NW<3_1D=fAYXYWd-E){145t)BNVzZk2BR}ENG zTM|uJJ+I(5<@}fOG1b3!y)?Z{2_?=@38u0%=MN&^j4*bkkIny&BeHNJ6{hR4Jx325qTq9ZoJ3j#!J0$Uzs zPqn9N?QcqD`+#H^@PB8TQ521T?><1&88oiv`@A12YNMn+DkdGL*`VgePzC)D1KKs? z`m&qV^CV%VI2Q<6so@j!DEIm$VdgDSzV}aX^jU2r9i>!#P@iCZQ_J`So1uc^6TDHa zx|OJimDvitg6;>uZt84!3~MWKnrzShx}Z&W9MhyJG7rTc!i&44l%qBGSVepPWI;TuH%FUKQ7?ki7>%JmhL-C;lW^c@LA(+Erg` zr@o2Kqk@+>4S5M0j@W+_5Gq05PlWyUQ^+!s|EqwuFGnfUPgZc2Xh7bpO-uctN&#$;5+FtoinWnUdlNE&vK$nfff9=T z*&U@nYaA5&mg&)~*}EybGV;Eptcejaf$-5=$B1Qtv5`0^_A;uG)@as!iJDJJO?%Dp zi9v4UW+)4Z+>8=Dq@mkbTvk3plH7|Fo6ZTC&&qOVe}fDqWGh4=`JmWMXiWq)<)GNM zT~33w45kp&$uFT-F4Xn&45?U`R=E{dGucG|Ry$JNE92AST4gJ(Yz=Yr8-G z;7DSrl+Q>uy%y9rR?sT6s5XJbNqe%6!;(J z@7vBnnCkC)`2Hj-x25Cn>jS|w{=Rl@6zg)<{=NP_z3&897sKDzRP0^x_pLwU$o6gx zf8T!KmgMg%&8-b3{Ca3%HN1PYZ&ST{^!HUiU&ecleQ7>HqHR_?_CK!)$#8QZ^M=M2>!i#C`dK`Jy-%Y{d>&> z1-qgAP}LX=SSfbwFYN$ay?2|@lh)L31PD8pH*kv`n+Kku=6>N%HCNe_1Q)T_8%jlk zXbgx*djo0E7sOT8Tc0!XBL%!6K%!G$VjZeU!I@~u@!)-~tKt={1jbAUu6Q0~-yr^m zmgt36bViClttp+g&PY?oH5ZAGu|e8sS9b*|a!4uRYWiGi*~%|)h{~R?tsoHxT!)Yn zeWt4^Fa$-umo{aW`y6q;TA>p_4ak2JIcCEYXTae1lVf17iLIFM`+fOiUEM!@PMC&O zoPNJCs9SyK{cg5o2>zFvQrX7|eiM;{9bRb+B1P2g*33$H8p|2t7Ysx9wT#bzFG$0 zs<6T>$YWk;H_Ozarp;Y=^#hEgX%Vs0kO}p{3UJ1c%3 zfXMwvxX%VCnBA9#O68-+2%;N>O4BoCOf!2UTcCJ4`)`rfn*i1L$==#ZqtN)tCQ9{$ zMR=#SendanbOT3`9tKcq4CW-msVK)P)hn#CJg@$kI+Zv_?X~x&_`GgG5!!V0bM-aP z?eN^jJa>wJ4W(1;yJJ8N$HhRf@)Mz4?7KXbreHQiUuD$(7ceAtqHW0(J3Y`W`}lcVudePEp4l1wIdos($;0p6TUO9;&`3ZaMmXkU155NWV8 zk>&`^UjdCm16irVq9W>jKw`X+$Rp)_J6l9^K5z_PlX$+G8r}nHy$BiRfR+esj!#Ec!ruQ+@oI~jC+VwW@ZyV{wvYUXw9dg#LSJoy zcK(CD%JHW0YLi-U=gB-y>Q$t_93Ap_U z`sy1H_&-)(jUCN#4Dk?s^=rJj`f7m;@tXRo%~4lfUwyj?=g|L3U%g&Xu&Z{KI zR*JrQHs+k)rLPWP=j%-fiB(`5!QtLv`2k?g^Vc+!v|56->Z?=HK39QceRV%^I+DKn zN@IbsNAQ+e#Eqjf`f3EN=#1p(t9NRh1*VRxuM(eBeRTr3Tule+sDvoL3?Yv-6(n*L zc~QJSKpRE}5`8txGzPauHGQ=h`V7O4e5|CoQS^YN6mR`sz%1l$ErmzM4a9Bpwi*n@=>V>8stCme5ys zfR(BG>IO+k)>m7zO2l4l@h3@NokgKh|Ax_5SF!g}_0_Rj`5htO^wp0-fgMGfqk0^p z&l<*N^wp55b69_0{g^ zBBQTnpe5=ta>?8ZVNyb0trT!aj_ZnphmPJ9%_`sE=&RvmIHIq}u>Tf#|uDAF9E`3}%Hz#;0Fu;}6R)xONAsjn6y z+2OnBs{_`j>Z^SPh2PRw>!60{tIZNcjlTLO5aST9!8iML$ep9Ft|MyEtR?GI=Rb_T z`kt0}RZAR3U;WMdqMOwhbyebrrURq0&HFVdD1aeRwxE9X_#w_i8b9=SJu;2)Lvg@x zb;s?oP?(OB6#3t`Ps|v+Z?p!zN|>8b#8L4^>{&$0po^_*S*z`$4J~z=uV2V z#tKbG5}z>*d2cn()Kl~L{5#`@689pZ;+nAp=)?_e#ap$wA?Lp68OS<9+|d7YUo_h{ z@j~yD2#psaJx;t(i9Y{H@j`n?|9SC3rvSFAnY#By?}m8%ulE7y{;Av--Je&R96=u) zi*+nv-|78aUjZp6Ug(dyFS-Ls!n}r9qu(DdbkyPEg|5!T*ooMe$PcD8CtheC$5hRD zA#-2!8yr@=4;)O!2gI(0qxOrFOK7h|M1fiw! zL#?zS;HGG$uVA(?T4@JtTUb+HB0%h-_Hm+tdcn*_&3_A*s$F_~F~LRb#|*(Tn|}n{ zkoJU7ASsoK#ib}^X8Z}r)Hq|=Q60+qqM?3?R?*m1$Tute`?{OvRT$@?r1;lB1-A=- zItn%2c%Y~GRwEwhLn0*cK&67NC}LThCDp5VskZQ}RJMPVh6vOgf(??zU2tpC z7t*=*cK}A+G;}5X5)u136cJtZ0o`lOO*foR1mG zlhU0Pq;H>Rd`?>x*j@t0`<%z1%MIKdQo$uHv4@*4gG2-Sx*Yp zhg5>t8NfpM^(OdX1)l=5^!*Gp2>u0ba(VYIYYXqb1T}_tgQp-)VXmM`S-h20K^9wx zblN|qnSzPYbellYc!&FiD}s-lSV~3u4(8%3unD9uMmvh#!vIX|PI9q3!No2ofnE7z zVAr15rGlp10Q8O(EgPMacK+Ikr{m)LK97ES$!^U>2N zFmgV+IjXwi)}B4!zI_Wha9<{+WbH!}ZdSdNtWa{TmS{)zn-PZx^1Z&BIqqugH}ANC z$r>Lq!#uY`@f*#v>^JlIckDOUO^%P4auWf&`_0qwdW8MvF39ry;pd?ryO9m*d1(J| z;G+A@n?Q?m9=aKlvG@Gv>^DCq4dEpDA9No2F!2#3!;-XmH$I{*1oMxJk7$vIk9e2Y zog6{Gud(0U4ZQsm_M7`b;Q#CWX5RZ%BR*p6fvym4h=-nk#+$p}`~^oBvZ}{Ne8L%k z`^}F)r*q;Xd0)^Vw9yq1pd(*!YOuzY+zzHy{{2!QHpzhq=V|E2hq2ntgS)OVf!h=30cEd91@&HA`L5+ zY~vn6>s-B(&Oft;==zT%936X1SeMh{<*MVg1x7ki#h=rZ21>;c(~hf^??zijKh!S@ zdYec$R}1qfmwNVIfdcBe)Sj$pex#@gnim^1=>_JA=q08+G;(ty`WTI!e*_t3v)MTj z%@3W52HQ$4|Pg10l z8f%%mDh0=df~xY=9>z4I{hRN>JgcPmrF4>J-wOau&)utid9L12(0LXG(*Qs@T^zb*R!)1J^)_OCix1E?=So^aCr{9q);L#NyBHi)QUx zX8LY5kkr15_W=++KRpo`nA6RS>9(dG1Y0mfgOA}?4l^tVhvHkI+PJ5h*NL9vy%G(( zI{J-diRf{2C6{{9MNETU^a@fm&MVS73?$4x^;JNOD9S!{XO>OU%sVTxM~th;GjNo~ zh5)5-HtkD-Bm2}hTqO&jo+TclD*4&PDf`sBP{i4re!)Cr@waa=&z<7@E`-EYY!bbE zkDT-^k+wuHHz$4TIk74cdngbja-xGlgA^6cdm%d<4*#X1gIU3q;Bw46UR3dh0?uxW zpX#G(?H*Dk%)DBa@JaxxajN+Vg|Kd~QyPP`k&4~xNOMHY)@RNeZ?LFzTPEP@sb+pZ zWxs^SLjtc8mDzi#Aix>7)BvX}@{6yBJ5GE#kaK9?f#bydS}Cd)AUSnRR0uHpR0C6{ zva3WA>@=h~2;Ya+-7!(7Ms`cBy2EhBM7s||X3BBmcaSfGqQ-IJC1i|qoOsn@qZF@> zA20CjQm0~gg-Z(hP>vIi!&K%RCoUzJXx4)YzzTK2&|;9sDKd2J90SII;d(6WvjD_7 zPTWg@3{fCBP8^e21a2E1CvJ^g){kaoCD0s)K}Et`z{t*Ewiqj0g^4gSR?9b&7#MRd zx>O_hXYU5e7?*=YlhZi9pZkC?}yKi&Q zn)|XMrPjI0wbtXM+WFz*>WB^T+(qICc=A#USgFm>9Z7s3sg3et^dA z{wpfZyM#a-Kfq4BRr3Ql=ZDWi))D*wegA;-!()e{W&M8SD?@;ix&tyQ_}Z25Oas#as2`A{lMQtTxy&j=I!PG;r#G(DB^slqkZE1 z@K#)4awL1%%=1=V6zB(~8r zKo%I}bMWD^dpBr7nqMfERqsW`p)N{sr9+vn%*5WXcoUee7DmGiYJJ|u$Ti-C@!IrT zKMBmVq;~9QndZ6@E|L<}j}}h=F5K4=Z$gJ{1R~1z5&RNW9bSVR?}1LUH{*}o5zH%BG4>&;QFCh_YA zZDc8aR9Dc?P%f8bZimZfD8B*_YRjP|YWz$`w!DuhHBq8H!R6yayY-uff^0c|Gjl|P~- zK108l2$`U!%$5`k?5a4wlnu0gm2R}36DUb`%0nn=7@nUK5@C{YdYfpiDQ%t~-ohArp#AhMJv6HTm(dT_;D~d<6dc2?H$2erDO0t%Y6PEwh zeZ!3v-i3fi@s4J#eUBP1&pE$Z4PM2o`M5(+uBbro@H{eZXR4ArDt^ROG)K6;Vg+xh z!G7tvR2S6P>PSxF`;~sn`F`aE7J5eG*VB;d_(J}TO5zKN2SiEr9tUiVb(0XxIfAEM zMV4@AaFRS-2)Ap4gGMl~mTY@IeoV@zOc9n32J|>3NKCo@c%zGj->-a0YKbYw?^nKw zrbIr?_bVehYapj_oUOydlJfn^sqZ?9_XDVDyaZiFh*@`*BILu5J2?zODfi`2%poZL zCYUJ4lV8FEahnSo*GoR-IbA@>T*mKLHgK>s$CAI-QHGqGrAqZ<$+345Ln;nX2G2>i z!(U*&U-=9{q)Z3I8xX@nx8eHxXc%cxWEmcBl?Lr|QHm)*-3pp*g4?C0?K1$3p{AEY z*#iIqjFw}`4N(Hm0Q~Y6VRDUQ$vucmH0wmtp&p$(Ww3G(#fSlnnvEhsDaVoz0~NaY$(;AGLyNm{1PzD_bUs4iV`vi;+cFb zdDRa>Sheq04sjbCWH80C=DB+M{jwSDZE79A(N=+f; z98NpcPw%c}J|e$ZMHy?pUwIeUqohp15KI1kWu`+)%CY1~Qlpaq)QH&eB<3*RuPoMf zFG{qV_{!h-2`&Kc4GeVHdEz%RN5;1B!#%39jMu5y>K#P=)vYXeEgl2@~s zS>~5If{`7&p5PDj{mK~>(`eSy3E+qQe&u*Ac4wkk;`^1q?Qi?;J8<8*kN8o%;Cx3* zLW{J%1nf`v+s?qifWOWA8|RVRQCh{{HWPHalh5m9g8McK>~de4vxnWcDQLodc|4_7 zv*cPY;6?mxC#k=!Wr2luYxvum=QBB9&UYL*Tb~&>7c%A-?o1v_TaF^ zCwpAi%hX!a-*yF%5P#ckuw5K~+Zw<*qQC7p6r`p65!LJ(_YH?IqZk|VE>+z}NeUF* zwD@pMxkggNW*MR>6WGs@mN-G1Qa>=R1Tk&9 zvJTa=;J3iiah}E1Jb4!|mZW76p)WP%1*A|fKPpg%U+M_W)8snRvi-&ewrMP$6?7Hie2K%gz%4wg^^n}mKITj)J z>z*O#iY3-bp;V#?TyIJOnrn)saEAh}3-j0Y7zc+{;JJb0vEAb#GWlbR1j+uX!6FzGYaZ_1yu=9(-c&mfU1AL&r?~o z2{rFjPzwY((q|$Cuc-mxdjkJo*k9fHH| zbwW;W0|Kjq>;L^)?b=mZqE+=q-lL55i6)WxA}UBDe@$-0IT8DwAe(Z+pcF1c?PvQ* zBO{{jQTq{P@MqS+moHug(!8W~8Y;vF;EFnMZ;%py9e%32ZrTaTfRPb5U*+fx@HNgt zZBhsw<+Fnb%d zs`ttJNOSgPO4UezkrI?jzD^9-fVZepH0#XsaOfm|b%y%vZ{&v7gnHkvpW8rOvSLIyvHC>+Jd7k z8{k&GR5y(!7NA559>{wEc{&$-`?U*dx+w^|!NHlnvT-OYt-hTo%7sO7f0l{StYHMm zxrE^!@qb~;k`HYD-urkzSR>|voTn)S#Int}ii=LNj*!yB_|sZLpw*vtE^2Dg>0fc; z;6K!RA3)rfN0F0I|1W_YxmgENvTj3bZq~$u_f<3-QYOeU9&|Ll)C zPqPwY{r~ot9rpg+MqhM=Alr512g|hMFB`!r;fUvHuH~?zzbuTCXvSZ*9w1zQndeKq zr1;BzUX2v-mz}^mumV2GfPB>OmreLw5L#*w!q}^R|Lzr-EsULTq1phPKk%IvbZNY= zrsPNp64K&~fWTyOlENL~z@@jS3DaDE)Ca5Ba&>>y&!B|cMxvqLD@8;@?<$Y7hxM^c z-`?HYDXEwFJ|^wiUrFm2`BbFp10-5sCk&I6o{HS#_@O<5GV_=zM-YtuPrkS+)x9h) zD%C(~n<~|4reOu^jTC2H_Ff}6HNw{)l3Xh3ic63C7Q7r zqosE$tMpovYoiU(((l^JF`h6576@h7K}w5nP}To6Nr5D%#Xr%M=8DT6x4p+i&LBc)l)&08KzL8>=T)0T%*S- z%1yLbeYeF6tGBp=y`RFP4bLA+H0MXC^(X1MX-RMx`INqvS`L{^HSiqE2Hm_FM zK1j?8WI(UN{rbE!r?}}fpJ#d1MvxyvSLwEd6+9PW<*FT%mFLPYGa>vc{bYZPEHl(P zEBg21hbeI$_nPK-hwhV1*E{quszHy#-LVWn!1)g}Eqa~(%ctxV_+5@+j^j`m@ib5s z8}er4n=SE1*iHf3$7s7Jl z$TBn*NVYu_KTI*yd0#cPU~$p+^%g3Sy3k8%c8x){P&-WDEr*7LulC`;lR$NkPx*v6 zaGC~ny-?SsAh@?*&AtKHc+LDp@;A^S7@IAjIU z_Fhe1E2{^)ex45v^ zd$MURn)T+BB$n_dRf8wz-KL)e?b7&ruVX((?Ma<1D6o^t;lje#9Z#?tnzQdXCgS2~lzJNQ^ z;}3E9L93A_#6_l}jmtnSFpg$zeB33tPzgTOsh)6(zRW^W@p)EM{v6BV)!8_i`O&P2 z38>unQaV;iUEm!Qyp5;wDuJ!jMv-<3|q;5jYye4^0lfHiE|e~Nzva&G)9 zSX{cfmm1*#%oP(CG(h)OzXIbXj0!c`A7h(h-TweE?xb1=GUC2`N9x_TnGjp|rH~Ti zzP*PA-Iq^OYWb3Dt;LHm*{4DE!m=Ab&@c@rSvPmEfQ_2$qknBE&ot8q?AK?S?`_LQRLtnJNXFxR25TAYA9%wSmxlg#M8&`;0zIKG{*z1?JKcc<9q3xey zulrh~eQR$0fxzWJLp-a!en(vk_WIm(CV$X?&wrM^eop;A&tCuNU_*FA=cf1NS3+U0 z&rLrEQ}1rbhI9Xg^TC=07@&tY*RlWT?}a@+E0}DrpPsPSZ{r<2{||dTy$!hh2ixl% zND?%m#QhgW46Ql6DTVkVYj02Ys?_g-HgV-J>3ca>f6x_R>`UY)$zGqw0aeppPuHdB z4UQ?=>zBZ%<=lU|HTr#q}c0ym?HN2HYks@*B_=5S;JocY>^<;63`r7&wh_- zu3derl&Ef3KWe5wv8x{xa>TAa2kn~qyrU{H1t>{#umR1%hBOE3SfNbK`-ie)fHaY0 z4puHybdt=$ihHpVwU>fK4o0BH=Uqt<;YJn9kX;K+8I}Ke;hcB70HOwUrj`TqzhRpD zvC2=$C_Unrjw#cc`gigR!MHu}TUH6v^>PLE1v;Td6xmoM;2ndP*#18XFYVdLGOF^i zl5O9OACvMlGo6q9FkO9?+v!=w_sWrLEOGO_oK8ZAeTUOd(zeQMS!KOPfsQ3Is>$3<@Msj@t$q5UFuDP^0Y+8c`6i|~EZ>1^MON#hz>uSm%Nr9N9#rIKrfc+*Zvb|!y7upq^ z0E5O#&w&Bl3OJ5wW-CC?$9aeTA8l72XjAot--{bET#{%oR4OV$-6D=D^2ihongsvwb!23 zxA!`GYt80LY9y2PAv?fny)h#;Pc&1B%#zCNV+oO!8+Ck(EkuZUsZK-j;zc|ynO>^( zXe(kFC;vAzr1Z(iuiyKv09)TbHKA1Rf(UM*YqCg+-S`4M&48wPieWI#V?w1J>%Zm# zlpDq0<5m2m5_e1p;g0jHNFm(utrT`={;30%-t_s}j8ci_AgQ>cQU<+s&j$Br$42~I zDTmW?Ulh9Nb`~h*wg0V>0g&eV$04}_kPkP~G|>Y$rfksX8tGpZQ$GpzS$^kTgt1q| zGWw``fmYjXh_e3k3q*#Jx+9f^oXZTdSojgBr)Qyqio@v}c=MMOnh8<2q|g@hq&u0z z>Hd&ME!s)*NFFA0#No8&c=j!t`s0w(4CcA*Wl7;p73fp^xQ?|7?A%LANJ^D9fk@(T zTHj=w50aNlJcr=hg_LtRy&qIW%06giDDz;nK9%y1xh7>@#`r*J*sZ|`@HO(9oYf$w z?{M0fBq9!{lpC~b7;71|PS%<@5Hw83BSc2;GyK@770;inopifKeJVd7rNCc(<-HXk z3z5a)^Z}$$@tdpoSq`U1f+3psj3Ty0S$g(_2YbaZ(nqh@PQVI$5W-f!QFg&r`9aQ7 zlG9uKN-$6wMCr~%QkgGHp@os0ofCx}4=^^BI4GcL4yPYOd@Ts)i+FxZc7E}sy$IZ- z_3Vithl$pte1@Gs(rV?#6HzO3b(B5Q7qU?peb16?I-pkxB;{Sh(8upD2L&@=H!PIl zYpD(?+E&q62Jm{7@u@^RW>Hl)7FoRCA&V9!CWTvw0a4!zz)=b}4neNbl?^ey6hy6f zliH$qD>7C^r2Fv=gTP#>K9E zOw%9kLc;WyfG*QN?_$>u)%0v%Dq%Q%fAmnM9~GoONz=boZ2E6zYx+}y^!sZ1yR*~( z4W4fgT0Wj%1iiTLSsy{W7_+cOCYXN!Wm7Q!?n@|(fcgE9&kf8iAcA|T&bHy+RzP0& za$O|qXK-^-xsj-A!?`Mfy@B~D3g)+cD`5VU?-aE2+tnu!DDg~S+NVze-jZ2Rx;YM$5Shlbi-%pKmjd;)n4Brm|^6)%#7 z2!Q0D1tgadKeBki9?Ib<6h7m#)$SsXH^KBIX4vZ}5_ET`6kI|!svtd)$_%sNj06sq z9czXwPJX)#%8u_P5o_X~_Lh1f*#%NrOco?^vX?I!kKp_CPa?n)h2YZ!`I^3cE}z(L))m72PYOy+85e z%zOJpc!xw0lf=i~CC%3>jf_%Jjdd~NbtK_?eu6zN>7DbuRa~$*v1)WsYc&yVHYbot z*q;dJqC!p|FMpzVxi6?YygZQ72-ce=u|x*vG7QMzQG}SkW~@KMlHT6J3b7%$FZ&SK zuawfuwZg9fM8%6v#D7Bh7PRK!>RuZK>W;RN?h>NA0J+RT{x}tHnuH)vPFg;|OvWB~ zj=b3-+#1|xlmp{MGS=E6LkoB5FHw1Vk5bJQQZ=#tnJSfddQ=GK54Ey{aQ;Wr$Z2Od zU&r0pJ4ndZmrC>mNyYhxWzduT#o3>6`quAB^I5=@chcuRygzUyjTMFW>yePp++Td% zo-3zU1J^cA$Ion zqGN9he%ydk3iRE}vqBR2%cKv1NCNNoH`(TcWRb+P?q3vA4&Kj&&?4ojD&?KptsvzA zzLZr(N`rS3Zw&g-if5dh$3adX-uEDh2)w7` zE5YV|a4;npPIze1|zwiJ>H-T5YSG>O0Yo7tt3& zP8EHYFoEb1G=D-!j3G#2ePL-62>(kq9`2!hO9y=4K_X>vy3Zhj=2ut^48{M95c zU&>@6=?zax!KN^m7OcNxu!(VKV%U7P9#SC0Rf)3@YtrvS@{O~lze9<43y4>cL>Vgz zmus?mK{C$Nm>>QIuilA#K3?4qHSX~0Z|pS-D`n!--PNp7UM1w`D- zB~-6_tB<_y<-JH$OLTJ=bxI`aU9=7tbsk6XNB=iQv`w3=zCKgn58hYtnko+JEk*0!;+967XsRO>vm~(9XDwX~XEW zJjN44r>|lHh!+hfOQ6$=FyQ4prTr9`?#-s5_l5-rfy@xr-eyyYm=N`!pg7(iQbq|m zL#22LKW4aniAc2q1)R=g0@`u;f3Tp**j&ULIK5Y9t61+xh3eDB$$`_8!Oeh9YXzqq z7n5ZR7KOaNE2)^OFO;9qbTpIJ>cF|ox9<|sNH_K3|d5p-H=D5p1_ff{fW_tEJjWOqaDYvATy9;8J2mcEViPcn8k zXoKY=h>~r!Y|_&aA@{3&`9oWfzb+MQTf|twzdWt7P`tlDF-(d21ME zXqN}=K#-+UMQAcP>E9KLzA7QI*=u-py9)cbPz<5dyQp+sQ80A+BC9dFXMUy#;N2@U ztkT|>y6~tMYe|2qwC5m|Gf$^#i@m^d5}w{EL0%tZl$z?P&ZdVV3E%Vg()YO!n_2_w z>%_r9wG9=$iL%;(pzh-?k{T0~_p{ooJ17ha6ECoXSLQ)Thf^1cF1fE8oX;i%yuR=F_^`!$oXZs-HbSVs z{rej-306!GhB+(X?Fl@v@128Y{(zKMz*`r*J_f#e-$FU*Y2NjaQBBHHEH=^GJ7|&4 z+#WfIl}GgUGE{0dU!8h_-s%f&?*#m~4%Z$G+{^k&rfhsKEVg!x<4D$h3(qT^jUoWJ zad2U~g1nm%W$m=5M0+pd$3hk`MAs`|x2J!VagOHvR7RjN{Kl$}LZnUX6RE@#16dQ& z4v&#R&pQWsR1pJEP#oq5E$I6X4^b2-WuII6z+)Qy`V3iHri?HGYnu3;l5wnd!)POpqa$8KUK@rseyP8I&qKtPM0A zqy-7xx$wNuW$k_meOn>g9)?2HWFexY=demriR%N>TcB~@f8lTJ^)(Mdy>?z|e>96R ztNv0Woa648g=I4Bbr0=G?e$BMQG!x+#xl~=k;vn4~9L-3y|xY_Hs@LBEk)A8ur>lf+sf40}ZWM9hqzH`fK zyU1Q&CgelkcVbVea=XG;Sqv^de}GnzwXHMjNU$QyI_Y8P+6GJQTnjE+11 z^l&xT_F!4KqyrS$vG?Lo%lo(XdF%VoSFoNXKNwnl`+O4nQ1*UO6q zi5DeF5Y~4c-};6t2rYs;L`xYvF2_Sm6nMB5SZ1E5AREH2lM+bC3YFpnq_Uakd_;z< z@21Qz*0-%-JzSrC%R2%x7LOWv*Yl_!2MFmUY>~qRvrd}bO1O1`_!8G-{sF5=)lJ7v-+^~Bv=)0G{SZaOq{Y2-8@=%#M>6_G2o(gUd zYy;BD9Hj;HCNS8U>?ca1Oq2a`DnU&4UqwY?ve$F6r4LmOCkaonysK)+u@WK{WUht` zpxWfC+VyI#*OyY!ZbcD~WkJLkSt_x#L+UULcF3!m{+qk;n)HrfsE-TYXPDuFdoB`{dJ^$S|U98tX3S{opD;D56O z3bkJHAS^ZiyW^UTS!c=EAdrQig)l<*zcHfRbKWa~Jzf`e(=OE-Lv?KLxnc>FpU25sErIz+$!A&ulkB-{`X=8X ze>G%~R}hZQAg{(MXocJ2^35Rs5yGn7Ip|KRA=4oLr7ty0lkFm?&rG&k4-|uZA~lxu zp1_amU@wB7dpTc7vRR~$QiJ?@u*)*Y>xhirg+h+0!R-!d7hWGkStD8~#Joe0%0e13 zgY(;)w%kFS`H zAZdyjdO%>1PZxP(2Ozh^(jb41nWEbvnvwQhg&Cq& z^DB%^C0Yt2Nfa35<3Sh&2^r*dTp{w2&kFJU{>2;Q7b@u=FLtU^gM1{%&cCt8PXlY; z9$x{CID7m>5FN9yYNkE@4C-C&@y~CA(6WABANgF<>J06=m%~{@?k$blcQ3a@qPByZ zi>eZdN``aQ0(-N^Z`bwnr)NkneB-5{=beclzehH(XWHYreEx^_c*NhUh7kAH&yT=c z3HJE>S-Zp@AD&^4Hw9Vq_xg)vP;>k?Jo^4#Z_4v-yRV=F$nUQ8^CMpjt)IL53KD2W z|8@O*|6u+6L7u2oyj`9ij>$dqyp^x0=3Tsgei54WzqZed_4k@|E5{4(9{IsY>)Yo! zGP1RjLl=2sRpDEm0V4{`-)kdBnT+qZt{Bfj+wAiR6YvtT&u?Ui*yo$fK7XKC`#i1! z^#ZkEQB9;uo4?mj7%igyUY{39AwHHL+VuM~ci5(%jXY-4e}s`NUi6*W^w)?@UoPtJ z^)l3(;qP^U$m2~mJ<0s_F^UA;Jt_s4kUdoR-uSWkYaAnee=mlsQU8#*P{jry*31?2 z_o^&~<7k^6q88cqlyK=_oShN>9TlqUwGGsWFD48-iH z8hjEz6r5%}J;0`0F7p6;85zWCo39>V*CJZpD`1pC@~RM3CYXo`|Im4yMRj5uA%!s$ zz6G+ok@|elb}uK8ufF;IUL8afZ~ZOQM#zNyiV9XWV3CQi>@TPg7DH&OVT$HmEzC^^ z)sYXCN4;28wO2(yh9A>GJpXjn?30$07VL=<UV!WnWCy#4k2`$U$Vt=~VP^nNJRI!h(421&&YCuPu+_4^S|bGlalE*?*V z_4_@a@z?JUe2&J6`gA>qg#P+{zCD*s{|1{`*6-^ZT%hySmm;NezWNS)rQzPA&}$w< z#5)qUgOp+v^XfabL1A_-IE$^AXyIuq1&(9Cu(F_q0Ycil7C){pj|F}A(pX4}hVO!G zAkq!&bloG=VK*wBW8{aak+83})#E|VI_w=n%-e(?3)zDi1T8crTBwh9ApTuP;0L)Lm|gVHlT#PMIq+J^4yt0x4s7{%*5^* zhl#ybTjBtchzv=UwS=cQeL$9cX#w78h_dob7lvL{E1?v@I@$4()2nO*%+KpFX~^E* zS_JuwYZ+*0eGa}!>ND#zuGI`rC4TP3rYJ+w`K~`aM+wj$x=DWsoVOtEGswoW;{MAZ z=bTN}7;PrmD7raar8z60IYlNyuc9l+0qEG_djswpD+SBAH=ved zSjv~C>DrenqE>n+!HbbCV~AdTMo^dU3sn(QOCLK%LcCWfA%`6Nw_TUCT<((T4V7g2 zRN__=RmCnB{OYv@1+A0rXw~6+0~QxpQ6g?$Jwsw0=S$sm?YasmOaVzoRajN|)(rSw zfJDmhN}oZ*&Fjz8{mS_i@z#QGA^F3Ee1?nFbP`D=USTdR*bYo6%Ak@m2)TJZD8$tO z7#@&sK=N;KB8p0XniB695Pw(_WysJ_leGzwU5jMV`?}kl-sZF}g>Q83{btA9Ep1Ni zSoq#)g`f1y8}lQN0ev(dm04+T3!2+q zc=f)?A-w9&2Q5G|`mcC3^nKD<51^C&3%r`3ns+f?<#=IuwZ=c*PbwC#t{=(q(M!uu z2(NbMke9umWO%hLyA|Q28;Dv!cv;MM0u9&dx`Ni3+kV<@AyNeV6@Jyehv z@M9Loaz^@imEnq4?faxTh>haa3vLvePZ%GEPV>OaU|B1*x%x^Q$Uvv%RLoA6U4*(G znunNO12LacCKXIfAD!-FxeT4wLAhNr`cL7+rm-{J>zWLuLoe7yO#J*4J0B$J7co7{O2zicSm_Z)mN>5 zfng5d%oCw9H=)*|u$-m^^^K8=71Y<%6(Mc@UTo*l?~}GE&qpO`2uj~UjYmAdrh{@M2;MjEV6{} zlbWGQk?IwlkgBubHm5kC-qUfiz|V#K!6xV)-RkF~_B zL_gjV{8-3JhDeo{{C(0K$>kvOYv3Ub(!Ni+4|Rlh^yq^`V?czF?~@)pnXQu$`H2zM zbepbinJW;vg9_9OKW;$j4f^h-l8{9H624FR86*|E?jxk!_enKy><+YLp zQbxW{+R`cLL%D&Rcjdq=xBKp;i*IumPL_>eV=rbWbi5rp9ofi z#Cs!B+wUGh#$vxuYHcY)K=##+e(km=(JW>sEU}u_eq~pKWJmc zexI~)sEEES&xvl|Clw->iheixSQxlg_eGBY*Lz99X4eNm)P!$B;fwh`=^EvGalkkD zK4~W7xJ4TQu5E<@yIRYD{6|o9@!u!yrwmF341({IPE!UU;JT(mApKWEob-c9zL@Wm zUO^I6*EHtR3NQBiq&qd)xFDH*pM*kmM04#4CxU@YgE1fHjU0xfy%2M>NXHO&zDJug zc78wJ>mUMv+kU@Aos)+S6N(MCNHx`LhM(YmysGGSxF4^|PVUFcVLy`l@y0?BH&{)e zRPL=O8n%1c9Es`&7B1@ANYo~@DHk;kB;+G^nN_tLE9AlBBx95MLyo$ zdJ?1C$vt_`*fa6&Kzpu-=k|Oq@t(YWL;H35ok^weeR<0}l7YJ~FOAod?#n||?yI?* z^CqHJI;Zv-)G>8x+ie}2Egc3Yl4a}4_Z^QJd|O_#Wy9*_6)tAyUa}=`%-7rUa@Y55 z-t@XveVY&8BVII)J1MEFN+X^4PfpDv!)2b6E)(BOEPjbqjV25=L+RD!7kbEOf(D?KXDT z(koYz59|P5{52mLGcW#njb&5)rDw@Xb!;SLvyewMWakUZ%+sn(PK&Vn1n3h7;~$NQBYs-xvrPOMw+{jS`T1x@bv2?ypyn6AO~AthDP3 zZ*QqYgdpt#sM~7AZbJMD^+c04sFDKB`=*Fz?PROy+q)NGemgl#p8;k!$MavdertIM zX8D1WR!v9U0X`RzG-kzbIH)5OlVwUJZfIroQa310ZxF#|YChUJD>0TUQB;o%Z&TomvUs<9eiB;mJ3h?=B{81ab(QggF?ffB7ei==u&-nZ z1a9?_SZ=bO%`n)WJvBeF><5;%u+&nCl#vi|pFK)LHldzuA!C1pU_Qk?zo=hPLn?7} zOM+Xw=WVMLKk(>Wa2eG>WSiHyaD6aN?f6>07pqyt=xEKX^k~5m)IJ}kvu-B*;hSQ3 zhg2NcOG78^K1`pE&Bb=fb0h{e&lubY|2d8-c+-{%zEf zc81;!w;IU>|03B`d#;yWNm|KRZAfZZIB3EPMNF@hU+Em`j?;$lDN61);okbp*yU7+ zREzjk(zQl5ieCj6ws78~H@F+>YMN+Hpm1wx-ub+tPnt9Cg+L`yWr|b^7YHX#nFnO&lOZ z1o%F!GQErL;&-v6_a|D4FV=>_h3P)J0=XK&(XM~9O7pJc4C32Wmk%M#*V~c$tX*HP zW{=I1Jl=TAYB-iRO6nl+wRB*w7ve>*;2y(Av}-qHar}D>2Q@d$uq=Inw05typD}cC z9@LA=U2xtA3NpC8D*OBXqU^>>AYO1gYLWxvco`17<={g8zB+;n1DBzF40&0JJgh`E zogh*So}ca_xzT@c?_Vq*vDz^{)&!(K8#}iV!l?1b7%l4_r;wnI(BtWP(0hp+WNveJ z9G*%IU>LYpTDI3mM8%zr+*-AL)paASR(<(-d0;EBp&nxE`Z+E~fXm0hi>BSgW+h*!upy1sTI)>bic1T`G|jNA7F9#D9!L zohPHCMGcHZtwWu=TsMG3VP&WdmJZ19Uci&pPqp1^6?w_PUyCY2D&6;cexW`S`}DDA zOoOrg_+0WO1N*Aqk>Z}c!{lLv9 zsP_%bkmucX-#~Rx-zEEhatDeapLd2XYm>Vkwe#nKip88ySb%2be@F(vQ3e1be<_;4 z-+f2MamD|RtZv}1+LlLom4J7KNAZq)Pd4;TXxaAv$ews-8s;_PotyDXyhAf3^9!?X z2#bDU<{?DRZ>aCSFDs)XF~=L*53H>Ff&bwCfhw+jhR=Vvm_vZKLVhr#`Tnb|p~PbL z1JhzIdQI5vxF5I`oy$M}p$`Xq+YemQ7cY_h!1)Z3{lL?h2TJ%0WkQAKRE@UD)`*~#;<_`7WdI`A8)=d5tm`&qFH&F=SpaW1N z#6g^|;{}*wX(Rlp>W$v~_n`3izA{Y-^4J?>!RuQox`eb=VJG7UvmY&mHyP=l?9Xt8 zMlA(@#HJ$F3^(&v?b=&t-W}rOoxm`+qxIuOOp&>xwJ&7h@}L;|3xtRm`}0^=x|~*3 zi>LX$M3}>J(losBqhf+;67S6uZZc9j=SHq7qG(ej%KK56Q9u~k)uE3h>smL$Zj*^H z_5^A*MEV^2#I=&rIroHvb;uNG}2)8bIeZZNP3wVx~id}>Zn2F;B1*lHE zABendmwmm*Y7U!vMqeR`Kbq_87yY+nh0NfWy9@KDuWbD@c@za!mU zY1X&Ip*^j>WP^JzUW8bCNd`3ZoOEqu0B9+lEBAu~wBV^c!u*Lbyp2Y3JTDL|NxOMxwnt@M9s986u71CQwg9D8(rw@Fu(5y>x=>C}MC# zztUKQ983p;gDAxA3Fxf7AF5e;t|=sPPe8Y$gRcG@(wa(s!ZqE#gDLwtp-pfK&@`2O zz0(I|IYgR}_ghe&QzY7(jvpJI;`uLW7hR@N(~N)tockowdmbcE1aUAOf)rYxRaN{f z2h%?}+NBbyhHT5S4|S@LVVCMg`sh;6p#iZ8gzgD=o!Kznr4r`^IrXYgZ|XV0h-e4T z*JC0%?TSRoaNAi{u*lBcIAOqoeF1^2VEd8$KE)Mm7Tazr(J^4~6WWk6xK9~` zcJ7W0Nq>Dne$F=_KZ9*AT3cr+@l8iM>Bmc=442bmG}#A1vi?Zs*6aQTe10!FeTv z@Ror){rl+KBWf4;n`WL@@-+qb&llvg;>`|t^v^5lsn5IVypr^Dy9jRbda~S1|Lu7tp>qYV;F(;-|FwTLhZ=!kk4cFIf+b~qmHCvPgF~u&MBy3EoGnB~?|RdnAfo3`Ot2m$%8-ziDqJh1 zGNbBZMCy{Z96abTKW(i1JrrZML%d2@#C4kA@UT2rSc_^d1^=wS)*PSue9{?7~x}cxTBE&Amy& zC$t0A3VA{|mhTzAX$G^VynA_YSLlxPeU(()kvc7t)Nd?xaQQh%4Ny{-W{`Tfr%1IA z3HZBgvlwOo`4|=c5l!}h{80FB$veFLIy#Hv7EE|@M|xG^8QhV6h7y}3;sqcg>JRqM@gKUNn#tDN~GL_d=hVDkT^*4dhhgL$wRd;JB!58Ac0z#Bm{z+ z>c>k?Z-s~wD#q|E0z6kxiZLQXhU-z|+2>!VU>6!)=?Qm8{dj#4Wj$e`az6yAETj=L zNL!|#Y5Hh1M8Yhd!&gmcxnn-dq@>= z6{4(&?+YofAyP4f#k&v*kF#7@BH>4M zim68aLeV$}G9;gi?5;dthfDf0C9)y4jFxUH>pyxfP8Si-D-!XobPKe^w^>=hHceX)++vfvnofA~%5fqK#0icJ5ZKw6EO=4Glg{pG$!k`rY7jU7x#ISP}Fb4^r0W>V5)L!gHxK*ZW;G zS7(>&T$d|1$o2Eb$aMOV31mDfJJD=SR60mh28r@4f5Nw?keKr)T!GgT{0VPBRPHYKCoBu9o#-scZpK2YKj8wD1wMr0Pq;~+ zcaJ~ea3#LW{0Y}{=#Tmn7EB85s@3R>!qWIX8V%F@3G291)E6`NKlLZn`@GekP|t%A zf5N-^VK68j_oTD@2`8cWA%DV=ElOef>VuJ~W2X0DcLYYg2kB3!`?bM-T1A;UVm;8{ z|8M_6;_oc~!EqhgkD=P(xfraj!JG3RT*KalDCa+Dw(yr60q8%t8FsbrKiI1i=e-jA z2d8io3&^J@e(9PMMLsbR!RrbNhJ2j=-~buRW8da6%KJioXuuxKv|$5wL1(bneX};0 zMdL+}ktO!c>f63qL2V`VwrCJyzZ&ukyHr?vPn#~pe);NT;W-jvn9s#ouYx|8NnW2* zutOjW^`#KzU_cl+x(H@?QBgz#m3k=Bh;xH)p;u#gv3_uWf+rmy1eaYQ*#(!KC}S>W zw`J*GN_$BMk#2wT_vy}Mm|6aMX=v<85Y*8!U0X9w)QsNDjmjOfr3o(kz~pxB;ibWb84BXQ=W34Y}ha z)tYTe!HSHDK8ta-yF_&{UA1<$WDLQLPM~dCD^&gVgM?h54}7*NN!h(_LISOp#_?!X z;~@z1RW=Q@O=a=?TH4(Yusk##%OglVjtbd}lHPa7KyBrpg!e#!uoBdVr%ZKIT1;B9 zw4OIn9PVeuCP09<=--x;-je_+8M{$Jz+{J>eGR)=O6&D)uiApmhJL9YhD&v|{bb1l znmf|wE!7Mmc8pAK81M0-J@Fr1KYuc+RCeduAvB*0%jpz|B-_itFk0zV1xJVOYmvPm zqKhS#=zcGT!8q)Jkig#rc1SZ+g!u=?_YL_6t`Ok^%Xcf}Lj&Rz&s&HO4 z-{_qXrn7D)Ce`Zq=;I=1sq(Qc~ zg-X;p4~1HQY}zMgYfjEZJiEy%$7f2ny>Un(ZhNiYdt8xBVN zL-{A*CBP>=(Y##L=15dOuy9e=Mxr*Mo?X;9kPv*bLw)@w-oddV3!fZxJA?TZaw@jz zHhsnr5?f}^#4RuL`5)kuvSEC(Q3yMH!q*b;$wEZ!dVF#gsQUQi3l>1}$t`&F@yUbw zynFCT6D7V|@yUb`KB?#9lUvaucO5>_bL0h|Tyze)(Lco}KR~wKfKR5Q!H4lljV`_4 zDY0ob-n_0#*e{j$K4syPwJq3>(L4m7e1%>c#Nn#xnj#4T*T}I4v1Fhh=e}EeS|_ zUWzOrt*hgn?g`og65|DV%BC5m5p)RA+EENKj*gI6+60Xl2AiOUrr!X%zJ0DCUr7jb z5Bpp#m72_w^xka7pAaaSfs|HPgS1vZV(oEJJE*JSnt8Sq-|Ff|DS?+lm~YbUr_Wfd z$H!2QX(KMMJhasK6@uDDgJ7aUn(l}cRC2U$vI14r-{4Tmz`d-pYKs6e*LMXGy=OPJ z6(Sf|tE8p;zNwV5kuhcO@IGRgL6PspP#CH6bj`-7BEtb?z=>vtELtxSB?UNOvXCno z2c)6H00+!0M{9|T>4jlBf&&^RLpY#_GN-(EZ;9Z5bC85M0F$`a$euBYdsXbYM*1@! z2keK^_&A`Z@G>00C5L!Efw8txZwDlFRumVM#e!PIJgG!X1jZ294jI-yJx_4J4AtbD z_{r=TqmQSOr2*b8Mrmvk$lK;t&}dE+iM)IvWQ}H)XwvJ2Fu&2P1~qnYH1#u?RGNA# z&`npC_Q>|$nh|L4dC(Zm&vs%UdL0q$>m3^wsYIu;RDH0}zn1y9B)=?O9Ua3)2VW61 zKg%J9n4fclq(4eq@?L;o%;6^wOyuX$?gk%BH6~*P%$G{MRfe3K#tU9S^CZ97Z0nMu zx2AYjQw&~}z6VhO9{n5tplZj7xw_v{w5NL@kvorWFuFuB{y`jv)IaFH1eL}!?b4v( zY{?1`$Gv=yn7~qf0yXBMI2W>~IF#jOb0DOk{9m>D;52_Y?htjY|iFRnj zKWIt;v>G{o?!Ws7HDOsWj=?F~zBfUM{;&H+uWEw6lJxq^4~8(`KWH)gP>KFQ3)zk6 zA2gc=px$TH@)(YW<{xz7v3QC22X$k}Klt9{tHvVGa`~YZS_^a|R_I)e4rYaN*pC;j zq!6$|`Psf$p?06q>!PI$r=Ckl4)@<#fo1gm9I_$oX(@q(lvA|~z>kgaw<0p+)YFd% z#3KDmY`EB!h_@Nt?lY>UB{|RMlzpGkuZ@In3#179HGRQg=hsvui8B3~UZTiin%yNe zC8pU6tQOtJZLJp31m*CVh(e;a3_gOjp*oT_$M&1l}2g(JtTyL30G0&;`Mj^@+ zvr<{KLMn#%?hYL+m$^H1M+V>BVPDahR}m>_LKXB9LpS#5(WZt*VV~y4x#(u*67Uh{ z1t}i{{s4U4xV{0j+{=5ENZ-;;)v7F%+M)5J2f!v{!@v!NdsU`(Zi6^RN7ya-;ND6>SK{sWgQXX8ar3j+|U#V7D<)uNBo#d zae1i1k@XS<+y|rdcd0pV6Nrf(=c#Er14;OvKSbZVG&H>i9s(cjDCd-VgEW3v8Xu== z_==xJY%*w4^mu`tn|=X^I>Y`_3L)0c3NdGB=$yeY7&>oBNUR15WrqC>4cSvdP}MnU zepRgg9Q~y^#hz?{%&9~Rh~@k__9Q`$ae+1ak)) zOXDluXQ0-9Ta?YZ&qFMF(#t_A3#rHqqTOq0OFn=~k+t*7@#gzVr6rg1mDvk0B!&hnvH19kx-usIUfPNb{BBl9lT=s(4&qGwAvG{RaY62Lzmli@& zYI}vOrc3=Z7wUh5)V9}8h{Tp0Y1C=s_9au+Xkg~%g1e1a^`)nJ5BWKQ)>>PHRj;7M zGOS2zrR!dXugG-9;^gmbWF(1>l5XQohRCXqX-MMxvm66nQGb>>%qe=g1nEpKr(zi) z{Vl73RYZmf?W+bX98oo<+ zawO`Fa6{__65;jYve&ZPWvv%a7@@tf4ov7i_RO{8j`mDjy#b&9?RxR>Ye?9w7mvVe z3G2nJ5tX~k{aKbnXn(!9GYg>W#kqL&*Ndy^^X^$Mo;q9@?auY$O~XR##qNBp^U)%0 zy||t;&;M_Kme6|f%9Bd8)3g0q`lI-}VZC@X8vL$ZFMjDT4nk-ivR?co-rRa|HR%|q>>oV7i#~sdj=l@zSPKXFzL;0blJ{YtjmU>l;IcBM^!t7J>dh!0O{LJ;@xg?kL zwp&SM{%l-d!j>Wov!yJvo~O@|_2PG!N38Q=){Cz{RA{{E)0O>x!98hPFFqSwbg=T* zi#uwb+boZ>qbZLWeYMm;>jo`ntU>-JxjfYuG{gm?e)U9%a)|N^awmAu1mL&3n5ihPq1gHXqcr|{@jeto44+`VIEP`udhr4fi>?<>lMpe` zZN2y>75%P5kTbkqT!55TSGHa}g|!!5FU})Bd@mz3tgc?s`a2h4eqE(O-0I4$7oTQ% zid`?RgGe#TOIR;%^P5%Ht-?&y6&2MF zy-D`Wwc~tyE@8d+Cn%|{J!mM@ASTj~@D)GriF$`_J_`0cL?-r;g@4`=J$LMho zl`IX=Ed8rMK5MA=O0y|py?Dh2YhevUGD&Ld#bY2?@$1E-&>sBt;!P}NDseaHz_>1M zz4#+daf7BPX1#dl{@1H(hwRn6@dE#b8q^2QMT3Nay?P94^Ka}`_BXXxAFIQz!$0W# zdAtPn>eZ0fMeWPFc5mar!oA!V$yF_!YbsvC_UiB}*rv1W)!fS&to{w3T&B;oQD@pS zx7gUhIb&_Zm?IEqQQsl)jI##zoG1b?8j&xVz2&j z00tb)L9)lwhaC@5nf}-3ve#wWtII*>|Fl;Nz!X#a4e~>K^>xY=_O9-YG3OuIs{>g1 znf7YMnnJ&;l~l(0QMDxOV3Atw)n~zI)j;g!PgZ?o1V44DU7I!Gieq>S@L-+g?2c zF@JBbc35W<)GH!9Cnzxf9xs{G@;WB40-L=$bw5$k2E=6At0_i>?bYj8mZ-hjhHWh= z_G(MVy%>A-OiJV1s~0n6hP~RIVS&9`1+1d>>JBK^PW?1{)f0x^cQq(NXhHcCq>S3D zzq0nC_Uc52t)t;Ze&|ti5^_B6nu5PDop2#f3_yy}F;2 zQWks7UM(ZV^ST>THY)Ge>Qtb*T1WjGPJ!OcUOgO~oV~h1s08-v1bHvnzoDGbA%Rq4 z*;?OTeIiUp?A1zrvhCHU`bO;47D(dzH&nJ~Oyb^#i#5DX@%{~-@G8k(tqlpY?bX@T zOe%4x2<-bey!U|EtDi6qe)0Ip>=+O4%P47pX0N`Aipa88dy7QgBSOd;&8Jc^-f)EZ zji$6dv-^)=(&FsZ3mB1Yul7f9#9kfnJyjprtII{wo!P7Pkwg3&o(Yngz4{SCinmvn zV5ITw)gjE6N__uaiS}wwP4R)I_}BL8vDHHM>i7Fl^$q$_AIX|efHLgWO*+GkK_`X1 zT45*txa@CguWklaXL;sQLihF>>dn3MjYKU63m3HxB!XOh!nwBKMeNl<`n}-V3)yzF z?9~P5Ggx;%?zCsFulBd+I(YW@{BP~mdcx1ytIhCQg1x%(g56=S_5)SlUVV=RPb@7;f#$O7)>o^DAB6bh9@gYv*sFg)w%uT_9?Zfe zafL$X-Z1Ri)&1}GYOgBn$7mj6uXe(lvsY)Z;}v7CKEqx|dvz@Kw|#%ydV6y`En$82 z7$l@W?zhGI<9ht++2(_W~II)tEv}~4E!I~;8*+~PUeOZ>|4=F#)18p z2sv-6l~0Vj&#MZj>k#IT{bltzVxt$?Q5HK`o$@S%uhd1$vlq~qO_4NyncC8PB3Xy)=hd6vGVR@he{=$HOdeHP0bXPU=87iKK^P(9PUpuc`| z_#`64iu3Spr4M_lzWbFGcSI$>xF9zexiT$_;bfr`Oj>8*SOS8XZTp$JMjRp`vKDLS zaaNHKDA1k9xdSz8=gHc6oIfGNzNH%pkA-*neN3pBpihy|jBDA)6(U%Yxg5{rww=sW|>N`H3KMZXmJy*OPr2W(!0ezTV z+ihjYuH8@g1a@t@0;Me3u5D~|)UMtBrEk|R5wVSq*tNsX2-&rwvy}JinGw78VuY?3>qido4EW0)-5_#_lA+6ik4$-VP z31NQsIZB_|xh6BIG??n3o5qKPB%T!F83SiSC4Oa?_`^#4#1QchAu1T@$YkL3Y{}yt zYgz4EyW7w>Y!M({a3nN`Mzs~Wsla3_dJPmVpfmK(GDgLg?FCW&@9p;fLX28&s+v}hdk6- z>Ho1ko{yW(cBFrB$Cz9|g6Lg8OSO2-OnyIq;CXyJsK)c}0w-+=WhfKQKm6RR^Ua{k z;`}OAfELV?`d5`xQBsK`G#yi%g&s<29S@M%_8G{C-^Mg#v4Oj>bY<^RaI(_*S@`)i zv4uAo!&_ZXX%~K-KL2O`=`|b&Qh9siHT&S|FFWUcs<(}O3eD{j|LO09JZ~~{=lPchZK5+&4Q@5{ z4_cgo=8<*K;sWF@{y_iMIh~thk1w9D=Z(CD`^#?Jq34Zs;72444=Wiz3`g$@zBkB| z^ZdVOQ;GOf58)`6>X6H$qd5UJdo@1xLWD(6@0auZ)sCz0&hM`d1~$%^KlMMq&pSBh zGj!f!of!H~(%VmdFtzyp)Fauavi+&;KJP*7R`jQqYq8az`e%@E{?t{<;3eWuy<<;= zh(GmDF#Cxj?!+%$BcrE|+*(=$T5bZ#9+XOzw)6Zi*A#u_hm*w9OdGb`PsVs+h@%4( z9532JmOvaSn3aM!^xN!M4>pY?KidnP+`LIxd&l__aNg~Y@<2@|un@WtStFJiFwbu$)h<;^A1I~5$HRrgYb90dtgA=Cddg;W=X*i|4$e;73JJdiUt z?DzBGP`y^#Ih*NsWQk_FUIF2!>`IXid%Z~F&2t)pbQ@F;Y=>6D+7j)J#E5Broac#DTBt9#S)p!aOw{>%1Zm+Gj1SmarQ<%KDE?>kPdBqNZOTuWJh<2r1w zdW}MS?cRasm_^#-yHY*Ebq{8amgO17rV^t94ks&6Iu;SCinbVh!dC(;{L@r3*{KE; z+B=44A*a>$SEEtee{dSfyb>Uxe9HxVKa$zTdj(}tzVD!EhpzP$MM$!2$WlM}ho8HsEM&?Vt)$iB<19=^v0p8CL=<*JLjT$%Z1C zt}pxzUOf~d`u71m0W$7BfP8k9g=I4FD*Kh<)u*;XHt_}73L0)~I}oLEFTYa(?rk>O zfO|QIGP}1Az|FmU6UlXUIM>g3F}!+=;??(B30~dQnnS;y;(8B)e7t(CJrl29#OHsA zS0ms1UM9qSym~3#O2DfgqISXezL|J+83niReJ|s);?*X2^zmwIecnxY^^=yn53e={ z?QFanLo@oXcvZhA5WM;W&YLUAKWjK9yiB}05JK&0yxIgU{$Jx&o;&klUbFQ>ehJ~# zt2U$W;QL?s!Bp?#)y3>nCF0eE>{c1~&9(fUGpPUl?-sm7@M<@P2wqJYUQHB>SHIdM z0xg#x8WgoaH-bjzVze+cIuE05yl9T0(QZB(ZLY@f>#C(F8oh+%@cpk9Sogmm8^WHJ z5=clnRm%YUn4NGdBYiZ=a7Cj8>=1GwVhxSr5DL!E)wLWK7#{}$cTf)sHQK7}R1;!m ze0jT2*_X1+BGPdxWSKz7ijMz;zrej%pyBWUpHH-ee67E;*!HxGIAd(rw5=nXQq;Z=rbWpa*{f%rNsr|;L0O}~oP zTOyCl`KV<=_LU5FSbV%B%EaPxpacct!}+9+TLqF-td$d#!{;E)9kzIZeq0#47h*c> z^C)E&+qS$Ur%^e9VK6GUa&AnSEour^?39RS+dV3%P?1Ff~eTo|w zBAV~{J@oyoji%GUn*92;pbF1Mv{oTXHWqo^eE9^Vb1(U1YIU|&tA%k87 zPj)#zz>~jG=9D)UL5e4zZiU!($g?xcRBM(u6Pl}c=Xm6atuzlMyd-t)+#I+~9rgdJKaNZ(sA z3w1Ujth0rrAUb2b>Fk`LFs0v;xx||&MTzD5vHYI-E@2C50q|nHNitam74O5Jv$|q8 zVP@YmBib@t#SGE%O=oN>Q8y@GQ;4Gl87euCAAGp0_&r@AuJM^RU3)i{J=1%z5K+=+ zDCwp1o$9{C$dz$kew)+VoYtlAjn2K_?3lZy&8Zy=-#e}Flb(5Fe&pFa2~hCu{n;qD zv-j^nLnvl{Dusrj_WsL1p;&tV7xKBbcNBE&Udm9D?rl-H!Cn@L;(X!KZD6U~8~eR` z*^U>p_fIr?zmeGc?T=yCRA09d2=eXyF80iQtAqIb5AFT(&dx%{iA_k*xA&jKTM71l zH$?3Qdw+Rj@HcyZ8w;WK{wO^9_Wlfg-c9!Y@u0rD_NPuhI%MzH@b{;xp&9*Gd%t>c z&QDhyyZ3MG{bAJdF5aJNixzM8ep$U=8g=@2=lulxq#=8M>Tyq~V?II5eyKk!GqMC|?Z86x)n17`2HFV^1wB`pH2l^@#s4M8_z z@4t`H!t8zCBoi-cKq0XEv=9Vk_sQ)2k3~xv=lu*Lxuo}!6LEnxR+gMVIh+YNapjK{f3nz(h&O}g6*c(|)skG{a|)gJbFZc-g_4->(>M*; zuvR2F0eNK7LCI+Yf5u>E1K%QvGHu|QEQD-E-7g$vGinhlN@qg52kchmuv~;AQ9A)> z80$xI$dd|}?nK@U974Gu&b5|VRQ0SX^hQLPs=iPb9#S#HKLMz{<+2lix*~&*KT4@j zUU{UzWEL-&rr=}B_ojvj_&9nt=VqNQ)0{b^d}t}}fv+3h*^b=HJCsP@(zO%|+$8md zIX@>|K|_WFHOO@~5bP}>FrjnOYc=E)2@#WYnTE7Nh;4qnf|T(hTzMgzAIAb_$>s+? zE|z`f^c2lf0mXtAPZKp+4R84lVP-U6r^ynk#+8f-e+TkDHLW$3qpgPRS3C!U1^)4x zd5N%69dviCk78tzD0fTH6CH>rhR7Bn3qt4bNfI_xj8wElKb9kBkm zKNYh7Q41h92ok_PDh;mEeZ>A3{UJ86|6h>QJKInCMpP9$*h-X2JT;Sck=Xwk^dk0u z`tZR1Urm`)-q3o!{r}?;ocph<%Wp*LAk?@2e?un01?hIWcX0sZ%Q`-2p78Z{u!!6R zrHS1{Yq=EkWHow$M0*SHV<8_fM3h(;)YCIjmjW^N4MB`2C6|L3FMyREAM~|CjGLhj zwK6NOCVQC6yx725nyDGAWz>n*XJ;1=d{PnG0qV#AO`Lds6 z_e~F;50YO>Jg0(ELP}8YV`vH$KtTKLJA^DKcqK3dN}4RU0z3z^fwgV8zfrE+>JWc z@}v?M2a>dq0(j3MqtFXhDjEqh9q+etM9>nKXNG9`K4&aWfeol$hXGOxc7{lVCc&!} zT*Li#x?hlokk<+_7?*CQ+j3~l+-kZ;89c~bD#ZaZ0tcID=>rvTuKhYFhwY>FbG(iT zO3_|=yjKNkRyk`UE}owcA@%(s5JHCwZS))_bZq`ZLo})9T>`0Z$;OOtvaO~PTc39_ zUm}SzHhLb?WQ&4it&vP+IKX76@4C`cOlEU%pFoBaC_~xe$hTJVR|n+3K?jfntQz|J z@qe?Q^vPGy(I2_$|A^Wgx#|Q3jmM%7japa<-6V5M=?L^Dg_ymNSyMlT!nm<#5$L#= zM_5ev))#Hpy_93?ac|dxp?fKcAddLz_BeEF1$ic{ z?6gInxusO=cRVM{$7hON4=__HFLhFGr_|s|xmdIxT($3bTI(Z+@7O1dFZ3f)nHZ58mW_;O%b;>-D^8T>|h!J4}XUv}7Q_uJm>)D-OsR;zc*1t z)d_saFO4BHUi1*Gcf#jm@jGT~*?7S@O6pE+1kvrXrdogzQUK7W75X$(4>s2$%B-Q! zL<+AtQd!6ajP$q57_Q)XJ)k=%v_-6e=dU<>Bx7q=2+hVmpAdMSt0~?D*SB&otmdSj z(vTM=1OYkedo<)>rLr!p#p)3CW;PauP}{U(rn1ubDSZH;x(IKt$TCY&7ijTs3kvp& zvgnRfX86elO)tv@u*(ga3y}eHX}n->MY;zen(z4^hyuLX%L8-4yq;P;8BDQ9AX*z4 zRI>&g-Rx5qgx$-xlttgtcdPNaUc{@M-lTQfUld)DDxx0;sNEQ-{$dTeTtWo(_Rx^C zB?P8)PP(;*bd-=X3~8t#$4dxGlaoGBLk^V?ls6~6mxff85Hz!#w0cd&R*3lJ81kJM zfU#dbm5OgFa%%(gK4+MLN+fTYdNLM0h+fTYfLIk|qe$r@! z7C-28W%km>!D|i*-|#1{~H=o`eg9bea(BoR*_k}Afb|+j=FJ(^+HyZfUW8h zOT^lRVKB&JLIvYLHjzd_6HxxbW%z;rwzd67^X?tyvj&rAvKvnbodddr)Qyq3SfN$ zZ(K_{8#>)8xdgDv{wL^3cWQ|GL-c2;S2bNP_=Kv1+5d|}QP9qpkFjqNuP*-B8PL~b z+(XD%73gmKxQ_KOL~<`(grrny6NnV{e-ymhK;k(B_Y_hNubu-cB4rnP397rKj z)@6*3SC1Dd)zGgO$oUDrKl1VF296^UFGtD^4J>y;LXPrU6JH?8blgm$y?gOvqZSao zcG7tob+-{PxSB7K-aR0JA`BS<7Uv>`D*4ZkMEt?PY!MH+s~Mh340)7oQKm>w$go!& zPx|N;+YP2BtFqxrowQ&!C?S<-7vwCZ0*ptT03PFoM3tFHGL{lKgwe-r%Ta08EEQ?K zdBjOmNydKf4(L`3!ucYe&#UhA{a_)8*0X20^*l-n!tgeb6lt2SZFLrEWv-60>-^wG zVHf&gl1;1gOv<7vIYI^sZ!DO3tcLrH)4u@V$+>v^=wsNExnX9Q)o_ zVPG)$Dq+CBcWOXBm*j60@)-p?S{XDB81!-s#wddjHm(|ye$!$n{lmCEHeDxM`lUz$ z>A!r~N&hFCStjg%N|VhDl6{P1qwCEmN1y}ZYtJeu|C(q^VkpdnHYA?2Y60aZ5y9i zp=@5M&UMSi=QYktwE=$U+&Fh#Re$}~aBTRVzDeJbiaQtNl+{FDxWBt=eBOb36>cqf z^@fYu#OM8*m#TIgQsx$W?sDtSh0E4e4dJC!_icI2mJO?ySGbtXc*&N$F<)=X%U$2M zdDH7w^=&?Uk9g5IcJ$O$`08!h(B&vW({C!^e31G3%6TgS7di0?r4SUz))~ zKIJp69B-e$^oGt|;`2W1lKXk5)Ty<%=QaCuSR$`*`?^Z{omr|of;J91*!Tmq<)uoW z)VF!r>sI3~RaSKBDtykj@#>YGbH8ezyBNfKEfeCq^L&syQF*8#{i?5CyZB7GPy8#i z9sj;QAJxi{@qcrjIP9Cw%`dB4+5f&z?-N&iE9ZlpupXVQ1bmxypLhc5-wo%3?7_k% zgY!Y`zP{qyY36->#JO4b^)-E;-5V7s=Yt%9H+MeBo$Q5(a_8B7%Yi5vOR)>`e2_h1 zHT&m-l>LA+atY^y@LD~7xziiJ+4uF$c#nL%?c|Nmq5Vw)?*WDr-J;23)^Z1(C1Yb` zgtU9Nw@Y@}HM|-^$Y{PS-ALh4W2DT&wEJjWN{a3sC;5F$D~B533N&YRjz@{BN)if# zO-CMEhx;^`8EE!HJpc9~2PhETk)Ev+>8f`rNM*#;({w1`2Mlv)_EqFDH2VQMP`rq` zA)4KekyFs@6-w$YXj}JhL$|>VP|=?gh@2eysP*+a+BeCgX+fWOJ{ugM-4-z5}bee`N zmk?OTIcfP$AsKs6LIgS{HBD(LVdeCvS`CjbV&n0CeuqD*CvO773`w4*xjvA1Z>Ma1blv> zAzwnBZ{-LUe+MD%Ad|Toy&VEMTv?7n3MP6;VrfBdqQtPEd7rq>FF4OZXqKUxhANqd zBt&qz-X|VQNr>Qb-Y1T_yjDWcae(iISUw)n0+KaXKx#XmWZFFhsdi5E2+>x6P}_(S zOFo}ug3%#?RN_34QgGThOh?WqDf5P|u_`28LjhCX-d_qN_3`JoZ__x?iv>S@OP}i? zS$TV|k!~#8DzT+tn{_Vd5aH>~d^>0tv9vaVn-S*spMCY2y(`J2qWyzFH+?;ZC_$uE z@y63GapsP9iI5XSs%P%xKZe$!1F_c$a`sIVVTlZI(K2;THPdr{HNNazz3BkkdRq!hkT?ZV`Wo zWKxOrU8?K?-r&j8L&nP_=8ZQpK8@g@k|GcpVz-E&r9_@lBDh7oi{!>yajX@hBs0z_ zX$nS#NJIKd(1IzSBh2>C`~o1$ksxu?vh-Bxi^0)Tc}OHjhOCkLlr;H93;@li$EzPJ z`AO#lNzX)5o-T5`JDTN45RLHX5pbzTqy#FDI===l!Sn zWeL>38}Lh8wEi%DvGWc81AZC)D!VtDhv1h1cysvW6Lz&?@XPxg5i;>h-U3bm{}+DQ zG@pFDmY^U5x^J_6$?#(F%WJRcm@9j7`{Kp+eKe6x|yt?01S^ zdP))slo8eQ<#xI>T#qE~D;g=@h9mOx*(MU4z zi`DaSK6zSL{ZZ)ez^dGMe$2l34v|m@JkB`!Q_{dHvDpggoN=+4G9V3mzAiyw{pVxrJZQi z;g>ZcuGdgP(a4}DZwbSq_@$D>d$T09%xE}*GJ;?32d96DU)qRpVf=E2goN=+O$jLx zzqFjo@=+_OypDLu#4ibkW#E?$sN}bD%21VtU%rx%Fn)PoLc;jvWeF(`zw8IK8-Dra zmJoiKE!qn3%fLC(G)lbZW(mqlI<&e{i3dSS@yoz49lICUUQtGl+CKfyAkHA>=1p9;FoEV#~Wu^OTsVR5if&K z7Jk|HB^1ZUF9U8CUD4h*{8HV|7&7U7{8AMK@$t)tvqahTl|VcbzbuB*A~1tnFoYQ1 z2WT2Tez{qR{8T7XMDWX%h!R~Iep!SxCE=F`nP2crGZHKwzl=j7!7tTm%=&Reva4DUE?=%)W8Eb?zVG__j;WR7k9?le7e8VIrr_p%^Pul;=c&73S8T5=>5{t?ZjjZnm-73trMu2^fHt$6a z?Djp{H#6`O@fZA%A>uE{@6fob@)PW}?DG=OSAnL2n#{H#M>IPx(ZgtAW`7S^4vHNq zdAI^MklDluuR6orwnaJQF|(h?L&uBmp%B=%Xoz2a!^ZP_;|21aF8nvxVlt0Wd{!j# zelbmn?SHV0pWd%hbP4IM;y;fc8q*MI86$m9JccU{Si>cM-0Oo_TZ_kuV_Y0QZ#qlv zJs#rYbz+!vnB4X}Q)D_!9tK(H8zJDVjR-57OIHXXSm7V14^a-9-)kS{u$DBy70Kz%0sWwLs`3A(uD|}GI+`dcd~^#o9V|=8<1~Ge zD(f<~5NvGVtmzu)6Y-*nw%;)UO;tW=!v_-F@8}H{y5BJha`=96U6gT4Fb?d0sZQ*d z6&x+G+`mXL4D)$Sp@Q}fsWwP?1!e51WWJIR!icmSsE~}kFChZ1R>_)ath|)5a{5kf z7Ee!8Z5T}FX^?4_wy<)#6bD5AdjsrmY?TU+oxmKa#Csz{et378g8Us!Pt9%xh5#XVeOTtbnEsHhaxttU=qJw>U|KpG6CK_yC`RCurGc15$22F-(JQGG&5 zR5U44z6_Nc6_QB!e!sQW+2@>l?~{u6$Ghk3VXd{-UVHELJA0DJ4qbltAIasG-;Dx2 zF?U;j*Aw#4|4e$zpJ!EMF2C!2qwhan07ABaYWpz)9Lfr5uO@z+;Wq$%_p(4pish{I zr$4@u>5o;i{BDZGv-ABNwICm^W?#eYV&8zINNLOOUV|N}lr4NIBg^lm-4L|U=~ki1 z{M9`mr@#De5J^Oq-%)PxI@?%_)^F3AI2Tc-<2Qt%R~xCUSBV$qsqwawoL)^MV0dGd zGzM=!ErKk+TLu~`{`Jp^lCzfIl_rf;V$*P%pmex8b;`y!jS`^om1hgW!hq27yN?(p z%kSm{IoZ^attwb$EWaDiL;?oxl2QqyW0)LdiF<5S-!+U)B`yqT+VZ;^h|q#GfO&?O z-%WlNS!g|x<#z`=h7FL@tY_v?s1;j&cNwxtaMSSeyUo`J)%l}nOeDQkx)3kl&lB{} z(?S`h2N?)Vs2)y_qiEWLPhfm1QN%2&YFmDnj|eSXM|4u*<#+ErV}*+>zv~oY+8%kW zc*{X9*Ydmi%C}m;H&}kx&u0)>ez$&@UtQn%Mb2M6lH_wPznjS_NF`ooE-hHF{I0Yz z2ra+6ONgsVZVt#dAo(22@A@e5-U0EP%kNrhvg3keTz=Od>+g1s|DJ~GZNFG!kQlXM ztKmPkq8#`S)@1k(ISv1zh_2_E2qNy~S{B~DHAi0e@^vKY6mWA<7eu0#qV`T`Sk)kxM4n; z>fgYFW!gZ^h6g!O)-n&*T;S_!%aZZJ;rNAXQq+fzVaAF2vWI`fdnHQVbYotH_VEtO z(jHR9anDFWaGriy_*)o>?||7y_ml0yc_ndYpCNqs@#E|@y?OEjKgGv~P1#3eQ2|u6#K{z{gPfx3sC6L;MS+WODBQeLZ!yXen2sS2G7T@oM=*BNtHw?iQPiGl%5pE z-fB~bI2^S>4@z1qC6tg(D#J7QF&AVZBY}wIG!up^46Iugg~U1{#2O47t03*n$Asp? z#>Zi;R!;V!_FCEJN@ZspyHY~MY-8C)sKHP%#Ox4=`KU4}WnvO-^@cPREf>%hm)cZE z28^lkqCq08_c?OO`{lqXNPgMmoa6ss4tzQ`9WM$pz;!pWyIy!2Sh<%wDUQC`(PXi% zkl8|psKa&wxD||Ql$Y+O??>=G>0K*D0Y`rF*^glkFMs$bQ)J@hO(+#dd%?@~IRfbh z!?B_z@l{GGhYyj`J~;4Tb(HuGq3D$g^L&C~hM?zbvXv^@ZIT+Ig*Ht+r75lw(t@q- z(U9{bL=c(o0f|vxKGwTR6P*si4(pvuE&?FVkXX8#ofrmpvkgK*_$!tt)CJugtfX40 zjH@4^0zz%%OWK5D`ma?DzdPO~_0# zA!zXh zuzL+3yT7JY&>n#L732~8UT3{%DRvY&rxNd86~e(|P1Fz$-YRysGaUSg(p&M6Dkqh= z6eJY~pO8Us%@kbFSekdW!0dQMOX;GS?c?p2rGLiCrS{lpEpbpj+98p=Gzo6Y zghYU!8`3dPc~2bcrg^i!D&ckA-$PF%)c9`r}^okZk;~>G$b5)?l_;LN%O0aV;V}&I0mrcI{CCc`-XYjzz z_HB?HDDkwzyM&ZXzY#w_2r44w8Pd&qLtq6e<<YfaPvf79`QL`H8Zeq0kiN`PE!hej=yACRJw<2Tn(l=l_L zLS(_ulaNBiZ>i#E;pghC?NnmwK$@;J;RVvj*r5$2eW>tbu^>z&+adZ;+cyxGWd$4z za^595y-y~Z9?)A59V5|cOeB^0n3Pi(^<(lVe!iKpslv#CkRoQTPnMzuaedv`LDu8aLrvtdE}$mu%i^q81EOpkXIkrt8QM?^OsDgGd;1 z-6~XdcwH*yEd`lK{bZu$HyNKwoXISz*mm04R&YhBDMgtLxwRjru{+G zOzf2dQJ8fcC88>9r+mM=%<=tzty6S$oX;SFmfvAgshqL_`EDdXUdU&B24H`Of)xe~ zE^!RLxL-;TLd*SyxT@?aNscKK=5)z{^7* zppTcgKpXCUxz9my)ae09`-8Uboqhb;p5?Y(ucQ_MVz>8uVBpF&dq^gZN7AGHmi*DRmR@S!PM~Z zOZVX=f`=bs$S$0(a-<406x1^Du+5iN(iCOnhkiz9rVZoaHRw+a4>!eN79ZQw@bEhL z+~ND>HlQ3Cc=%pn>@7BhhyziP{ZrEWT1qG(%~gi`@nbH<+l=(_FvArOPr(-ui1-L% z4G&L}p(=JFXlh@SzD+|CcMF#rLY%$&40FKmv%8og6Zma|X4&-%@Ea$igiMrvbSG2G zD0--J(EQ&1#=&9mH(57|jXu^71xr9CYewjL$>;r7KMBa z);ouS2-ce^S|}00daKQzRN7^dB7}rLVqIx%uTX`oLH$SF=<%BOQ@^CF>KO7tQ(qv; zs`_Y&_U^)uRdu}Z3N@hnEGLn$9TNB;GD;Ocpvd=JB;kAE0Db>$yj6LCgopJB>U;Y* zvKMpaA%V6}PO2IvQzG3_{rBU*#s9is_seaB2He+$9aM+FEA{E=jIUuBoblj(x%#LD z6!}7k1b=Mfg&{mUL-dK*VD)Do6^$SFI*<7_xG!_Zw}#j2d?LDw?QKO&B_04t#j^u5 z=ta&~Dc>N#r*^;G69|H#;uN^+52i1n__QlR1(O27R=4LWa=#pkQ4yud!lzS&ulEa! z=r033P^dYvb)e-@W{dELx!S(GW@S>7gbY@#zAI z=eV&^m^*yB4J1WM!>5b1OM;X=B@3jC;M2wD2gZ59SSRN-`@sFS<3R5qi3mQW+@N@! zv6epcIjxD|h%z02B@De5NaY&VKH3|cCpo=*BVhP+i{jJcwFrVww}XZ%c_M@ZjLX8O z&!rHaO6#g(@UTpt&^eX{KB)jn}sBb z62Yg#LQJ;h~U!(!hkL9p@96WxOX-;KK+j}Saq%| zSb$HDRR$q^`W}-<{-h;L|!vd|W_0CqCVDs}yoTkSxHb1${Pk88f#aZ+n{_ zoyII^)4k1@MQyru=LHi5DB|Z};LcOIh1`-&%1PU((+L%h^HjDe3T=R9)MnJI*iJSh zR$=>-&4~A)+^+L^gi3I4ePChkr3|gky$uBm_mYg{iiLCChZot5cy&3#omiud6~Q-a zGvZahGPpe)^;GO2d&Z7{*smKjocMJapOe*20{Y8wm`Y{%Bk=xl9%$L{IVz6{F}DwK z5?(XTQ8~xXQ5lS=yqxE#U{L&m>wDqI{^j{8T;Cf$KV@%Fg~ZjlNclq+K=&U$jz^rC zQkucf>hr%nKjmk^lbPqIbWq~E?fjH)9ctZh&0^lTj*r*%a41c6R88zzm`HoNb#N?E z=+c}!E&Px<{^HP-LZor$rrd_dPNVePl(^tlIX7kRDQJzw;MQy4Z?b-BJh#4L_I^X& zhu$gG8ppc@tLD0g0popOIJTN(Eo z-VA@+KQCo5=oGu(@Mv}3i&pZp^r&|W0?+Op)K(FgVx+u5e&|oUOPRtrv=90i!=cZi zQsQIJCPB>0F2k?j&`!`9a&o*$Rw?>4v}Ha%MyPkSa*Crcid|pQYbY}7(IPK`J6(kK z$#YSrr7|14Kl9K-E9?l*dTs|jTx6M|f`vB=jhaT+VZhfx+fYF_t+Yi_X)+HR>=+y> z`Ml{;Xq1+~V6BRpQc>i@lUgPgPd7LNNyb=upuhI*lO4DXF<$frw1DDtN1W}yOSZxe zJe=lVcmbpQ14M?LX*)qKWesvbNe-O?>Y~JsqBGJG; zNQ(_C!Wq^gDDY)Q1zSad+gUVs;!U5X;JZl%4nf#5-ikbWzbocbl=d5M#th z+fNAb=L?q``zYAxdOzqTr9Ep^E#HJ z1i^l{DIld_XGEBe?00LmR!0;rVIA8aMQopH&6&AYKcTa?udsI_jX%1bXwMwoYS?ql z^lR`Z1%>cjP#PUCtFJE11ckKoPe&=_6^~ly-bM&1Tb4MJLbpu3)G{nuD)C1*@o{j% zDl)8oq=JBtXH<=E;wRJet{p`Ui{b~17ahABLOs7?Ii1OR%A)PX`ed z<#`6C5-%bV7{m*QK!h~c*Zb?K|LQ!6>LWw`+uRY9vq^!dvd$O?2LJ6(9Rd2FX~Tc3 zvJ?NUt27d}=Py9jbs)>}5;$p-QC%*oBg^jIrm^>dmf3^FK8WP%5YDw2FXF$|)5Gva ze@9c!^5534Pz$G@_P9OM!Ux!MJv@7S-Ua`yLfC(Me-#Nk|7{6gi}BxXK-9nY-!jj? zD+j8+|91FF$fEw+ODK!)zkR3A|JHxYeg56WN_@BZZ|hj&GV5Ue8_w@rt~y2KU`uXi z_;T!B{|9sN&yR4sv_59;zwqU_Un}eUyZr(`?p7YrS&Sc-b^hJMDE=NeKcXZHmkiFo zv-2Z%&7Uiu%b&}?fz27J)${N0=KQ(4+3*nM{5e6sIRB2Vj{e*xcsag5SMEl3oyD9V zF&PQzc$|UXY=7>x;pF3OH%Y={_a*A4-Ki;Vlb)#Ll-dZBPI(nOq{ISdb+9p~i$hkz&hb@6xlOGhjIPAMt4bn7?} zm5%EOr9EFFI5a@~%Nb^V1r}~I**PGny=D3U4Jpu!<1M3eLz^O{xuI{XrcOaMw@=oD za~smsddcS<72+G~r`junFke%5fD1K6kDxo`C~4{8hIaHlf}&Zd8i>6BX>CliV<3w1 z2}YB_Ao*Ko8{hsIMwOZ)dN(p=dIJ+!JS%Y%_1k(tJoVeswKb%@P+=Xo<3L28IQDQ% z74gFSZ_Me7R2LVLY|^VJ8AG4+|Dbi~C;c(1-=9s-D(XRI4p$R9_{Q79)@?Xng?Q z;$zF;Kj&e1?bN8vWp#gK;nk=JIsXojgdM|3rS}e4ITw2Y`HBao=iku}dV^u`gLwX3 zXn$<7P8!mi|NQnzA^&-d2p{;*)2|ayXg*{emMMmJda_Qi=a|G9Pah)V;dzjz8H6TrTvy8}O6aT#jcp zbn#H>4t%Od;*R{9N};9vFf|fhq1I6aVZI4Z1U0sL#8zcesk|paH+=%^P9_8< z$b`VAcwt|)@afl50CwsBGf`;kC;GN7mp=Kno%G&>b@^pqk8|%zD3Qky9Bp$aslZ8B zJTRCcRp_0kLW;k?2HdTiiWfek?ciF;<8`&H_MJb4NNs&QWE_=L6Y(NgaBjr@5)r8G{V#RvM} zKI9R|M#8DY0L@9poO{R=94YdVLLg0N@={3CMH)ET;f6IYF^dxt>C2I#K)~8ThW(LY zSMkZZa z;i3+UL_H3ZaZ&joA^2ot1=v$6Hu@p<71{V?B7-^K4SZtH#3}>qxgPNepLYSD>=ni* zizkt=!zXFH7K2a5B5L>JlbWFF@X3Ra#qbHr;_!(+?;(7m#P=vZc_4&O8u|F76%5nx zNpOn9KgK7u0({bg$C2(TKAD2z?*V*rAq@T>;}fpe%lh7Y-&JhKFb}~ex8lv=li%37 z5S58feqs+md_oN1D(ic54H3cX4GJ<=hQ2KtKKb=ZMtN)H zhlANsOdG~0p9}_jaTE*p!!Qva+k-5DPnO_UzDOHBSu7gNz$e3mwfC0kLPpqMt`?r- z5ay4+`|EQEpHN?lPd z@1E|aFykADXCZAhq_#-oy*rRP2*HR~kkWLZyH{egm#9l~t>&F3YBU9`QKj65Fkb;R z^;uy=SM`qyEe~BQ&v&hgKGj)(QxPdJg2$)?>TodP%2uX={-SLGp_@@rx(;Z|^i8}A&EljTb$81B$htdl?>w-RZZVaWX5K&`{cdO1Qgcr z#1$um@I-T|x&Tj{1`%QT#o~$6jE?$FbwNt;#Cp-2(Gfgx=3OB?(UA&Bc~{>X!4s>H zgm{7&;y!zZGvM{I=X&Wod_3_<2u~CVuLz!)7T}4CAYtH*jhUt2jIX1$r4pBW>T4Eu zM26MXe-%7YN9cJ+;3u;c{CFwVA&Na!oZDDAkk7&s&nktrm-(sDWgZ|V|ACQ;8-@1QU-K3Ml&PhB;0Z%ps^?3u6`(RA^Xt2i( zw(kB~q)T6XLhCd8N;`ES;q>)ULZ)ADW&?SqYWnlC)Bn}{O*aVZ*58!H3-HlsFaZ5|1H$t+ zlR^70@Xe8TfLtB14i%fd&e z4P&t4qnJI{114JX9}Oo~dY;d_fR7^cH;sg!!$-~WS`0o~cKx2fM;C*tkB@F+!4w}= z#iNgpI_UGB!AI{yX<)P`@zJ8|a^a%`V3_{>MZ0zWW)hD(-Bo;40=nG;_^2%mK8%n4 z)_Rbqn&LzG;o!VC(}wZUOBaE?;-g&iH>KSC%{0+q20rR3ti6e*3mKjl_7|zHM3_H3 z{|Wvao`ds3Wf9e#2llnC%XpG?jI10_*tN~AsNiu&kNwNz*dO-SI z8Nm!6&AL#es}Pddd!Av@`J4Me&>)1(-;CCbp9pb^VKC}Sq%;U&^EYF`Gz&&G6NcU( z%PyLFT(#E`VZNq51s8KN{NDtidDO=a=Ix^Od)tfJ+~Ie+s7GQdeGcK+t~W~Q`r#gfH( z-2BZ52r!o$?@Od@{^kk^0be(N^SqSS>v6tnE64mz3&{gtdWWqwi8V%uL9Sf$H+H^d zaq~B&z|onVG#2fTH?J=e@Ve^WzvMetT={^oZ`==@eV zt?H*=g(sWdNc5o*gagtG8f3z5jXUI>{9 zzo6F96=A*!e+_ChVOZ{IOe&SP^ZA=C=TZQ6=?56`DBk)87V38nNpCB<3cu_jytN9! z(KdIh5c588#RG%wT8M{KNSVJm%ml{FnVY|PUGjM2ENgM|H)kPU1Pkz%&ENdYM(g9P zK}Sf15VQpIH^-26Fn?3YCzS&cl}FM1`J1~*IF)FmB;%R$H}64}l*m_5Fn{wdGWzp3 zU6sgJO+>Ej`I~7%B@5BjLN;v^PixMd%-;+}3c-u3#6+ay+1dO}0VxVndnL&5cjj+i z?HR%+7vTl?WVIMpoyPbH=5N@)0H2iK$@;Q&v>d@F*Ysj%#6K9%2)qRNq#Y8usP7|D zXMu%_x-=5?9qQRd4Fw6oCp&b1z*Fb4ugJnD&3Z9dFDr`KGrEx2w>>qS^Ez|*ybJiG zTzLMbr0{e2gs;WmlTX1m?_ci^$Xs7`38?z`WGxGz_+%m;eS9)SpZ5$tX{*HdBtE(O zoDe>7>&tG0MeaU)QazZzx#UJPqg}-(e?Yc9fKMKU!H4llqb_~s7i*fC`vuD8n!j0m zCYv+NL-5Ibyg7W5kS3muPnxjR5ufzNcY1&R=BcwdHWhSepM0$tAtI@&m#$ zex4&?8^F^aU2o85>==+`__BWNN6N%uR_3ZOy5nPDiS+0AJ_TkE_7EE1i`>$S;DQ)E zq3&f(F$`R^M@m1eApBQ zJj~M_+yinRWXu2#PE2;8-ii)_-k_3Sk zbllTtfVP0dcu|3}X-sMSOL2~2CUK4ql~{g*t;aC<1T{7Na;Vbx&oyMBgs6WmA75jY zgts@f8$}3#lE;zK>S~bI>N~7Go`N2%Xunu9KP|<#y82p5;0;HZZ*=ALS-(g>p+-E! z^3YS`ZHoFGdJw+wqa3XfDX8Q~yj$I&;@ou51qWGWwGsiuInWJAt&u&Jh6o1MDr+gf zJcGsa>KRk1nRggwNcRVP(skce>(oaT84mcpVF(Az5+wyVV3v?89tSLe4g(zU1V||k zxGqdba6o>y5DpkinN!}@Zu#l*nh#+ROFB*nfn6C(KX4rC|S=cvZp|i?s#g@Fu5R5te zPuK+vI{fBe^cHNK?(THjy37iUB4u0$r6~rlNKZgiFdy(2=Pkuf z6L+=Nr}%z81`@gRiTk2SjGA2|^SmYYLwep)vMZIA54|n{4d+Y#2_o+0OT+}8>IA6E zMYTk_AZiM@xu{u@TrI-67T^V++ITMUWc5{hodV|pM%I;Pt@qQEM-ZRO!5{soi$3$) z`6GPZ#q*YedqI$~K#2S2EuDk6V$NIIaVp)@-F`pKP>}V{Te^*f(*ud? zQ8p`{w=@9DXYBmpx~H&rgeO`F?Z3^bc!`|1bRC2Oa zWAQkprdYptMm%pA!gmpo%#PKNQnHe>iEm z;F3;F!>lCD-#??QJDWGtj2#q;Vev2?oLWEh;Tb_mh+SMx;O z-XP55Q3!*TJd+jGtIDp^<(OQIAQKDgN{Ft#I9 zWmotrV~?Wt<6Vs?Gq#Ue@}$=csVw9KW{?Vb7u3^S`YBsCrsB=6m-6-#qT=%NdZ`AW zCpKs2FKtC#;2kj|I+A?m`AggPr2)$Mz>r)tp1*q1N8 za4o+qkJ`^S1skA56|o zAO7jiU)q}_B2Aofqug7ZkdWhWt%+@jG98~I(cYW*aZUUVwd4P3)HEYt-}Q$`r1u6$ zpa^pQ(hW$VO5R_^&pLmpI;4XM-m?!)P@4D=LWWK3EYe34Ybr1bCLTH;7%f(fw_lKx zXL%#rOYKb$e&?M^G-D#E%*T+?7|mhw==n=GGd7hd8PK%zmtKSTT99|pp@h$0Y6ouF z=L5f2!)JK3Ns9A<&&Lu;JAcXBDnUUWwy%rgD30vUD|9$l&~?o!+O@9Rm92122I#My;^p zmR@D6nO!y$uRf0^pm=p@8x&3OYGdScJxyoSrh7Sr`gLz09@hBng z+0VSIgj$_m9G%itVk>dV$Wr zI3JjEvf1~kKGkwJ;ngpMeCT{&?9Q*!ehlsg&}&prfc0b@3;YH$<%X&45zzuC;l>N~ zd?md%r-sa%oJhamkN#*7x#vyRj8cC_@M!@G7{#YW?87o{$GHk&ys#j+9p^lT7@f@| z&?awY`VhFj=sX6&j18Zb+hu$TaBg-N!ly5uz+S|AT7KYX`1rI6w3P#&Ruxy;E6HXg z_u~L#8a}T8}$ERRF2 z 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�e;-jX&a-d`|7m^ISQglbhMJyoy_y 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

    P4n-lkzNt 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 s#U2JrDGI9{&%J_|mk_&wlN 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 literal 0 HcmV?d00001 diff --git a/src/detector.c b/src/detector.c index 3004166..86d918b 100644 --- a/src/detector.c +++ b/src/detector.c @@ -37,8 +37,8 @@ const char *magic_parse(char *line) { size_t length; for (p = line; p < eol; p++) *p = tolower(*p); - p = strstr(line, "script text"); - if (p && p == line) { // /^script text(?: executable)? for \w/ + p = strstr(line, "script text"); // Example: "script text executable for perl -w," + if (p && p == line) { p = strstr(line, "for "); if (p) { p += 4; @@ -50,7 +50,10 @@ const char *magic_parse(char *line) { struct LanguageMap *rl = ohcount_hash_language_from_name(buf, length); if (rl) return(rl->name); } - } else if (p) { // /(\w+)(?: -\w+)* script text/ + } + + p = strstr(line, "script"); // Example: "PHP script, ASCII text" + if (p) { do { p--; pe = p; diff --git a/src/sourcefile.c b/src/sourcefile.c index 2f23cd4..27a7327 100644 --- a/src/sourcefile.c +++ b/src/sourcefile.c @@ -375,7 +375,8 @@ void ohcount_sourcefile_list_add_directory(SourceFileList *list, char *f_p = filepath + strlen(directory) + 1; struct dirent *file; - DIR *d = opendir(directory); + DIR *d = NULL; + d = opendir(directory); if (d) { while ((file = readdir(d))) { struct stat st; diff --git a/test/src_dir/perl.cgi b/test/src_dir/html.cgi similarity index 100% rename from test/src_dir/perl.cgi rename to test/src_dir/html.cgi diff --git a/test/unit/ruby/source_file_test.rb b/test/unit/ruby/source_file_test.rb index 807b614..83a1af1 100644 --- a/test/unit/ruby/source_file_test.rb +++ b/test/unit/ruby/source_file_test.rb @@ -1,12 +1,12 @@ require 'test/unit' -require File.dirname(__FILE__) + '/../../../ruby/gestalt' +require_relative '../../../ruby/gestalt' class SourceFileTest < Test::Unit::TestCase def test_diff - c = File.open(File.dirname(__FILE__) + "/../../src_dir/optimer").read - new = Ohcount::SourceFile.new("optimer", :contents => c, :filenames => nil, :filenames => ["optimer"]) + optimer = File.open(File.dirname(__FILE__) + "/../../src_dir/optimer").read + new = Ohcount::SourceFile.new("optimer", :contents => optimer, :filenames => nil, :filenames => ["optimer"]) old = Ohcount::SourceFile.new("optimer", :contents => "", :filenames => ["optimer"]) - assert_equal c, new.contents + assert_equal optimer, new.contents deltas = old.diff(new).loc_deltas assert_not_nil deltas assert_equal "shell", deltas.first.language diff --git a/test/unit/sourcefile_test.h b/test/unit/sourcefile_test.h index 1e6241a..f780675 100644 --- a/test/unit/sourcefile_test.h +++ b/test/unit/sourcefile_test.h @@ -203,7 +203,7 @@ void test_sourcefile_calc_diff() { void test_sourcefile_list_language_facts() { SourceFileList *sfl = ohcount_sourcefile_list_new(); - ohcount_sourcefile_list_add_directory(sfl, "../gestalt_files/win32_enough/"); + ohcount_sourcefile_list_add_directory(sfl, "../gestalt_files/win32_enough"); LocList *list = ohcount_sourcefile_list_analyze_languages(sfl); assert(ohcount_loc_list_filecount(list) == 2); Loc *loc = ohcount_loc_list_get_loc(list, "c"); From 68f0d0cee24419c692842395f664f47225b35d1b Mon Sep 17 00:00:00 2001 From: Peter Degen-Portnoy Date: Thu, 14 Aug 2014 15:42:23 +0000 Subject: [PATCH 380/387] Update README for compatibility with Ubuntu 14.04 --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b48ac45..45ed563 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Overview Ohcount is a library for counting lines of source code. It was originally developed at Ohloh, and is used to generate -the reports at www.ohloh.net. +the reports at www.openhub.net. Ohcount supports multiple languages within a single file: for example, a complex HTML document might include regions of both CSS and JavaScript. @@ -45,7 +45,7 @@ language detection features from a Ruby application. System Requirements ------------------- -Ohcount is supported on Mac OS X 10.4 and 10.5 and Ubuntu 10.04 LTS. Other Linux +Ohcount is supported on Ubuntu 12.04 LTS. Other Linux environments should also work, but your mileage may vary. Ohcount does not support Windows. @@ -63,7 +63,7 @@ Ohcount source code is available as a Git repository: Building Ohcount ---------------- -You will need ragel 6.3 or higher, bash, pcre, magic, gcc (version 4.1.2 or greater) +You will need ragel 6.8 or higher, bash, pcre, magic, gcc (version 4.8.2 or greater) and SWIG (2.0.11). Once you have them, go to the top directory of ohcount and run ``` From acc63f4b9e3b8a25aced701f880242a2d8bb13d6 Mon Sep 17 00:00:00 2001 From: Alex Johnson Date: Tue, 20 Jun 2017 16:38:54 +0530 Subject: [PATCH 381/387] Fix incorrect comment pattern for objective_c detection Objective_c comments always start with a /. The existing code matches the * character in the second column of a line to decide that a file is objective_c. This leads it to detect mathematica comments "(*" as objective_c comments. --- src/detector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detector.c b/src/detector.c index 86d918b..1c9847f 100644 --- a/src/detector.c +++ b/src/detector.c @@ -694,7 +694,7 @@ const char *disambiguate_m(SourceFile *sourcefile) { matlab_score++; octave_syntax_detected = 1; } - } else if (*p == '/' && *(p + 1) == '/' || *(p + 1) == '*') { + } else if (*p == '/' && *(p + 1) == '/' || *p == '/' && *(p + 1) == '*') { objective_c_score++; // Objective C comment } else if (*p == '+' || *p == '-') { // Objective C method signature objective_c_score++; From 56cfdf6c10aa67904c1fb82ce5ea753f48a767cf Mon Sep 17 00:00:00 2001 From: Alex Johnson Date: Wed, 21 Jun 2017 15:22:05 +0530 Subject: [PATCH 382/387] OTWO-3077 Expand Grace lang test cases --- test/detect_files/grace1.grace | 7 ++++++ test/detect_files/grace2.grc | 2 ++ test/expected_dir/grace.grace | 48 ++++++++++++++++++++++++++++++++++++++++-- test/src_dir/grace.grace | 46 +++++++++++++++++++++++++++++++++++++++- test/unit/detector_test.h | 3 ++- 5 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 test/detect_files/grace1.grace create mode 100644 test/detect_files/grace2.grc diff --git a/test/detect_files/grace1.grace b/test/detect_files/grace1.grace new file mode 100644 index 0000000..ecef509 --- /dev/null +++ b/test/detect_files/grace1.grace @@ -0,0 +1,7 @@ +// Sample Grace code + +import "parsers-test" as parsers + +class exports { + def program = rule {codeSequence ~ rep(ws) ~ end} +} diff --git a/test/detect_files/grace2.grc b/test/detect_files/grace2.grc new file mode 100644 index 0000000..0d500ff --- /dev/null +++ b/test/detect_files/grace2.grc @@ -0,0 +1,2 @@ +// Sample Grace code +print "OK" diff --git a/test/expected_dir/grace.grace b/test/expected_dir/grace.grace index bdff20b..2cc0a16 100644 --- a/test/expected_dir/grace.grace +++ b/test/expected_dir/grace.grace @@ -1,2 +1,46 @@ -grace lcomment // Sample Grace code -grace lcode print "OK" +grace comment ////////////////////////////////////////////////// +grace comment // Sample Grace code +grace blank +grace code import "parsers-test" as parsers +grace blank +grace code class exports { +grace code inherit parsers.exports +grace comment //BEGINGRAMMAR +grace comment // top level +grace code def program = rule {codeSequence ~ rep(ws) ~ end} +grace code def codeSequence = rule { repdel((declaration | statement | empty), semicolon) } +grace code def hashLine = rule { (symbol "#") ~ rep(anyChar | space) ~ (newLine | end) } +grace blank +grace comment // def comment = +grace blank +grace comment //def oldClassDeclaration = rule { classId ~ identifier ~ lBrace ~ +grace comment // opt(genericFormals ~ blockFormals ~ arrow) ~ codeSequence ~ rBrace } +grace blank +grace code def typeOpExpression = rule { rep1sep(basicTypeExpression, typeOp) } +grace blank +grace code def typeOpExpression = rule { +grace code var otherOperator +grace code basicTypeExpression ~ opt(ws) ~ +grace code opt( guard(typeOp, { s -> otherOperator:= s; +grace code true }) ~ rep1sep(basicTypeExpression ~ opt(ws), +grace code guard(typeOp, { s -> s == otherOperator }) +grace code ) +grace code ) +grace code } +grace blank +grace comment // "literals" +grace code def literal = rule { stringLiteral | selfLiteral | blockLiteral | numberLiteral | objectLiteral | lineupLiteral | typeLiteral } +grace blank +grace comment // terminals +grace code def backslash = token "\\" // doesn't belong here, doesn't work if left below! +grace blank +grace code def colon = rule {both(symbol ":", not(assign))} +grace code def newLine = symbol "\n" +grace code def lParen = symbol "(" +grace code def rParen = symbol ")" +grace blank +grace code def reservedOp = rule {assign | equals | dot | arrow | colon | semicolon} // this is not quite right +grace blank +grace comment //ENDGRAMMAR +grace code } +grace blank diff --git a/test/src_dir/grace.grace b/test/src_dir/grace.grace index 0d500ff..3343b9a 100644 --- a/test/src_dir/grace.grace +++ b/test/src_dir/grace.grace @@ -1,2 +1,46 @@ +////////////////////////////////////////////////// // Sample Grace code -print "OK" + +import "parsers-test" as parsers + +class exports { + inherit parsers.exports + //BEGINGRAMMAR + // top level + def program = rule {codeSequence ~ rep(ws) ~ end} + def codeSequence = rule { repdel((declaration | statement | empty), semicolon) } + def hashLine = rule { (symbol "#") ~ rep(anyChar | space) ~ (newLine | end) } + + // def comment = + + //def oldClassDeclaration = rule { classId ~ identifier ~ lBrace ~ + // opt(genericFormals ~ blockFormals ~ arrow) ~ codeSequence ~ rBrace } + + def typeOpExpression = rule { rep1sep(basicTypeExpression, typeOp) } + + def typeOpExpression = rule { + var otherOperator + basicTypeExpression ~ opt(ws) ~ + opt( guard(typeOp, { s -> otherOperator:= s; + true }) ~ rep1sep(basicTypeExpression ~ opt(ws), + guard(typeOp, { s -> s == otherOperator }) + ) + ) + } + + // "literals" + def literal = rule { stringLiteral | selfLiteral | blockLiteral | numberLiteral | objectLiteral | lineupLiteral | typeLiteral } + + // terminals + def backslash = token "\\" // doesn't belong here, doesn't work if left below! + + def colon = rule {both(symbol ":", not(assign))} + def newLine = symbol "\n" + def lParen = symbol "(" + def rParen = symbol ")" + + def reservedOp = rule {assign | equals | dot | arrow | colon | semicolon} // this is not quite right + + //ENDGRAMMAR +} + diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index 02c7254..3915d7c 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -145,7 +145,8 @@ void test_detector_detect_polyglot() { ASSERT_DETECT(LANG_FORTH, "forth.4th"); ASSERT_DETECT(LANG_FORTH, "forth.fr"); ASSERT_DETECT(LANG_FSHARP, "fs1.fs"); - ASSERT_DETECT(LANG_GRACE, "grace.grace"); + ASSERT_DETECT(LANG_GRACE, "grace1.grace"); + ASSERT_DETECT(LANG_GRACE, "grace2.grc"); ASSERT_DETECT(LANG_AUTOCONF, "m4.m4"); ASSERT_DETECT(LANG_NSIS, "foo.nsi"); ASSERT_DETECT(LANG_NSIS, "foo.nsh"); From 40ee6d1f89ecd9bd370a5310cfc7bb50a2b81910 Mon Sep 17 00:00:00 2001 From: Alex Johnson Date: Wed, 28 Jun 2017 17:32:16 +0530 Subject: [PATCH 383/387] OTWO-3061 Fix mathematica comment parsing The original code in PR#23 did not consider multiline comments. We compared and copied the code from OCaml parser which has a similar comment structure and it worked. The existing test files in test/expected_dir & test/src_dir needed fixing for some mismatch in whitespace characters and expected lines. --- src/parsers/mathematica.rl | 36 +- test/expected_dir/mathematica1.m | 118 ++- test/src_dir/mathematica1.m | 1480 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 1564 insertions(+), 70 deletions(-) create mode 100644 test/src_dir/mathematica1.m diff --git a/src/parsers/mathematica.rl b/src/parsers/mathematica.rl index dcf142e..72b5957 100644 --- a/src/parsers/mathematica.rl +++ b/src/parsers/mathematica.rl @@ -44,14 +44,24 @@ enum { } } - mathematica_comment = - '(*' @comment ( - newline %{ entity = INTERNAL_NL; } %mathematica_ccallback - | - ws - | - (nonnewline - ws) @code - )* :>> '*)'; + action mathematica_comment_nc_res { nest_count = 0; } + action mathematica_comment_nc_inc { nest_count++; } + action mathematica_comment_nc_dec { nest_count--; } + + mathematica_nested_block_comment = + '(*' >mathematica_comment_nc_res @comment ( + newline %{ entity = INTERNAL_NL; } %mathematica_ccallback + | + ws + | + '(*' @mathematica_comment_nc_inc @comment + | + '*)' @mathematica_comment_nc_dec @comment + | + (nonnewline - ws) @comment + )* :>> ('*)' when { nest_count == 0 }) @comment; + + mathematica_comment = mathematica_nested_block_comment; mathematica_string = '"' @code ([^"]) '"'; @@ -70,7 +80,13 @@ enum { userdata); } - mathematica_comment_entity = '(*' any* :>> '*)'; + mathematica_comment_entity = '(*' >mathematica_comment_nc_res ( + '(*' @mathematica_comment_nc_inc + | + '*)' @mathematica_comment_nc_dec + | + any + )* :>> ('*)' when { nest_count == 0 }); mathematica_entity := |* space+ ${ entity = MATHEMATICA_SPACE; } => mathematica_ecallback; @@ -100,6 +116,8 @@ void parse_mathematica(char *buffer, int length, int count, ) { init + int nest_count = 0; + %% write init; cs = (count) ? mathematica_en_mathematica_line : mathematica_en_mathematica_entity; %% write exec; diff --git a/test/expected_dir/mathematica1.m b/test/expected_dir/mathematica1.m index b48ed57..43fcb2a 100644 --- a/test/expected_dir/mathematica1.m +++ b/test/expected_dir/mathematica1.m @@ -42,7 +42,7 @@ mathematica comment (*********************************************************** mathematica code (-1)^(fdOrder/2) * mathematica code spacing[i]^(fdOrder+1) / 2^(fdOrder+2) * mathematica code StandardCenteredDifferenceOperator[fdOrder+2,fdOrder/2+1,i], -mathematica blank +mathematica blank mathematica comment (* PD: These come from my mathematica notebook mathematica comment "Upwind-Kranc-Convert.nb" that converts upwinding finite mathematica comment differencing operators generated by @@ -294,16 +294,16 @@ mathematica comment (*********************************************************** mathematica code g[la,lb] -> admg[la,lb], mathematica code detg -> detgExpr, mathematica code gu[ua,ub] -> 1/detg detgExpr MatrixInverse [g[ua,ub]], -mathematica code +mathematica blank mathematica code phi -> IfThen[conformalMethod==CMW, detg^(-1/6), Log[detg]/12], mathematica code em4phi -> IfThen[conformalMethod==CMW, phi^2, Exp[-4 phi]], mathematica code gt[la,lb] -> em4phi g[la,lb], -mathematica code +mathematica blank mathematica code trK -> gu[ua,ub] admK[la,lb], mathematica code At[la,lb] -> em4phi (admK[la,lb] - (1/3) g[la,lb] trK), -mathematica code +mathematica blank mathematica code alpha -> admalpha, -mathematica code +mathematica blank mathematica code beta[ua] -> admbeta[ua], mathematica blank mathematica code IfCCZ4[Theta -> 0] @@ -330,13 +330,13 @@ mathematica comment (* Synchronise after this routine, so that the refinement mathematica code Equations -> mathematica code { mathematica code dir[ua] -> Sign[beta[ua]], -mathematica code +mathematica blank mathematica code detgt -> 1 (* detgtExpr *), mathematica code gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], mathematica code Gt[ua,lb,lc] -> 1/2 gtu[ua,ud] mathematica code (PD[gt[lb,ld],lc] + PD[gt[lc,ld],lb] - PD[gt[lb,lc],ld]), mathematica code Xt[ua] -> gtu[ub,uc] Gt[ua,lb,lc], -mathematica code +mathematica blank mathematica comment (* mathematica comment A -> - admdtalpha / (harmonicF alpha^harmonicN) (LapseAdvectionCoeff - 1), mathematica comment *) @@ -347,9 +347,9 @@ mathematica comment (* If LapseACoeff=0, then A is not evolved, in the sense mathematica code (+ admdtalpha mathematica code - LapseAdvectionCoeff Upwind[beta[ua], alpha, la]), mathematica code 0], -mathematica code +mathematica blank mathematica code theta -> thetaExpr, -mathematica code +mathematica blank mathematica comment (* If ShiftBCoeff=0 or theta ShiftGammaCoeff=0, then B^i is not mathematica comment evolved, in the sense that it does not influence the time mathematica comment evolution of other variables. *) @@ -413,14 +413,14 @@ mathematica comment (*********************************************************** mathematica code Equations -> mathematica code { mathematica code dir[ua] -> Sign[beta[ua]], -mathematica code +mathematica blank mathematica code detgt -> 1 (* detgtExpr *), mathematica comment (* This leads to simpler code... *) mathematica code gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], -mathematica code +mathematica blank mathematica code eta -> etaExpr, mathematica code theta -> thetaExpr, -mathematica code +mathematica blank mathematica comment (* see RHS *) mathematica comment (* mathematica comment admdtalpha -> - harmonicF alpha^harmonicN @@ -438,7 +438,7 @@ mathematica code (- 2 alpha PD[phi,lj] mathematica code + 2 phi PD[alpha,lj] mathematica code + gtu[uk,ul] phi alpha mathematica code (PD[gt[lk,ll],lj] - 2 PD[gt[lj,lk],ll])), -mathematica code (* else *) +mathematica comment (* else *) mathematica code + theta ShiftGammaCoeff mathematica code (+ ShiftBCoeff B[ua] mathematica code + (1 - ShiftBCoeff) @@ -459,10 +459,10 @@ mathematica code (Xt[ua] - eta BetaDriver beta[ mathematica code detgt -> 1 (* detgtExpr *), mathematica comment (* This leads to simpler code... *) mathematica code gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], -mathematica code +mathematica blank mathematica code eta -> etaExpr, mathematica code theta -> thetaExpr, -mathematica code +mathematica blank mathematica comment (* see RHS, but omit derivatives near the boundary *) mathematica comment (* mathematica comment admdtalpha -> - harmonicF alpha^harmonicN @@ -474,7 +474,7 @@ mathematica code (+ LapseACoeff A mathematica code (trK - IfCCZ4[2 Theta, 0]))), mathematica code admdtbeta[ua] -> IfThen[harmonicShift, mathematica code 0, -mathematica code (* else *) +mathematica comment (* else *) mathematica code + theta ShiftGammaCoeff mathematica code (+ ShiftBCoeff B[ua] mathematica code + (1 - ShiftBCoeff) @@ -494,10 +494,10 @@ mathematica code (Xt[ua] - eta BetaDriver beta[ mathematica code detgt -> 1 (* detgtExpr *), mathematica comment (* This leads to simpler code... *) mathematica code gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], -mathematica code +mathematica blank mathematica code eta -> etaExpr, mathematica code theta -> thetaExpr, -mathematica code +mathematica blank mathematica comment (* see RHS, but omit derivatives everywhere (which is wrong, but mathematica comment faster, since it does not require synchronisation or boundary mathematica comment conditions) *) @@ -511,7 +511,7 @@ mathematica code (+ LapseACoeff A mathematica code (trK - IfCCZ4[2 Theta, 0]))), mathematica code admdtbeta[ua] -> IfThen[harmonicShift, mathematica code 0, -mathematica code (* else *) +mathematica comment (* else *) mathematica code + theta ShiftGammaCoeff mathematica code (+ ShiftBCoeff B[ua] mathematica code + (1 - ShiftBCoeff) @@ -547,16 +547,16 @@ mathematica comment (* Synchronise the RHS grid functions after this routine, mathematica code Equations -> mathematica code { mathematica code dir[ua] -> Sign[beta[ua]], -mathematica code +mathematica blank mathematica code detgt -> 1 (* detgtExpr *), -mathematica code +mathematica blank mathematica comment (* This leads to simpler code... *) mathematica code gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], mathematica code Gtl[la,lb,lc] -> 1/2 mathematica code (PD[gt[lb,la],lc] + PD[gt[lc,la],lb] - PD[gt[lb,lc],la]), mathematica code Gtlu[la,lb,uc] -> gtu[uc,ud] Gtl[la,lb,ld], mathematica code Gt[ua,lb,lc] -> gtu[ua,ud] Gtl[ld,lb,lc], -mathematica code +mathematica blank mathematica comment (* The conformal connection functions calculated from the conformal metric, mathematica comment used instead of Xt where no derivatives of Xt are taken *) mathematica code Xtn[ui] -> gtu[uj,uk] Gt[ui,lj,lk], @@ -594,36 +594,36 @@ mathematica comment (* PRD 62, 044034 (2000), eqn. (15) *) mathematica code - 2 gt[li,lj] gtu[ul,un] cdphi2[ll,ln] mathematica code + 4 cdphi[li] cdphi[lj] mathematica code - 4 gt[li,lj] gtu[ul,un] cdphi[ln] cdphi[ll], -mathematica code +mathematica blank mathematica code Atm[ua,lb] -> gtu[ua,uc] At[lc,lb], mathematica code Atu[ua,ub] -> Atm[ua,lc] gtu[ub,uc], -mathematica code +mathematica blank mathematica code R[la,lb] -> Rt[la,lb] + Rphi[la,lb], mathematica code IfCCZ4[ mathematica code R[la,lb] -> R[la,lb] + (2/phi) (+ g[la,lc] Z[uc] PD[phi,lb] mathematica code + g[lb,lc] Z[uc] PD[phi,la] - g[la,lb] Z[uc] PD[phi,lc]) mathematica code + e4phi Z[uc] PD[gt[la,lb],lc] mathematica code ], -mathematica code +mathematica blank mathematica comment (* Matter terms *) -mathematica blank +mathematica blank mathematica comment (* rho = n^a n^b T_ab *) mathematica code rho -> addMatter mathematica code (1/alpha^2 (T00 - 2 beta[ui] T0[li] + beta[ui] beta[uj] T[li,lj])), -mathematica code +mathematica blank mathematica comment (* S_i = -p^a_i n^b T_ab, where p^a_i = delta^a_i + n^a n_i *) mathematica code S[li] -> addMatter (-1/alpha (T0[li] - beta[uj] T[li,lj])), -mathematica code +mathematica blank mathematica comment (* trS = gamma^ij T_ij *) mathematica code trS -> addMatter (em4phi gtu[ui,uj] T[li,lj]), -mathematica code +mathematica blank mathematica comment (* RHS terms *) -mathematica code +mathematica blank mathematica comment (* PRD 62, 044034 (2000), eqn. (10) *) mathematica comment (* PRD 67 084023 (2003), eqn. (16) and (23) *) mathematica code dot[phi] -> IfThen[conformalMethod==CMW, 1/3 phi, -1/6] mathematica code (alpha trK - PD[beta[ua],la]), -mathematica code +mathematica blank mathematica comment (* PRD 62, 044034 (2000), eqn. (9) *) mathematica comment (* gr-qc:1106.2254 (2011), eqn. (14) *) mathematica comment (* removing trA from Aij ensures that detg = 1 *) @@ -700,17 +700,14 @@ mathematica comment (* Adding Z terms in the Ricci and Theta terms *) mathematica comment (* Equation (4.23) in Baumgarte & Shapiro (Phys. Rept. 376 (2003) 41-131) *) mathematica code + addMatter (- em4phi alpha 8 Pi mathematica code (T[la,lb] - (1/3) g[la,lb] trS)), -mathematica code +mathematica blank mathematica comment (* dot[alpha] -> - harmonicF alpha^harmonicN trK, *) mathematica comment (* dot[alpha] -> - harmonicF alpha^harmonicN A + Lie[alpha, beta], *) mathematica comment (* mathematica comment dot[alpha] -> - harmonicF alpha^harmonicN ( mathematica comment (1 - LapseAdvectionCoeff) A + LapseAdvectionCoeff trK) mathematica comment + LapseAdvectionCoeff beta[ua] PDu[alpha,la], -mathematica blank -mathematica blank mathematica comment dot[A] -> (1 - LapseAdvectionCoeff) (dottrK - AlphaDriver A), -mathematica blank mathematica comment *) mathematica code dot[alpha] -> - harmonicF alpha^harmonicN mathematica code (+ LapseACoeff A @@ -721,10 +718,10 @@ mathematica code (+ trK - IfCCZ4[2 Theta, 0] mathematica code dot[A] -> + (LapseACoeff mathematica code (+ dottrK - IfCCZ4[2 dotTheta, 0] mathematica code - AlphaDriver A)), -mathematica code +mathematica blank mathematica code eta -> etaExpr, mathematica code theta -> thetaExpr, -mathematica code +mathematica blank mathematica comment (* dot[beta[ua]] -> eta Xt[ua], *) mathematica comment (* dot[beta[ua]] -> ShiftGammaCoeff alpha^ShiftAlphaPower B[ua], *) mathematica code dot[beta[ua]] -> IfThen[harmonicShift, @@ -939,20 +936,20 @@ mathematica comment (* Initialise the RHS variables in analysis in case they are mathematica code Equations -> mathematica code { mathematica code dir[ua] -> Sign[normal[ua]], -mathematica code +mathematica blank mathematica code detgt -> 1 (* detgtExpr *), mathematica code gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], mathematica code em4phi -> IfThen[conformalMethod==CMW, phi^2, Exp[-4 phi]], mathematica code gu[ua,ub] -> em4phi gtu[ua,ub], -mathematica code +mathematica blank mathematica code nn[la] -> Euc[la,lb] normal[ub], mathematica code nu[ua] -> gu[ua,ub] nn[lb], mathematica code nlen2 -> nu[ua] nn[la], mathematica code nlen -> Sqrt[nlen2], mathematica code su[ua] -> nu[ua] / nlen, -mathematica code +mathematica blank mathematica code vg -> Sqrt[harmonicF], -mathematica code +mathematica blank mathematica code dot[phi] -> - vg su[uc] PDo[phi ,lc], mathematica code dot[gt[la,lb]] -> - su[uc] PDo[gt[la,lb],lc], mathematica code dot[trK] -> - vg su[uc] PDo[trK ,lc], @@ -986,11 +983,11 @@ mathematica comment which is not always the case (since we don't enforce mathematica comment the other hand, this may not be so important... *) mathematica code detgt -> 1 (* detgtExpr *), mathematica code gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], -mathematica code +mathematica blank mathematica code trAt -> gtu[ua,ub] At[la,lb], -mathematica code +mathematica blank mathematica code At[la,lb] -> At[la,lb] - (1/3) gt[la,lb] trAt, -mathematica code +mathematica blank mathematica code alpha -> Max[alpha, MinimumLapse] mathematica code } mathematica code }; @@ -1041,14 +1038,14 @@ mathematica comment (*********************************************************** mathematica code { mathematica code detgt -> 1 (* detgtExpr *), mathematica code ddetgt[la] -> 0 (* ddetgtExpr[la] *), -mathematica code +mathematica blank mathematica comment (* This leads to simpler code... *) mathematica code gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], mathematica code Gtl[la,lb,lc] -> 1/2 mathematica code (PD[gt[lb,la],lc] + PD[gt[lc,la],lb] - PD[gt[lb,lc],la]), mathematica code Gtlu[la,lb,uc] -> gtu[uc,ud] Gtl[la,lb,ld], mathematica code Gt[ua,lb,lc] -> gtu[ua,ud] Gtl[ld,lb,lc], -mathematica code +mathematica blank mathematica comment (* The conformal connection functions calculated from the conformal metric, mathematica comment used instead of Xt where no derivatives of Xt are taken *) mathematica code Xtn[ui] -> gtu[uj,uk] Gt[ui,lj,lk], @@ -1063,7 +1060,7 @@ mathematica comment (* The Z quantities *) mathematica code IfCCZ4[ mathematica code Z[ud] -> (1/2) gu[ua,ud] (- PD[gt[la,lb],lc] gtu[ub,uc] + gt[la,lc] Xt[uc]) mathematica code ], -mathematica code +mathematica blank mathematica comment (* PRD 62, 044034 (2000), eqn. (18) *) mathematica code Rt[li,lj] -> - (1/2) gtu[ul,um] PD[gt[li,lj],ll,lm] mathematica code + (1/2) gt[lk,li] PD[Xt[uk],lj] @@ -1106,14 +1103,14 @@ mathematica comment (* PRD 62, 044034 (2000), eqn. (15) *) mathematica code - 2 gt[li,lj] gtu[ul,un] cdphi2[ll,ln] mathematica code + 4 cdphi[li] cdphi[lj] mathematica code - 4 gt[li,lj] gtu[ul,un] cdphi[ln] cdphi[ll], -mathematica code +mathematica blank mathematica comment (* ddetg[la] -> PD[e4phi detg,la], *) mathematica code ddetg[la] -> e4phi ddetgt[la] + 4 detgt e4phi PD[phi,la], mathematica comment (* TODO: check this equation, maybe simplify it by omitting ddetg *) mathematica code G[ua,lb,lc] -> Gt[ua,lb,lc] mathematica code + 1/(2 detg) (+ KD[ua,lb] ddetg[lc] + KD[ua,lc] ddetg[lb] mathematica code - (1/3) g[lb,lc] gu[ua,ud] ddetg[ld]), -mathematica code +mathematica blank mathematica code R[la,lb] -> + Rt[la,lb] + Rphi[la,lb], mathematica blank mathematica code IfCCZ4[ @@ -1123,42 +1120,41 @@ mathematica comment (* TODO: check this equation, maybe simplify it by omitt mathematica code ], mathematica blank mathematica code trR -> gu[ua,ub] R[la,lb], -mathematica code +mathematica blank mathematica comment (* K[la,lb] -> e4phi At[la,lb] + (1/3) g[la,lb] trK, *) mathematica comment (* Km[ua,lb] -> gu[ua,uc] K[lc,lb], *) mathematica code Atm[ua,lb] -> gtu[ua,uc] At[lc,lb], -mathematica code +mathematica blank mathematica comment (* Matter terms *) -mathematica code +mathematica blank mathematica comment (* rho = n^a n^b T_ab *) mathematica code rho -> 1/alpha^2 (T00 - 2 beta[ui] T0[li] + beta[ui] beta[uj] T[li,lj]), -mathematica code +mathematica blank mathematica comment (* S_i = -p^a_i n^b T_ab, where p^a_i = delta^a_i + n^a n_i *) mathematica code S[li] -> -1/alpha (T0[li] - beta[uj] T[li,lj]), -mathematica code +mathematica blank mathematica comment (* Constraints *) -mathematica code +mathematica blank mathematica comment (* H -> trR - Km[ua,lb] Km[ub,la] + trK^2, *) mathematica comment (* PRD 67, 084023 (2003), eqn. (19) *) mathematica code H -> trR - Atm[ua,lb] Atm[ub,la] + (2/3) trK^2 - addMatter 16 Pi rho, -mathematica code +mathematica blank mathematica comment (* gK[la,lb,lc] -> CD[K[la,lb],lc], *) mathematica comment (* gK[la,lb,lc] -> + 4 e4phi PD[phi,lc] At[la,lb] + e4phi CD[At[la,lb],lc] mathematica comment + (1/3) g[la,lb] PD[trK,lc], -mathematica blank mathematica comment M[la] -> gu[ub,uc] (gK[lc,la,lb] - gK[lc,lb,la]), *) mathematica blank mathematica code M[li] -> + gtu[uj,uk] (CDt[At[li,lj],lk] + 6 At[li,lj] cdphi[lk]) mathematica code - (2/3) PD[trK,li] mathematica code - addMatter 8 Pi S[li], mathematica comment (* TODO: use PRD 67, 084023 (2003), eqn. (20) *) -mathematica code +mathematica blank mathematica comment (* det gamma-tilde *) mathematica code cS -> Log[detgt], -mathematica code +mathematica blank mathematica comment (* Gamma constraint *) mathematica code cXt[ua] -> gtu[ub,uc] Gt[ua,lb,lc] - Xt[ua], -mathematica code +mathematica blank mathematica comment (* trace A-tilde *) mathematica code cA -> gtu[ua,ub] At[la,lb] mathematica code } @@ -1481,4 +1477,4 @@ mathematica comment (* These are the arguments to createComment: mathematica code createCode[4, False, True, True , True , 3, 1, "BSSN"]; mathematica blank mathematica code createCode[4, False, True, True , False, 3, 1, "CCZ4"]; -mathematica blank \ No newline at end of file +mathematica blank diff --git a/test/src_dir/mathematica1.m b/test/src_dir/mathematica1.m new file mode 100644 index 0000000..4bec755 --- /dev/null +++ b/test/src_dir/mathematica1.m @@ -0,0 +1,1480 @@ + +SetEnhancedTimes[False]; +SetSourceLanguage["C"]; + +(******************************************************************************) +(* Options *) +(******************************************************************************) + +createCode[derivOrder_, useJacobian_, splitUpwindDerivs_, useVectors_, useOpenCL_, evolutionTimelevels_, addMatter_, formulation_] := +Module[{prefix, suffix, thorn}, + +prefix = "ML_"; +suffix = + "" + <> If [useJacobian, "_MP", ""] + <> If [derivOrder!=4, "_O" <> ToString[derivOrder], ""] + <> If [splitUpwindDerivs, "", "_UPW"] + <> If [useVectors, "", "_NV"] + <> If [useOpenCL, "_CL", ""] + (* <> If [evolutionTimelevels!=3, "_TL" <> ToString[evolutionTimelevels], ""] *) + (* <> If [addMatter==1, "_M", ""] *) + ; + +thorn = prefix <> formulation <> suffix; + +SetAttributes[IfCCZ4, HoldAll]; +IfCCZ4[expr_, else_:Sequence[]] := If[formulation === "CCZ4", expr, Unevaluated[else]]; + +(******************************************************************************) +(* Derivatives *) +(******************************************************************************) + +KD = KroneckerDelta; + +derivatives = +{ + PDstandardNth[i_] -> StandardCenteredDifferenceOperator[1,fdOrder/2,i], + PDstandardNth[i_,i_] -> StandardCenteredDifferenceOperator[2,fdOrder/2,i], + PDstandardNth[i_,j_] -> StandardCenteredDifferenceOperator[1,fdOrder/2,i] * + StandardCenteredDifferenceOperator[1,fdOrder/2,j], + PDdissipationNth[i_] -> + (-1)^(fdOrder/2) * + spacing[i]^(fdOrder+1) / 2^(fdOrder+2) * + StandardCenteredDifferenceOperator[fdOrder+2,fdOrder/2+1,i], + +(* PD: These come from my mathematica notebook + "Upwind-Kranc-Convert.nb" that converts upwinding finite + differencing operators generated by + StandardUpwindDifferenceOperator into this form *) + + Sequence@@Flatten[Table[ + {PDupwindNth[i] -> Switch[fdOrder, + 2, (dir[i]*(-3 + 4*shift[i]^dir[i] - shift[i]^(2*dir[i])))/(2*spacing[i]), + 4, (dir[i]*(-10 - 3/shift[i]^dir[i] + 18*shift[i]^dir[i] - + 6*shift[i]^(2*dir[i]) + shift[i]^(3*dir[i])))/(12*spacing[i]), + 6, (dir[i]*(-35 + 2/shift[i]^(2*dir[i]) - 24/shift[i]^dir[i] + 80*shift[i]^dir[i] - + 30*shift[i]^(2*dir[i]) + 8*shift[i]^(3*dir[i]) - shift[i]^(4*dir[i])))/(60*spacing[i]), + 8, (dir[i]*(-378 - 5/shift[i]^(3*dir[i]) + 60/shift[i]^(2*dir[i]) - 420/shift[i]^dir[i] + + 1050*shift[i]^dir[i] - 420*shift[i]^(2*dir[i]) + 140*shift[i]^(3*dir[i]) - 30*shift[i]^(4*dir[i]) + + 3*shift[i]^(5*dir[i])))/(840*spacing[i])], + + PDupwindNthAnti[i] -> Switch[fdOrder, + 2, (+1 shift[i]^(-2) -4 shift[i]^(-1) +0 shift[i]^( 0) +4 shift[i]^(+1) -1 shift[i]^(+2)) / (4 spacing[i]), + 4, (-1 shift[i]^(-3) +6 shift[i]^(-2) -21 shift[i]^(-1 )+0 shift[i]^( 0) +21 shift[i]^(+1) + -6 shift[i]^(+2) +1 shift[i]^(+3)) / (24 spacing[i]), + 6, (+1 shift[i]^(-4) -8 shift[i]^(-3) +32 shift[i]^(-2) -104 shift[i]^(-1) +0 shift[i]^( 0) + +104 shift[i]^(+1) -32 shift[i]^(+2) +8 shift[i]^(+3) -1 shift[i]^(+4)) / (120 spacing[i]), + 8, (-3 shift[i]^(-5) +30 shift[i]^(-4) -145 shift[i]^(-3) +480 shift[i]^(-2) -1470 shift[i]^(-1) + +0 shift[i]^( 0) +1470 shift[i]^(+1) -480 shift[i]^(+2) +145 shift[i]^(+3) -30 shift[i]^(+4) + +3 shift[i]^(+5)) / (1680 spacing[i])], + + PDupwindNthSymm[i] -> Switch[fdOrder, + 2, (-1 shift[i]^(-2) +4 shift[i]^(-1) -6 shift[i]^( 0) +4 shift[i]^(+1) -1 shift[i]^(+2)) / (4 spacing[i]), + 4, (+1 shift[i]^(-3) -6 shift[i]^(-2) +15 shift[i]^(-1) -20 shift[i]^( 0) +15 shift[i]^(+1) + -6 shift[i]^(+2) +1 shift[i]^(+3)) / (24 spacing[i]), + 6, (-1 shift[i]^(-4) +8 shift[i]^(-3) - 28 shift[i]^(-2)+56 shift[i]^(-1)-70 shift[i]^( 0) + +56 shift[i]^(+1) -28 shift[i]^(+2) +8 shift[i]^(+3) -1 shift[i]^(+4)) / (120 spacing[i]), + 8, (+3 shift[i]^(-5) -30 shift[i]^(-4) +135 shift[i]^(-3) -360 shift[i]^(-2) +630 shift[i]^(-1) + -756 shift[i]^( 0) +630 shift[i]^(+1) -360 shift[i]^(+2) +135 shift[i]^(+3) -30 shift[i]^(+4) + +3 shift[i]^(+5)) / (1680 spacing[i])], + + (* TODO: make these higher order stencils *) + PDonesided[i] -> dir[i] (-1 + shift[i]^dir[i]) / spacing[i]} /. i->j, {j,1,3}],1] +}; + +PD = PDstandardNth; +PDu = PDupwindNth; +PDua = PDupwindNthAnti; +PDus = PDupwindNthSymm; +(* PDo = PDonesided; *) +PDdiss = PDdissipationNth; + +If [splitUpwindDerivs, + Upwind[dir_, var_, idx_] := dir PDua[var,idx] + Abs[dir] PDus[var,idx], + Upwind[dir_, var_, idx_] := dir PDu[var,idx]]; + + + +(******************************************************************************) +(* Tensors *) +(******************************************************************************) + +(* Register the tensor quantities with the TensorTools package *) +Map [DefineTensor, + {normal, tangentA, tangentB, dir, + nn, nu, nlen, nlen2, su, vg, + xx, rr, th, ph, + admg, admK, admalpha, admdtalpha, admbeta, admdtbeta, H, M, + g, detg, gu, G, R, trR, Km, trK, cdphi, cdphi2, + phi, gt, At, Xt, Xtn, Theta, Z, + alpha, A, beta, B, Atm, Atu, trA, Ats, trAts, + dottrK, dotXt, + cXt, cS, cA, + e4phi, em4phi, ddetg, detgt, gtu, ddetgt, dgtu, ddgtu, Gtl, Gtlu, Gt, + Rt, Rphi, gK, + T00, T0, T, rho, S, + x, y, z, r, + epsdiss}]; + +(* NOTE: It seems as if Lie[.,.] did not take these tensor weights + into account. Presumably, CD[.,.] and CDt[.,.] don't do this either. *) +SetTensorAttribute[phi, TensorWeight, +1/6]; +SetTensorAttribute[gt, TensorWeight, -2/3]; +SetTensorAttribute[Xt, TensorWeight, +2/3]; +SetTensorAttribute[At, TensorWeight, -2/3]; +SetTensorAttribute[cXt, TensorWeight, +2/3]; +SetTensorAttribute[cS, TensorWeight, +2 ]; + +Map [AssertSymmetricIncreasing, + {admg[la,lb], admK[la,lb], g[la,lb], K[la,lb], R[la,lb], cdphi2[la,lb], + gt[la,lb], At[la,lb], Ats[la,lb], Rt[la,lb], Rphi[la,lb], T[la,lb]}]; +AssertSymmetricIncreasing [G[ua,lb,lc], lb, lc]; +AssertSymmetricIncreasing [Gtl[la,lb,lc], lb, lc]; +AssertSymmetricIncreasing [Gt[ua,lb,lc], lb, lc]; +AssertSymmetricIncreasing [gK[la,lb,lc], la, lb]; +Map [AssertSymmetricIncreasing, + {gu[ua,ub], gtu[ua,ub], Atu[ua,ub]}]; +AssertSymmetricIncreasing [dgtu[ua,ub,lc], ua, ub]; +AssertSymmetricIncreasing [ddgtu[ua,ub,lc,ld], ua, ub]; +AssertSymmetricIncreasing [ddgtu[ua,ub,lc,ld], lc, ld]; + +DefineConnection [CD, PD, G]; +DefineConnection [CDt, PD, Gt]; + +(* Use the CartGrid3D variable names *) +x1=x; x2=y; x3=z; + +(* Use the ADMBase variable names *) +admg11=gxx; admg12=gxy; admg22=gyy; admg13=gxz; admg23=gyz; admg33=gzz; +admK11=kxx; admK12=kxy; admK22=kyy; admK13=kxz; admK23=kyz; admK33=kzz; +admalpha=alp; +admdtalpha=dtalp; +admbeta1=betax; admbeta2=betay; admbeta3=betaz; +admdtbeta1=dtbetax; admdtbeta2=dtbetay; admdtbeta3=dtbetaz; + +(* Use the TmunuBase variable names *) +T00=eTtt; +T01=eTtx; T02=eTty; T03=eTtz; +T11=eTxx; T12=eTxy; T22=eTyy; T13=eTxz; T23=eTyz; T33=eTzz; + + + +(******************************************************************************) +(* Expressions *) +(******************************************************************************) + +(* enum constants for conformalMethod; these must be consistent + with the definition of the Cactus parameter conformalMethod *) +CMphi = 0; +CMW = 1; + +detgExpr = Det [MatrixOfComponents [g [la,lb]]]; +ddetgExpr[la_] = + Sum [D[Det[MatrixOfComponents[g[la, lb]]], X] PD[X, la], + {X, Union[Flatten[MatrixOfComponents[g[la, lb]]]]}]; + +detgtExpr = Det [MatrixOfComponents [gt[la,lb]]]; +ddetgtExpr[la_] = + Sum [D[Det[MatrixOfComponents[gt[la, lb]]], X] PD[X, la], + {X, Union[Flatten[MatrixOfComponents[gt[la, lb]]]]}]; + +etaExpr = SpatialBetaDriverRadius / Max [r, SpatialBetaDriverRadius]; +thetaExpr = Min [Exp [1 - r / SpatialShiftGammaCoeffRadius], 1]; + + + +(******************************************************************************) +(* Groups *) +(******************************************************************************) + +evolvedGroups = + {SetGroupName [CreateGroupFromTensor [phi ], prefix <> "log_confac"], + SetGroupName [CreateGroupFromTensor [gt[la,lb]], prefix <> "metric" ], + SetGroupName [CreateGroupFromTensor [Xt[ua] ], prefix <> "Gamma" ], + SetGroupName [CreateGroupFromTensor [trK ], prefix <> "trace_curv"], + SetGroupName [CreateGroupFromTensor [At[la,lb]], prefix <> "curv" ], + SetGroupName [CreateGroupFromTensor [alpha ], prefix <> "lapse" ], + SetGroupName [CreateGroupFromTensor [A ], prefix <> "dtlapse" ], + SetGroupName [CreateGroupFromTensor [beta[ua] ], prefix <> "shift" ], + SetGroupName [CreateGroupFromTensor [B[ua] ], prefix <> "dtshift" ], + IfCCZ4[SetGroupName[CreateGroupFromTensor[Theta], prefix <> "Theta"]]}; +evaluatedGroups = + {SetGroupName [CreateGroupFromTensor [H ], prefix <> "Ham"], + SetGroupName [CreateGroupFromTensor [M[la] ], prefix <> "mom"], + SetGroupName [CreateGroupFromTensor [cS ], prefix <> "cons_detg"], + SetGroupName [CreateGroupFromTensor [cXt[ua]], prefix <> "cons_Gamma"], + SetGroupName [CreateGroupFromTensor [cA ], prefix <> "cons_traceA"]}; + +declaredGroups = Join [evolvedGroups, evaluatedGroups]; +declaredGroupNames = Map [First, declaredGroups]; + + + +extraGroups = + {{"grid::coordinates", {x, y, z, r}}, + {"ADMBase::metric", {gxx, gxy, gxz, gyy, gyz, gzz}}, + {"ADMBase::curv", {kxx, kxy, kxz, kyy, kyz, kzz}}, + {"ADMBase::lapse", {alp}}, + {"ADMBase::dtlapse", {dtalp}}, + {"ADMBase::shift", {betax, betay, betaz}}, + {"ADMBase::dtshift", {dtbetax, dtbetay, dtbetaz}}, + {"TmunuBase::stress_energy_scalar", {eTtt}}, + {"TmunuBase::stress_energy_vector", {eTtx, eTty, eTtz}}, + {"TmunuBase::stress_energy_tensor", {eTxx, eTxy, eTxz, eTyy, eTyz, eTzz}} +}; + +groups = Join [declaredGroups, extraGroups]; + + + +(******************************************************************************) +(* Initial data *) +(******************************************************************************) + +initialCalc = +{ + Name -> thorn <> "_Minkowski", + Schedule -> {"IN ADMBase_InitialData"}, + ConditionalOnKeyword -> {"my_initial_data", "Minkowski"}, + Equations -> + { + phi -> IfThen[conformalMethod==CMW, 1, 0], + gt[la,lb] -> KD[la,lb], + trK -> 0, + At[la,lb] -> 0, + Xt[ua] -> 0, + alpha -> 1, + A -> 0, + beta[ua] -> 0, + B[ua] -> 0, + IfCCZ4[Theta -> 0] + } +}; + + + +(******************************************************************************) +(* Split a calculation *) +(******************************************************************************) + +PartialCalculation[calc_, suffix_, updates_, evolVars_] := +Module[ + {name, calc1, replaces, calc2, vars, patterns, eqs, calc3}, + (* Add suffix to name *) + name = lookup[calc, Name] <> suffix; + calc1 = mapReplace[calc, Name, name]; + (* Replace some entries in the calculation *) + (* replaces = Map[Function[rule, mapReplace[#, rule[[1]], rule[[2]]]&], updates]; *) + replaces = updates //. (lhs_ -> rhs_) -> (mapReplace[#, lhs, rhs]&); + calc2 = Apply[Composition, replaces][calc1]; + (* Remove unnecessary equations *) + vars = Join[evolVars, lookup[calc2, Shorthands]]; + patterns = Replace[vars, { Tensor[n_,__] -> Tensor[n,__] , + dot[Tensor[n_,__]] -> dot[Tensor[n,__]]}, 1]; + eqs = FilterRules[lookup[calc, Equations], patterns]; + calc3 = mapReplace[calc2, Equations, eqs]; + calc3 +]; + + + +(******************************************************************************) +(* Convert from ADMBase *) +(******************************************************************************) + +convertFromADMBaseCalc = +{ + Name -> thorn <> "_convertFromADMBase", + Schedule -> {"AT initial AFTER ADMBase_PostInitial"}, + ConditionalOnKeyword -> {"my_initial_data", "ADMBase"}, + Shorthands -> {g[la,lb], detg, gu[ua,ub], em4phi}, + Equations -> + { + g[la,lb] -> admg[la,lb], + detg -> detgExpr, + gu[ua,ub] -> 1/detg detgExpr MatrixInverse [g[ua,ub]], + + phi -> IfThen[conformalMethod==CMW, detg^(-1/6), Log[detg]/12], + em4phi -> IfThen[conformalMethod==CMW, phi^2, Exp[-4 phi]], + gt[la,lb] -> em4phi g[la,lb], + + trK -> gu[ua,ub] admK[la,lb], + At[la,lb] -> em4phi (admK[la,lb] - (1/3) g[la,lb] trK), + + alpha -> admalpha, + + beta[ua] -> admbeta[ua], + + IfCCZ4[Theta -> 0] + } +}; + +convertFromADMBaseGammaCalc = +{ + Name -> thorn <> "_convertFromADMBaseGamma", + Schedule -> {"AT initial AFTER " <> thorn <> "_convertFromADMBase"}, + ConditionalOnKeyword -> {"my_initial_data", "ADMBase"}, + (* + Where -> InteriorNoSync, + *) + (* Do not synchronise right after this routine; instead, synchronise + after extrapolating *) + Where -> Interior, + (* Synchronise after this routine, so that the refinement boundaries + are set correctly before extrapolating. (We will need to + synchronise again after extrapolating because extrapolation does + not fill ghost zones, but this is irrelevant here.) *) + Shorthands -> {dir[ua], + detgt, gtu[ua,ub], Gt[ua,lb,lc], theta}, + Equations -> + { + dir[ua] -> Sign[beta[ua]], + + detgt -> 1 (* detgtExpr *), + gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], + Gt[ua,lb,lc] -> 1/2 gtu[ua,ud] + (PD[gt[lb,ld],lc] + PD[gt[lc,ld],lb] - PD[gt[lb,lc],ld]), + Xt[ua] -> gtu[ub,uc] Gt[ua,lb,lc], + +(* + A -> - admdtalpha / (harmonicF alpha^harmonicN) (LapseAdvectionCoeff - 1), +*) + (* If LapseACoeff=0, then A is not evolved, in the sense that it + does not influence the time evolution of other variables. *) + A -> IfThen [LapseACoeff != 0, + 1 / (- harmonicF alpha^harmonicN) + (+ admdtalpha + - LapseAdvectionCoeff Upwind[beta[ua], alpha, la]), + 0], + + theta -> thetaExpr, + + (* If ShiftBCoeff=0 or theta ShiftGammaCoeff=0, then B^i is not + evolved, in the sense that it does not influence the time + evolution of other variables. *) + B[ua] -> IfThen [ShiftGammaCoeff ShiftBCoeff != 0, + 1 / (theta ShiftGammaCoeff) + (+ admdtbeta[ua] + - ShiftAdvectionCoeff Upwind[beta[ub], beta[ua], lb]), + 0] + } +}; + +(* Initialise the Gamma variables to 0. This is necessary with + multipatch because convertFromADMBaseGamma does not perform the + conversion in the boundary points, and the order in which symmetry + (interpatch) and outer boundary conditions is applied means that + points which are both interpatch and symmetry points are never + initialised. *) +initGammaCalc = +{ + Name -> thorn <> "_InitGamma", + Schedule -> {"AT initial BEFORE " <> thorn <> "_convertFromADMBaseGamma"}, + ConditionalOnKeyword -> {"my_initial_data", "ADMBase"}, + Where -> Everywhere, + Equations -> + { + Xt[ua] -> 0, + A -> 0, + B[ua] -> 0 + } +}; + + + +(******************************************************************************) +(* Convert to ADMBase *) +(******************************************************************************) + +convertToADMBaseCalc = +{ + Name -> thorn <> "_convertToADMBase", + Schedule -> {"IN " <> thorn <> "_convertToADMBaseGroup"}, + Where -> Everywhere, + Shorthands -> {e4phi}, + Equations -> + { + e4phi -> IfThen[conformalMethod==CMW, 1/phi^2, Exp[4 phi]], + admg[la,lb] -> e4phi gt[la,lb], + admK[la,lb] -> e4phi At[la,lb] + (1/3) admg[la,lb] trK, + admalpha -> alpha, + admbeta[ua] -> beta[ua] + } +}; + +convertToADMBaseDtLapseShiftCalc = +{ + Name -> thorn <> "_convertToADMBaseDtLapseShift", + Schedule -> {"IN " <> thorn <> "_convertToADMBaseGroup"}, + ConditionalOnKeyword -> {"dt_lapse_shift_method", "correct"}, + Where -> Interior, + Shorthands -> {dir[ua], detgt, gtu[ua,ub], eta, theta}, + Equations -> + { + dir[ua] -> Sign[beta[ua]], + + detgt -> 1 (* detgtExpr *), + (* This leads to simpler code... *) + gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], + + eta -> etaExpr, + theta -> thetaExpr, + + (* see RHS *) +(* + admdtalpha -> - harmonicF alpha^harmonicN + ((1 - LapseAdvectionCoeff) A + LapseAdvectionCoeff trK) + + LapseAdvectionCoeff beta[ua] PDu[alpha,la], +*) + admdtalpha -> - harmonicF alpha^harmonicN + (+ LapseACoeff A + + ((1 - LapseACoeff) + (trK - IfCCZ4[2 Theta, 0]))) + + LapseAdvectionCoeff Upwind[beta[ua], alpha, la], + admdtbeta[ua] -> IfThen[harmonicShift, + - 1/2 gtu[ua,uj] phi alpha + (- 2 alpha PD[phi,lj] + + 2 phi PD[alpha,lj] + + gtu[uk,ul] phi alpha + (PD[gt[lk,ll],lj] - 2 PD[gt[lj,lk],ll])), + (* else *) + + theta ShiftGammaCoeff + (+ ShiftBCoeff B[ua] + + (1 - ShiftBCoeff) + (Xt[ua] - eta BetaDriver beta[ua]))] + + ShiftAdvectionCoeff Upwind[beta[ub], beta[ua], lb] + } +}; + +convertToADMBaseDtLapseShiftBoundaryCalc = +{ + Name -> thorn <> "_convertToADMBaseDtLapseShiftBoundary", + Schedule -> {"IN " <> thorn <> "_convertToADMBaseGroup"}, + ConditionalOnKeyword -> {"dt_lapse_shift_method", "correct"}, + Where -> BoundaryWithGhosts, + Shorthands -> {detgt, gtu[ua,ub], eta, theta}, + Equations -> + { + detgt -> 1 (* detgtExpr *), + (* This leads to simpler code... *) + gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], + + eta -> etaExpr, + theta -> thetaExpr, + + (* see RHS, but omit derivatives near the boundary *) +(* + admdtalpha -> - harmonicF alpha^harmonicN + ((1 - LapseAdvectionCoeff) A + LapseAdvectionCoeff trK), +*) + admdtalpha -> - harmonicF alpha^harmonicN + (+ LapseACoeff A + + ((1 - LapseACoeff) + (trK - IfCCZ4[2 Theta, 0]))), + admdtbeta[ua] -> IfThen[harmonicShift, + 0, + (* else *) + + theta ShiftGammaCoeff + (+ ShiftBCoeff B[ua] + + (1 - ShiftBCoeff) + (Xt[ua] - eta BetaDriver beta[ua]))] + } +}; + +convertToADMBaseFakeDtLapseShiftCalc = +{ + Name -> thorn <> "_convertToADMBaseFakeDtLapseShift", + Schedule -> {"IN " <> thorn <> "_convertToADMBaseGroup"}, + ConditionalOnKeyword -> {"dt_lapse_shift_method", "noLapseShiftAdvection"}, + Where -> Everywhere, + Shorthands -> {detgt, gtu[ua,ub], eta, theta}, + Equations -> + { + detgt -> 1 (* detgtExpr *), + (* This leads to simpler code... *) + gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], + + eta -> etaExpr, + theta -> thetaExpr, + + (* see RHS, but omit derivatives everywhere (which is wrong, but + faster, since it does not require synchronisation or boundary + conditions) *) +(* + admdtalpha -> - harmonicF alpha^harmonicN + ((1 - LapseAdvectionCoeff) A + LapseAdvectionCoeff trK), +*) + admdtalpha -> - harmonicF alpha^harmonicN + (+ LapseACoeff A + + ((1 - LapseACoeff) + (trK - IfCCZ4[2 Theta, 0]))), + admdtbeta[ua] -> IfThen[harmonicShift, + 0, + (* else *) + + theta ShiftGammaCoeff + (+ ShiftBCoeff B[ua] + + (1 - ShiftBCoeff) + (Xt[ua] - eta BetaDriver beta[ua]))] + } +}; + +(******************************************************************************) +(* Evolution equations *) +(******************************************************************************) + +evolCalc = +{ + Name -> thorn <> "_RHS", + Schedule -> {"IN " <> thorn <> "_evolCalcGroup"}, + (* + Where -> Interior, + *) + (* Synchronise the RHS grid functions after this routine, so that + the refinement boundaries are set correctly before applying the + radiative boundary conditions. *) + Where -> InteriorNoSync, + ConditionalOnKeyword -> {"RHS_split", "combined"}, + Shorthands -> {dir[ua], + detgt, gtu[ua,ub], + Gt[ua,lb,lc], Gtl[la,lb,lc], Gtlu[la,lb,uc], Xtn[ua], + Rt[la,lb], Rphi[la,lb], R[la,lb], + Atm[ua,lb], Atu[ua,ub], + e4phi, em4phi, cdphi[la], cdphi2[la,lb], g[la,lb], detg, + gu[ua,ub], Ats[la,lb], trAts, eta, theta, + rho, S[la], trS, fac1, fac2, dottrK, dotXt[ua], + epsdiss[ua], IfCCZ4[Z[ua]], IfCCZ4[dotTheta]}, + Equations -> + { + dir[ua] -> Sign[beta[ua]], + + detgt -> 1 (* detgtExpr *), + + (* This leads to simpler code... *) + gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], + Gtl[la,lb,lc] -> 1/2 + (PD[gt[lb,la],lc] + PD[gt[lc,la],lb] - PD[gt[lb,lc],la]), + Gtlu[la,lb,uc] -> gtu[uc,ud] Gtl[la,lb,ld], + Gt[ua,lb,lc] -> gtu[ua,ud] Gtl[ld,lb,lc], + + (* The conformal connection functions calculated from the conformal metric, + used instead of Xt where no derivatives of Xt are taken *) + Xtn[ui] -> gtu[uj,uk] Gt[ui,lj,lk], + + e4phi -> IfThen[conformalMethod==CMW, 1/phi^2, Exp[4 phi]], + em4phi -> 1 / e4phi, + g[la,lb] -> e4phi gt[la,lb], + detg -> detgExpr, + gu[ua,ub] -> em4phi gtu[ua,ub], + + (* The Z quantities *) + (* gr-qc:1106.2254 (2011), eqn. (23) *) + IfCCZ4[ + Z[ud] -> (1/2) gu[ua,ud] (- PD[gt[la,lb],lc] gtu[ub,uc] + gt[la,lc] Xt[uc]) + ], + + (* PRD 62, 044034 (2000), eqn. (18) *) + (* Adding Z term by changing Xtn to Xt *) + Rt[li,lj] -> - (1/2) gtu[ul,um] PD[gt[li,lj],ll,lm] + + (1/2) gt[lk,li] PD[Xt[uk],lj] + + (1/2) gt[lk,lj] PD[Xt[uk],li] + + (1/2) Xtn[uk] Gtl[li,lj,lk] + + (1/2) Xtn[uk] Gtl[lj,li,lk] + + (+ Gt[uk,li,ll] Gtlu[lj,lk,ul] + + Gt[uk,lj,ll] Gtlu[li,lk,ul] + + Gt[uk,li,ll] Gtlu[lk,lj,ul]), + + fac1 -> IfThen[conformalMethod==CMW, -1/(2 phi), 1], + cdphi[la] -> fac1 CDt[phi,la], + fac2 -> IfThen[conformalMethod==CMW, 1/(2 phi^2), 0], + cdphi2[la,lb] -> fac1 CDt[phi,la,lb] + fac2 CDt[phi,la] CDt[phi,lb], + + (* PRD 62, 044034 (2000), eqn. (15) *) + Rphi[li,lj] -> - 2 cdphi2[lj,li] + - 2 gt[li,lj] gtu[ul,un] cdphi2[ll,ln] + + 4 cdphi[li] cdphi[lj] + - 4 gt[li,lj] gtu[ul,un] cdphi[ln] cdphi[ll], + + Atm[ua,lb] -> gtu[ua,uc] At[lc,lb], + Atu[ua,ub] -> Atm[ua,lc] gtu[ub,uc], + + R[la,lb] -> Rt[la,lb] + Rphi[la,lb], + IfCCZ4[ + R[la,lb] -> R[la,lb] + (2/phi) (+ g[la,lc] Z[uc] PD[phi,lb] + + g[lb,lc] Z[uc] PD[phi,la] - g[la,lb] Z[uc] PD[phi,lc]) + + e4phi Z[uc] PD[gt[la,lb],lc] + ], + + (* Matter terms *) + + (* rho = n^a n^b T_ab *) + rho -> addMatter + (1/alpha^2 (T00 - 2 beta[ui] T0[li] + beta[ui] beta[uj] T[li,lj])), + + (* S_i = -p^a_i n^b T_ab, where p^a_i = delta^a_i + n^a n_i *) + S[li] -> addMatter (-1/alpha (T0[li] - beta[uj] T[li,lj])), + + (* trS = gamma^ij T_ij *) + trS -> addMatter (em4phi gtu[ui,uj] T[li,lj]), + + (* RHS terms *) + + (* PRD 62, 044034 (2000), eqn. (10) *) + (* PRD 67 084023 (2003), eqn. (16) and (23) *) + dot[phi] -> IfThen[conformalMethod==CMW, 1/3 phi, -1/6] + (alpha trK - PD[beta[ua],la]), + + (* PRD 62, 044034 (2000), eqn. (9) *) + (* gr-qc:1106.2254 (2011), eqn. (14) *) + (* removing trA from Aij ensures that detg = 1 *) + dot[gt[la,lb]] -> - 2 alpha (At[la,lb] - IfCCZ4[(1/3) At[lc,ld] gtu[uc,ud] gt[la,lb], 0]) + + gt[la,lc] PD[beta[uc],lb] + gt[lb,lc] PD[beta[uc],la] + - (2/3) gt[la,lb] PD[beta[uc],lc], + (* PRD 62, 044034 (2000), eqn. (20) *) + (* PRD 67 084023 (2003), eqn (26) *) + (* gr-qc:1106.2254 (2011), eqn. (19) *) + (* Adding Z terms by changing Xtn to Xt, + also adding extra Z and Theta terms *) + dotXt[ui] -> - 2 Atu[ui,uj] PD[alpha,lj] + + 2 alpha (+ Gt[ui,lj,lk] Atu[uk,uj] + - (2/3) gtu[ui,uj] PD[trK,lj] + + 6 Atu[ui,uj] cdphi[lj]) + + gtu[uj,ul] PD[beta[ui],lj,ll] + + (1/3) gtu[ui,uj] PD[beta[ul],lj,ll] + - Xtn[uj] PD[beta[ui],lj] + + (2/3) Xtn[ui] PD[beta[uj],lj] + + IfCCZ4[ + + GammaShift 2 e4phi (- Z[uj] PD[beta[ui],lj] + + (2/3) Z[ui] PD[beta[uj],lj]) + - (4/3) alpha e4phi Z[ui] trK + + 2 gtu[ui,uj] (+ alpha PD[Theta,lj] + - Theta PD[alpha,lj]) + - 2 alpha e4phi dampk1 Z[ui], + 0] + (* Equation (4.28) in Baumgarte & Shapiro (Phys. Rept. 376 (2003) 41-131) *) + + addMatter (- 16 Pi alpha gtu[ui,uj] S[lj]), + dot[Xt[ui]] -> dotXt[ui], + + (* gr-qc:1106.2254 (2011), eqn. (18) *) + IfCCZ4[ + dotTheta -> + - PD[alpha,la] Z[ua] - dampk1 (2 + dampk2) alpha Theta + + (1/2) alpha (gu[ua,ub] R[la,lb] - Atm[ua,lb] Atm[ub,la] + (2/3) trK^2 - 2 trK Theta) + + addMatter (- 8 Pi alpha rho) + ], + + IfCCZ4[ + dot[Theta] -> dotTheta + ], + + (* PRD 62, 044034 (2000), eqn. (11) *) + (* gr-qc:1106.2254 (2011), eqn. (17) *) + (* Adding the RHS of Theta to K, because K_Z4 = K_BSSN + 2 Theta *) + (* Also adding the Z term, as it has to cancel with the one in Theta *) + dottrK -> - em4phi ( gtu[ua,ub] ( PD[alpha,la,lb] + + 2 cdphi[la] PD[alpha,lb] ) + - Xtn[ua] PD[alpha,la] ) + + alpha (Atm[ua,lb] Atm[ub,la] + (1/3) trK^2) + + IfCCZ4[ + + 2 dotTheta + 2 PD[alpha,la] Z[ua] + + dampk1 (1 - dampk2) alpha Theta, + 0] + (* Equation (4.21) in Baumgarte & Shapiro (Phys. Rept. 376 (2003) 41-131) *) + + addMatter (4 Pi alpha (rho + trS)), + dot[trK] -> dottrK, + + (* PRD 62, 044034 (2000), eqn. (12) *) + (* TODO: Should we use the Hamiltonian constraint to make Rij tracefree? *) + (* gr-qc:1106.2254 (2011), eqn. (15) *) + (* Adding Z terms in the Ricci and Theta terms *) + Ats[la,lb] -> - CDt[alpha,la,lb] + + + 2 (PD[alpha,la] cdphi[lb] + PD[alpha,lb] cdphi[la] ) + + alpha R[la,lb], + trAts -> gu[ua,ub] Ats[la,lb], + dot[At[la,lb]] -> + em4phi (+ Ats[la,lb] - (1/3) g[la,lb] trAts ) + + alpha (+ ((trK - IfCCZ4[2 Theta, 0]) + At[la,lb]) + - 2 At[la,lc] Atm[uc,lb]) + + At[la,lc] PD[beta[uc],lb] + At[lb,lc] PD[beta[uc],la] + - (2/3) At[la,lb] PD[beta[uc],lc] + (* Equation (4.23) in Baumgarte & Shapiro (Phys. Rept. 376 (2003) 41-131) *) + + addMatter (- em4phi alpha 8 Pi + (T[la,lb] - (1/3) g[la,lb] trS)), + + (* dot[alpha] -> - harmonicF alpha^harmonicN trK, *) + (* dot[alpha] -> - harmonicF alpha^harmonicN A + Lie[alpha, beta], *) +(* + dot[alpha] -> - harmonicF alpha^harmonicN ( + (1 - LapseAdvectionCoeff) A + LapseAdvectionCoeff trK) + + LapseAdvectionCoeff beta[ua] PDu[alpha,la], + dot[A] -> (1 - LapseAdvectionCoeff) (dottrK - AlphaDriver A), +*) + dot[alpha] -> - harmonicF alpha^harmonicN + (+ LapseACoeff A + + ((1 - LapseACoeff) + (+ trK - IfCCZ4[2 Theta, 0] + + AlphaDriver (alpha - 1)))), + + dot[A] -> + (LapseACoeff + (+ dottrK - IfCCZ4[2 dotTheta, 0] + - AlphaDriver A)), + + eta -> etaExpr, + theta -> thetaExpr, + + (* dot[beta[ua]] -> eta Xt[ua], *) + (* dot[beta[ua]] -> ShiftGammaCoeff alpha^ShiftAlphaPower B[ua], *) + dot[beta[ua]] -> IfThen[harmonicShift, + - 1/2 gtu[ua,uj] phi alpha + (- 2 alpha PD[phi,lj] + + 2 phi PD[alpha,lj] + + gtu[uk,ul] phi alpha + (PD[gt[lk,ll],lj] - 2 PD[gt[lj,lk],ll])), + (* else *) + + theta ShiftGammaCoeff + (+ ShiftBCoeff B[ua] + + (1 - ShiftBCoeff) + (Xt[ua] - eta BetaDriver beta[ua]))], + + dot[B[ua]] -> + ShiftBCoeff (dotXt[ua] - eta BetaDriver B[ua]) + (* Note that this dotXt[ua] is not yet \partial_t \tilde \Gamma^i, because the + advection term has not yet been added. It is actually + \partial_t \tilde \Gamma^i - \beta^j \partial_j \tilde \Gamma^i *) + } +}; + +advectCalc = +{ + Name -> thorn <> "_Advect", + Schedule -> {"IN " <> thorn <> "_evolCalcGroup " <> + "AFTER (" <> thorn <> "_RHS " <> thorn <> "_RHS1 " <> thorn <> "_RHS2)"}, + (* + Where -> Interior, + *) + (* Synchronise the RHS grid functions after this routine, so that + the refinement boundaries are set correctly before applying the + radiative boundary conditions. *) + Where -> InteriorNoSync, + ConditionalOnKeyword -> {"advection_split", "combined"}, + Shorthands -> {dir[ua]}, + Equations -> + { + dir[ua] -> Sign[beta[ua]], + + dot[phi] -> dot[phi] + Upwind[beta[ua], phi, la], + + dot[gt[la,lb]] -> dot[gt[la,lb]] + Upwind[beta[uc], gt[la,lb], lc], + + dot[Xt[ui]] -> dot[Xt[ui]] + Upwind[beta[uj], Xt[ui], lj], + + IfCCZ4[ + dot[Theta] -> dot[Theta] + Upwind[beta[ua], Theta, la] + ], + + dot[trK] -> dot[trK] + Upwind[beta[ua], trK, la], + + dot[At[la,lb]] -> dot[At[la,lb]] + Upwind[beta[uc], At[la,lb], lc], + + dot[alpha] -> dot[alpha] + + LapseAdvectionCoeff Upwind[beta[ua], alpha, la], + + dot[A] -> dot[A] + + LapseACoeff ( + + LapseAdvectionCoeff Upwind[beta[ua], A, la] + + (1 - LapseAdvectionCoeff) Upwind[beta[ua], trK, la]), + + dot[beta[ua]] -> dot[beta[ua]] + + ShiftAdvectionCoeff Upwind[beta[ub], beta[ua], lb], + + dot[B[ua]] -> dot[B[ua]] + + ShiftBCoeff ( + + ShiftAdvectionCoeff Upwind[beta[ub], B[ua], lb] + + ((1 - ShiftAdvectionCoeff) + Upwind[beta[ub], Xt[ua], lb])) + (* Note that the advection term \beta^j \partial_j \tilde \Gamma^i is not + subtracted here when ShiftAdvectionCoefficient == 1 because it was + implicitly subtracted before (see comment in previous calculation of + dot[B[ua]]. *) + } +}; + +varsNames = { + {"phi", dot[phi]}, + {"gt", dot[gt[la,lb]]}, + {"Xt", dot[Xt[ui]]}, + {"trK", dot[trK]}, + {"At", dot[At[la,lb]]}, + {"alpha", dot[alpha]}, + {"A", dot[A]}, + {"beta", dot[beta[ua]]}, + {"B", dot[B[ua]]}, + IfCCZ4[{"Theta", dot[Theta]}] + }; + +advectCalcs = Map[ + PartialCalculation[advectCalc, "_"<>ToString[First[#]], + {ConditionalOnKeyword -> {"advection_split", + "per variable"}}, + {Last[#]}]&, + varsNames]; + +evolCalc1 = PartialCalculation[evolCalc, "1", + { + ConditionalOnKeyword -> {"RHS_split", "split At"} + }, + { + dot[phi], + dot[gt[la,lb]], + dot[Xt[ui]], + dot[trK], + dot[alpha], + dot[A], + dot[beta[ua]], + dot[B[ua]], + IfCCZ4[dot[Theta]] + }]; + +evolCalc2 = PartialCalculation[evolCalc, "2", + { + ConditionalOnKeyword -> {"RHS_split", "split At"} + }, + { + dot[At[la,lb]] + }]; + +dissCalc = +{ + Name -> thorn <> "_Dissipation", + Schedule -> {"IN " <> thorn <> "_evolCalcGroup " <> + "AFTER (" <> thorn <> "_RHS1 " <> thorn <> "_RHS2)"}, + ConditionalOnKeyword -> {"apply_dissipation", "always"}, + Where -> InteriorNoSync, + Shorthands -> {epsdiss[ua]}, + Equations -> + { + epsdiss[ua] -> EpsDiss, + Sequence@@Table[ + dot[var] -> dot[var] + epsdiss[ux] PDdiss[var,lx], + {var, {phi, gt[la,lb], Xt[ui], IfCCZ4[Theta], trK, At[la,lb], + alpha, A, beta[ua], B[ua]}}] + } +}; + +dissCalcs = +Table[ +{ + Name -> thorn <> "_Dissipation_" <> ToString[var /. {Tensor[n_,__] -> n}], + Schedule -> {"IN " <> thorn <> "_evolCalcGroup " <> + "AFTER (" <> thorn <> "_RHS1 " <> thorn <> "_RHS2)"}, + ConditionalOnKeyword -> {"apply_dissipation", "always"}, + Where -> InteriorNoSync, + Shorthands -> {epsdiss[ua]}, + Equations -> + { + epsdiss[ua] -> EpsDiss, + dot[var] -> dot[var] + epsdiss[ux] PDdiss[var,lx] + } +}, + {var, {phi, gt[la,lb], Xt[ui], IfCCZ4[Theta], trK, At[la,lb], + alpha, A, beta[ua], B[ua]}} +]; + +RHSStaticBoundaryCalc = +{ + Name -> thorn <> "_RHSStaticBoundary", + Schedule -> {"IN MoL_CalcRHS"}, + ConditionalOnKeyword -> {"my_rhs_boundary_condition", "static"}, + Where -> Boundary, + Equations -> + { + dot[phi] -> 0, + dot[gt[la,lb]] -> 0, + dot[trK] -> 0, + dot[At[la,lb]] -> 0, + dot[Xt[ua]] -> 0, + dot[alpha] -> 0, + dot[A] -> 0, + dot[beta[ua]] -> 0, + dot[B[ua]] -> 0, + IfCCZ4[dot[Theta] -> 0] + } +}; + +(* Initialise the RHS variables in analysis in case they are going to + be output - the noninterior points cannot be filled, so we define + them to be zero *) +initRHSCalc = +{ + Name -> thorn <> "_InitRHS", + Schedule -> {"AT analysis BEFORE " <> thorn <> "_evolCalcGroup"}, + Where -> Everywhere, + Equations -> + { + dot[phi] -> 0, + dot[gt[la,lb]] -> 0, + dot[trK] -> 0, + dot[At[la,lb]] -> 0, + dot[Xt[ua]] -> 0, + dot[alpha] -> 0, + dot[A] -> 0, + dot[beta[ua]] -> 0, + dot[B[ua]] -> 0, + IfCCZ4[dot[Theta] -> 0] + } +}; + +RHSRadiativeBoundaryCalc = +{ + Name -> thorn <> "_RHSRadiativeBoundary", + Schedule -> {"IN MoL_CalcRHS"}, + ConditionalOnKeyword -> {"my_rhs_boundary_condition", "radiative"}, + Where -> Boundary, + Shorthands -> {dir[ua], + detgt, gtu[ua,ub], em4phi, gu[ua,ub], + nn[la], nu[ua], nlen, nlen2, su[ua], + vg}, + Equations -> + { + dir[ua] -> Sign[normal[ua]], + + detgt -> 1 (* detgtExpr *), + gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], + em4phi -> IfThen[conformalMethod==CMW, phi^2, Exp[-4 phi]], + gu[ua,ub] -> em4phi gtu[ua,ub], + + nn[la] -> Euc[la,lb] normal[ub], + nu[ua] -> gu[ua,ub] nn[lb], + nlen2 -> nu[ua] nn[la], + nlen -> Sqrt[nlen2], + su[ua] -> nu[ua] / nlen, + + vg -> Sqrt[harmonicF], + + dot[phi] -> - vg su[uc] PDo[phi ,lc], + dot[gt[la,lb]] -> - su[uc] PDo[gt[la,lb],lc], + dot[trK] -> - vg su[uc] PDo[trK ,lc], + dot[At[la,lb]] -> - su[uc] PDo[At[la,lb],lc], + dot[Xt[ua]] -> - su[uc] PDo[Xt[ua] ,lc], + dot[alpha] -> - vg su[uc] PDo[alpha ,lc], + dot[A] -> - vg su[uc] PDo[A ,lc], + dot[beta[ua]] -> - su[uc] PDo[beta[ua] ,lc], + dot[B[ua]] -> - su[uc] PDo[B[ua] ,lc], + IfCCZ4[ + dot[Theta] -> - vg su[uc] PDo[Theta ,lc] + ] + } +}; + +enforceCalc = +{ + Name -> thorn <> "_enforce", + Schedule -> {"IN MoL_PostStepModify"}, + Shorthands -> {detgt, gtu[ua,ub], trAt}, + Equations -> + { + (* The following comment is still interesting, but is not correct + any more since it is now scheduled in MoL_PostStepModify instead: + + Enforcing the constraints needs to be a projection, because it + is applied in MoL_PostStep and may thus be applied multiple + times, not only during time evolution. Therefore detgt has to + be calculated correctly, without assuming that det gt_ij = 1, + which is not always the case (since we don't enforce it). On + the other hand, this may not be so important... *) + detgt -> 1 (* detgtExpr *), + gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], + + trAt -> gtu[ua,ub] At[la,lb], + + At[la,lb] -> At[la,lb] - (1/3) gt[la,lb] trAt, + + alpha -> Max[alpha, MinimumLapse] + } +}; + +(******************************************************************************) +(* Boundary conditions *) +(******************************************************************************) + +boundaryCalc = +{ + Name -> thorn <> "_boundary", + Schedule -> {"IN MoL_PostStep"}, + ConditionalOnKeyword -> {"my_boundary_condition", "Minkowski"}, + Where -> BoundaryWithGhosts, + Equations -> + { + phi -> IfThen[conformalMethod==CMW, 1, 0], + gt[la,lb] -> KD[la,lb], + trK -> 0, + At[la,lb] -> 0, + Xt[ua] -> 0, + alpha -> 1, + A -> 0, + beta[ua] -> 0, + B[ua] -> 0, + IfCCZ4[Theta -> 0] + } +}; + +(******************************************************************************) +(* Constraint equations *) +(******************************************************************************) + +constraintsCalc = +{ + Name -> thorn <> "_constraints", + Schedule -> Automatic, + After -> "MoL_PostStep", + Where -> Interior, + Shorthands -> {detgt, ddetgt[la], gtu[ua,ub], Z[ua], + Gt[ua,lb,lc], Gtl[la,lb,lc], Gtlu[la,lb,uc], Xtn[ua], + e4phi, em4phi, + g[la,lb], detg, gu[ua,ub], ddetg[la], G[ua,lb,lc], + Rt[la,lb], Rphi[la,lb], R[la,lb], trR, Atm[ua,lb], + gK[la,lb,lc], cdphi[la], cdphi2[la,lb], + rho, S[la], fac1, fac2}, + Equations -> + { + detgt -> 1 (* detgtExpr *), + ddetgt[la] -> 0 (* ddetgtExpr[la] *), + + (* This leads to simpler code... *) + gtu[ua,ub] -> 1/detgt detgtExpr MatrixInverse [gt[ua,ub]], + Gtl[la,lb,lc] -> 1/2 + (PD[gt[lb,la],lc] + PD[gt[lc,la],lb] - PD[gt[lb,lc],la]), + Gtlu[la,lb,uc] -> gtu[uc,ud] Gtl[la,lb,ld], + Gt[ua,lb,lc] -> gtu[ua,ud] Gtl[ld,lb,lc], + + (* The conformal connection functions calculated from the conformal metric, + used instead of Xt where no derivatives of Xt are taken *) + Xtn[ui] -> gtu[uj,uk] Gt[ui,lj,lk], + + e4phi -> IfThen[conformalMethod==CMW, 1/phi^2, Exp[4 phi]], + em4phi -> 1 / e4phi, + g[la,lb] -> e4phi gt[la,lb], + detg -> e4phi^3, + gu[ua,ub] -> em4phi gtu[ua,ub], + + (* The Z quantities *) + IfCCZ4[ + Z[ud] -> (1/2) gu[ua,ud] (- PD[gt[la,lb],lc] gtu[ub,uc] + gt[la,lc] Xt[uc]) + ], + + (* PRD 62, 044034 (2000), eqn. (18) *) + Rt[li,lj] -> - (1/2) gtu[ul,um] PD[gt[li,lj],ll,lm] + + (1/2) gt[lk,li] PD[Xt[uk],lj] + + (1/2) gt[lk,lj] PD[Xt[uk],li] + + (1/2) Xtn[uk] Gtl[li,lj,lk] + + (1/2) Xtn[uk] Gtl[lj,li,lk] + + (+ Gt[uk,li,ll] Gtlu[lj,lk,ul] + + Gt[uk,lj,ll] Gtlu[li,lk,ul] + + Gt[uk,li,ll] Gtlu[lk,lj,ul]), + + (* From the long turducken paper. + This expression seems to give the same result as the one from 044034. *) + (* TODO: symmetrise correctly: (ij) = (1/2) [i+j] *) +(* + Rt[li,lj] -> - (1/2) gtu[uk,ul] PD[gt[li,lj],lk,ll] + + gt[lk,li] PD[Xt[uk],lj] + gt[lk,lj] PD[Xt[uk],li] + + gt[li,ln] Gt[un,lj,lk] gtu[um,ua] gtu[uk,ub] PD[gt[la,lb],lm] + + gt[lj,ln] Gt[un,li,lk] gtu[um,ua] gtu[uk,ub] PD[gt[la,lb],lm] + + gtu[ul,us] (+ 2 Gt[uk,ll,li] gt[lj,ln] Gt[un,lk,ls] + + 2 Gt[uk,ll,lj] gt[li,ln] Gt[un,lk,ls] + + Gt[uk,li,ls] gt[lk,ln] Gt[un,ll,lj]), +*) + + (* Below would be a straightforward calculation, + without taking any Gamma^i into account. + This expression gives a different answer! *) +(* + Rt[la,lb] -> + Gt[u1,l2,la] Gt[l1,lb,u2] - Gt[u1,la,lb] Gt[l1,l2,u2] + + 1/2 gtu[u1,u2] (- PD[gt[l1,l2],la,lb] + PD[gt[l1,la],l2,lb] + - PD[gt[la,lb],l1,l2] + PD[gt[l2,lb],l1,la]), +*) + + fac1 -> IfThen[conformalMethod==CMW, -1/(2 phi), 1], + cdphi[la] -> fac1 CDt[phi,la], + fac2 -> IfThen[conformalMethod==CMW, 1/(2 phi^2), 0], + cdphi2[la,lb] -> fac1 CDt[phi,la,lb] + fac2 CDt[phi,la] CDt[phi,lb], + + (* PRD 62, 044034 (2000), eqn. (15) *) + Rphi[li,lj] -> - 2 cdphi2[lj,li] + - 2 gt[li,lj] gtu[ul,un] cdphi2[ll,ln] + + 4 cdphi[li] cdphi[lj] + - 4 gt[li,lj] gtu[ul,un] cdphi[ln] cdphi[ll], + + (* ddetg[la] -> PD[e4phi detg,la], *) + ddetg[la] -> e4phi ddetgt[la] + 4 detgt e4phi PD[phi,la], + (* TODO: check this equation, maybe simplify it by omitting ddetg *) + G[ua,lb,lc] -> Gt[ua,lb,lc] + + 1/(2 detg) (+ KD[ua,lb] ddetg[lc] + KD[ua,lc] ddetg[lb] + - (1/3) g[lb,lc] gu[ua,ud] ddetg[ld]), + + R[la,lb] -> + Rt[la,lb] + Rphi[la,lb], + + IfCCZ4[ + R[la,lb] -> R[la, lb] + (2/phi) (+ g[la,lc] Z[uc] PD[phi,lb] + + g[lb,lc] Z[uc] PD[phi,la] - g[la,lb] Z[uc] PD[phi,lc]) + + e4phi Z[uc] PD[gt[la,lb],lc] + ], + + trR -> gu[ua,ub] R[la,lb], + + (* K[la,lb] -> e4phi At[la,lb] + (1/3) g[la,lb] trK, *) + (* Km[ua,lb] -> gu[ua,uc] K[lc,lb], *) + Atm[ua,lb] -> gtu[ua,uc] At[lc,lb], + + (* Matter terms *) + + (* rho = n^a n^b T_ab *) + rho -> 1/alpha^2 (T00 - 2 beta[ui] T0[li] + beta[ui] beta[uj] T[li,lj]), + + (* S_i = -p^a_i n^b T_ab, where p^a_i = delta^a_i + n^a n_i *) + S[li] -> -1/alpha (T0[li] - beta[uj] T[li,lj]), + + (* Constraints *) + + (* H -> trR - Km[ua,lb] Km[ub,la] + trK^2, *) + (* PRD 67, 084023 (2003), eqn. (19) *) + H -> trR - Atm[ua,lb] Atm[ub,la] + (2/3) trK^2 - addMatter 16 Pi rho, + + (* gK[la,lb,lc] -> CD[K[la,lb],lc], *) +(* gK[la,lb,lc] -> + 4 e4phi PD[phi,lc] At[la,lb] + e4phi CD[At[la,lb],lc] + + (1/3) g[la,lb] PD[trK,lc], + M[la] -> gu[ub,uc] (gK[lc,la,lb] - gK[lc,lb,la]), *) + + M[li] -> + gtu[uj,uk] (CDt[At[li,lj],lk] + 6 At[li,lj] cdphi[lk]) + - (2/3) PD[trK,li] + - addMatter 8 Pi S[li], + (* TODO: use PRD 67, 084023 (2003), eqn. (20) *) + + (* det gamma-tilde *) + cS -> Log[detgt], + + (* Gamma constraint *) + cXt[ua] -> gtu[ub,uc] Gt[ua,lb,lc] - Xt[ua], + + (* trace A-tilde *) + cA -> gtu[ua,ub] At[la,lb] + } +}; + +constraintsCalc1 = PartialCalculation[constraintsCalc, "1", + {}, + { + H + }]; + +constraintsCalc2 = PartialCalculation[constraintsCalc, "2", + {}, + { + M[li], + cS, + cXt[ua], + cA + }]; + +(******************************************************************************) +(* Implementations *) +(******************************************************************************) + +inheritedImplementations = + Join[{"ADMBase"}, + If [addMatter!=0, {"TmunuBase"}, {}]]; + +(******************************************************************************) +(* Parameters *) +(******************************************************************************) + +inheritedKeywordParameters = {}; + +extendedKeywordParameters = +{ + { + Name -> "ADMBase::evolution_method", + AllowedValues -> {thorn} + }, + { + Name -> "ADMBase::lapse_evolution_method", + AllowedValues -> {thorn} + }, + { + Name -> "ADMBase::shift_evolution_method", + AllowedValues -> {thorn} + }, + { + Name -> "ADMBase::dtlapse_evolution_method", + AllowedValues -> {thorn} + }, + { + Name -> "ADMBase::dtshift_evolution_method", + AllowedValues -> {thorn} + } +}; + +keywordParameters = +{ + { + Name -> "my_initial_data", + (* Visibility -> "restricted", *) + (* Description -> "ddd", *) + AllowedValues -> {"ADMBase", "Minkowski"}, + Default -> "ADMBase" + }, + { + Name -> "my_initial_boundary_condition", + Visibility -> "restricted", + (* Description -> "ddd", *) + AllowedValues -> {"none"}, + Default -> "none" + }, + { + Name -> "my_rhs_boundary_condition", + Visibility -> "restricted", + (* Description -> "ddd", *) + AllowedValues -> {"none", "static", "radiative"}, + Default -> "none" + }, + { + Name -> "my_boundary_condition", + (* Visibility -> "restricted", *) + (* Description -> "ddd", *) + AllowedValues -> {"none", "Minkowski"}, + Default -> "none" + }, + { + Name -> "calculate_ADMBase_variables_at", + Visibility -> "restricted", + (* Description -> "ddd", *) + AllowedValues -> {"MoL_PostStep", "CCTK_EVOL", "CCTK_ANALYSIS"}, + Default -> "MoL_PostStep" + }, + { + Name -> "UseSpatialBetaDriver_UNUSED", + Visibility -> "restricted", + (* Description -> "ddd", *) + AllowedValues -> {"no", "yes"}, + Default -> "no" + }, + { + Name -> "dt_lapse_shift_method", + Description -> "Treatment of ADMBase dtlapse and dtshift", + AllowedValues -> {"correct", + "noLapseShiftAdvection" (* omit lapse and shift advection terms (faster) *) + }, + Default -> "correct" + }, + { + Name -> "apply_dissipation", + Description -> "Whether to apply dissipation to the RHSs", + AllowedValues -> {"always", + "never" (* yes and no keyword values confuse Cactus, and Kranc + doesn't support boolean parameters *) + }, + Default -> "never" + }, + { + Name -> "RHS_split", + Description -> "How to split RHS calculation", + AllowedValues -> {"combined", + "split At"}, + Default -> "split At" + }, + { + Name -> "advection_split", + Description -> "How to split advection calculation", + AllowedValues -> {"combined", + "per variable"}, + Default -> "combined" + } +}; + +intParameters = +{ + { + Name -> harmonicN, + Description -> "d/dt alpha = - f alpha^n K (harmonic=2, 1+log=1)", + Default -> 2 + }, + { + Name -> ShiftAlphaPower, + Default -> 0 + }, + { + Name -> conformalMethod, + Description -> "Treatment of conformal factor", + AllowedValues -> {{Value -> "0", Description -> "phi method"}, + {Value -> "1", Description -> "W method"}}, + Default -> 0 + }, + { + Name -> fdOrder, + Default -> derivOrder, + AllowedValues -> {2,4,6,8} + }, + { + Name -> harmonicShift, + Description -> "Whether to use the harmonic shift", + AllowedValues -> {{Value -> "0", Description -> "Gamma driver shift"}, + {Value -> "1", Description -> "Harmonic shift"}}, + Default -> 0 + } +}; + +realParameters = +{ + IfCCZ4[{ + Name -> GammaShift, + Description -> "Covariant shift term in Gamma", + Default -> 0.5 + }], + IfCCZ4[{ + Name -> dampk1, + Description -> "CCZ4 damping term 1 for Theta and Z", + Default -> 0 + }], + IfCCZ4[{ + Name -> dampk2, + Description -> "CCZ4 damping term 2 for Theta and Z", + Default -> 0 + }], + { + Name -> LapseACoeff, + Description -> "Whether to evolve A in time", + Default -> 0 + }, + { + Name -> harmonicF, + Description -> "d/dt alpha = - f alpha^n K (harmonic=1, 1+log=2)", + Default -> 1 + }, + { + Name -> AlphaDriver, + Default -> 0 + }, + { + Name -> ShiftBCoeff, + Description -> "Whether to evolve B^i in time", + Default -> 1 + }, + { + Name -> ShiftGammaCoeff, + Default -> 0 + }, + { + Name -> BetaDriver, + Default -> 0 + }, + { + Name -> LapseAdvectionCoeff, + Description -> "Factor in front of the lapse advection terms in 1+log", + Default -> 1 + }, + { + Name -> ShiftAdvectionCoeff, + Description -> "Factor in front of the shift advection terms in gamma driver", + Default -> 1 + }, + { + Name -> MinimumLapse, + Description -> "Minimum value of the lapse function", + Default -> -1 + }, + { + Name -> SpatialBetaDriverRadius, + Description -> "Radius at which the BetaDriver starts to be reduced", + AllowedValues -> {{Value -> "(0:*", Description -> "Positive"}}, + Default -> 10^12 + }, + { + Name -> SpatialShiftGammaCoeffRadius, + Description -> "Radius at which the ShiftGammaCoefficient starts to be reduced", + AllowedValues -> {{Value -> "(0:*", Description -> "Positive"}}, + Default -> 10^12 + }, + { + Name -> EpsDiss, + Description -> "Dissipation strength", + AllowedValues -> {{Value -> "(0:*", Description -> "Positive"}}, + Default -> 0 + } +}; + +(******************************************************************************) +(* Construct the thorns *) +(******************************************************************************) + +calculations = +Join[ +{ + initialCalc, + convertFromADMBaseCalc, + initGammaCalc, + convertFromADMBaseGammaCalc, + evolCalc, + evolCalc1, evolCalc2, + dissCalc, + advectCalc, + (*advectCalcs,*) + initRHSCalc, + RHSStaticBoundaryCalc, + (* RHSRadiativeBoundaryCalc, *) + enforceCalc, + boundaryCalc, + convertToADMBaseCalc, + convertToADMBaseDtLapseShiftCalc, + convertToADMBaseDtLapseShiftBoundaryCalc, + convertToADMBaseFakeDtLapseShiftCalc, + (* constraintsCalc, *) + constraintsCalc1, constraintsCalc2 +}, + advectCalcs + (*dissCalcs*) +]; + +CreateKrancThornTT [groups, ".", thorn, + Calculations -> calculations, + DeclaredGroups -> declaredGroupNames, + PartialDerivatives -> derivatives, + EvolutionTimelevels -> evolutionTimelevels, + DefaultEvolutionTimelevels -> 3, + UseJacobian -> True, + UseLoopControl -> True, + UseVectors -> useVectors, + UseOpenCL -> useOpenCL, + InheritedImplementations -> inheritedImplementations, + InheritedKeywordParameters -> inheritedKeywordParameters, + ExtendedKeywordParameters -> extendedKeywordParameters, + KeywordParameters -> keywordParameters, + IntParameters -> intParameters, + RealParameters -> realParameters +]; + +]; + + + +(******************************************************************************) +(* Options *) +(******************************************************************************) + +(* These are the arguments to createComment: + - derivative order: 2, 4, 6, 8, ... + - useJacobian: False or True + - split upwind derivatives: False or True + - use vectorisation: False or True + - use OpenCL: False or True + - timelevels: 2 or 3 + (keep this at 3; this is better chosen with a run-time parameter) + - matter: 0 or 1 + (matter seems cheap; it should be always enabled) + - thorn base name +*) + +createCode[4, False, True, True , False, 3, 1, "BSSN"]; +createCode[4, False, True, False, False, 3, 1, "BSSN"]; +createCode[4, False, True, True , True , 3, 1, "BSSN"]; + +createCode[4, False, True, True , False, 3, 1, "CCZ4"]; + From e71809861e3579a680c011cac3a5eb45006149e9 Mon Sep 17 00:00:00 2001 From: Alex Johnson Date: Wed, 28 Jun 2017 17:38:48 +0530 Subject: [PATCH 384/387] OTWO-3061 Octave comments nested within mathematica When octave comments were nested within mathematica comments, the parser incorrectly detected the file as Octave. To fix this we moved around an If/Else block which placed mathematica at the bottom of the conditional. We have also tried adding mathematica comments within Octave comments to see if the reverse was true. We found that Octave parsing worked correctly without any further change in code. --- src/detector.c | 8 +++----- test/expected_dir/mathematica1.m | 4 ++-- test/expected_dir/octave1.m | 6 +++--- test/src_dir/mathematica1.m | 4 ++-- test/src_dir/octave1.m | 6 +++--- 5 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/detector.c b/src/detector.c index 414fea4..fa09f49 100644 --- a/src/detector.c +++ b/src/detector.c @@ -788,12 +788,10 @@ const char *disambiguate_m(SourceFile *sourcefile) { else if (objective_c_score > matlab_score && objective_c_score > mathematica_score) return LANG_OBJECTIVE_C; - else if (octave_syntax_detected) - return LANG_OCTAVE; - else if (matlab_score > mathematica_score) - return LANG_MATLAB; - else + else if (mathematica_score > matlab_score) return LANG_MATHEMATICA; + else + return octave_syntax_detected ? LANG_OCTAVE : LANG_MATLAB; } #include diff --git a/test/expected_dir/mathematica1.m b/test/expected_dir/mathematica1.m index 43fcb2a..ea293c3 100644 --- a/test/expected_dir/mathematica1.m +++ b/test/expected_dir/mathematica1.m @@ -1466,9 +1466,9 @@ mathematica comment (* These are the arguments to createComment: mathematica comment - use vectorisation: False or True mathematica comment - use OpenCL: False or True mathematica comment - timelevels: 2 or 3 -mathematica comment (keep this at 3; this is better chosen with a run-time parameter) +mathematica comment ## (keep this at 3; this is better chosen with a run-time parameter) mathematica comment - matter: 0 or 1 -mathematica comment (matter seems cheap; it should be always enabled) +mathematica comment ## (matter seems cheap; it should be always enabled) mathematica comment - thorn base name mathematica comment *) mathematica blank diff --git a/test/expected_dir/octave1.m b/test/expected_dir/octave1.m index 311ca33..73977b0 100644 --- a/test/expected_dir/octave1.m +++ b/test/expected_dir/octave1.m @@ -4,7 +4,7 @@ octave comment ## 3-clause BSD license appended to this file. octave blank octave code function varargout = toledolu(LU) -octave comment ## -*- texinfo -*- +octave comment ## (*- texinfo -*) octave comment ## @deftypefn{Function File} {[@var{L}, @var{U}, @var{P}]} = toledolu(@var{A}) octave comment ## @deftypefnx{Function File} {[@var{L}, @var{U}]} = toledolu(@var{A}) octave comment ## @deftypefnx{Function File} {@var{LUP}} = toledolu(@var{A}) @@ -20,8 +20,8 @@ octave comment ## See the help for lu for details about the other calling forms. octave comment ## octave comment ## For the algorithm, see -octave comment ## @itemize -octave comment ## @item +octave comment ## (* @itemize *) +octave comment ## (* @item *) octave comment ## Toledo, Sivan. "Locality of reference in LU decomposition with octave comment ## partial pivoting," SIAM J. of Matrix Analysis and Applications, octave comment ## v18, n4, 1997. DOI: 10.1137/S0895479896297744 diff --git a/test/src_dir/mathematica1.m b/test/src_dir/mathematica1.m index 4bec755..6cccde6 100644 --- a/test/src_dir/mathematica1.m +++ b/test/src_dir/mathematica1.m @@ -1466,9 +1466,9 @@ which is not always the case (since we don't enforce it). On - use vectorisation: False or True - use OpenCL: False or True - timelevels: 2 or 3 - (keep this at 3; this is better chosen with a run-time parameter) + ## (keep this at 3; this is better chosen with a run-time parameter) - matter: 0 or 1 - (matter seems cheap; it should be always enabled) + ## (matter seems cheap; it should be always enabled) - thorn base name *) diff --git a/test/src_dir/octave1.m b/test/src_dir/octave1.m index d72372d..4c795fb 100644 --- a/test/src_dir/octave1.m +++ b/test/src_dir/octave1.m @@ -4,7 +4,7 @@ ## 3-clause BSD license appended to this file. function varargout = toledolu(LU) - ## -*- texinfo -*- + ## (*- texinfo -*) ## @deftypefn{Function File} {[@var{L}, @var{U}, @var{P}]} = toledolu(@var{A}) ## @deftypefnx{Function File} {[@var{L}, @var{U}]} = toledolu(@var{A}) ## @deftypefnx{Function File} {@var{LUP}} = toledolu(@var{A}) @@ -20,8 +20,8 @@ ## See the help for lu for details about the other calling forms. ## ## For the algorithm, see - ## @itemize - ## @item + ## (* @itemize *) + ## (* @item *) ## Toledo, Sivan. "Locality of reference in LU decomposition with ## partial pivoting," SIAM J. of Matrix Analysis and Applications, ## v18, n4, 1997. DOI: 10.1137/S0895479896297744 From 86c728432709b84f5a65ad33822b4e661135255f Mon Sep 17 00:00:00 2001 From: Alex Johnson Date: Thu, 29 Jun 2017 16:32:14 +0530 Subject: [PATCH 385/387] OTWO-3061 Detect alternate mathematica extensions --- src/hash/extensions.gperf | 3 +++ test/unit/detector_test.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/hash/extensions.gperf b/src/hash/extensions.gperf index 0fb0e4a..fad70e7 100755 --- a/src/hash/extensions.gperf +++ b/src/hash/extensions.gperf @@ -133,6 +133,7 @@ mov, BINARY mp, LANG_METAPOST_WITH_TEX mp3, BINARY mpg, BINARY +mt, LANG_MATHEMATICA mustache, LANG_HTML mxml, LANG_MXML nix, LANG_NIX @@ -217,6 +218,8 @@ vhd, LANG_VHDL vhdl, LANG_VHDL vim, LANG_VIM wav, BINARY +wl, LANG_MATHEMATICA +wlt, LANG_MATHEMATICA xaml, LANG_XAML xls, BINARY xlw, BINARY diff --git a/test/unit/detector_test.h b/test/unit/detector_test.h index 64735a2..4719cbd 100755 --- a/test/unit/detector_test.h +++ b/test/unit/detector_test.h @@ -116,6 +116,9 @@ void test_detector_detect_polyglot() { ASSERT_DETECT(LANG_CPP, "uses_cpp_keywords.h"); ASSERT_DETECT(LANG_RUBY, "foo.rb"); ASSERT_DETECT(LANG_MAKE, "foo.mk"); + ASSERT_DETECT(LANG_MATHEMATICA, "foo.mt"); + ASSERT_DETECT(LANG_MATHEMATICA, "foo.wl"); + ASSERT_DETECT(LANG_MATHEMATICA, "foo.wlt"); ASSERT_DETECT(LANG_OBJECTIVE_C, "foo_objective_c.h"); ASSERT_DETECT(LANG_PHP, "upper_case_php"); ASSERT_DETECT(LANG_SMALLTALK, "example.st"); From 5019d25103fbcecc4661fa2bb6e515db7d5ca0a9 Mon Sep 17 00:00:00 2001 From: Alex Johnson Date: Wed, 19 Jul 2017 13:44:05 +0530 Subject: [PATCH 386/387] OTWO-3080 Fix ampl comment parsing The existing parser counts multiline ampl comments as code. Added parser tests. --- src/parsers/ampl.rl | 16 ++++++++++++++-- test/expected_dir/ampl.mod | 7 +++++++ test/src_dir/ampl.mod | 7 +++++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 test/expected_dir/ampl.mod create mode 100644 test/src_dir/ampl.mod diff --git a/src/parsers/ampl.rl b/src/parsers/ampl.rl index 6a92d3a..4b4bd17 100644 --- a/src/parsers/ampl.rl +++ b/src/parsers/ampl.rl @@ -44,7 +44,16 @@ enum { } } - ampl_comment = '#' @comment nonnewline*; + ampl_line_comment = '#' @comment nonnewline*; + ampl_block_comment = + '/*' @comment ( + newline %{ entity = INTERNAL_NL; } %ampl_ccallback + | + ws + | + (nonnewline - ws) @comment + )* :>> '*/'; + ampl_comment = ampl_line_comment | ampl_block_comment; ampl_line := |* spaces ${ entity = AMPL_SPACE; } => ampl_ccallback; @@ -59,7 +68,10 @@ enum { callback(AMPL_LANG, ampl_entities[entity], cint(ts), cint(te), userdata); } - ampl_comment_entity = '#' nonnewline*; + ampl_line_comment_entity = '#' nonnewline*; + ampl_block_comment_entity = '/*' any* :>> '*/'; + ampl_comment_entity = + ampl_line_comment_entity | ampl_block_comment_entity; ampl_entity := |* space+ ${ entity = AMPL_SPACE; } => ampl_ecallback; diff --git a/test/expected_dir/ampl.mod b/test/expected_dir/ampl.mod new file mode 100644 index 0000000..3afde0d --- /dev/null +++ b/test/expected_dir/ampl.mod @@ -0,0 +1,7 @@ +ampl comment /* This is a test file for AMPL +ampl comment * This is a multiline comment +ampl comment */ +ampl blank +ampl comment # An AMPL model +ampl code var x >= 42; # variable definition. +ampl code minimize o: x; diff --git a/test/src_dir/ampl.mod b/test/src_dir/ampl.mod new file mode 100644 index 0000000..24ac1b5 --- /dev/null +++ b/test/src_dir/ampl.mod @@ -0,0 +1,7 @@ +/* This is a test file for AMPL + * This is a multiline comment + */ + +# An AMPL model +var x >= 42; # variable definition. +minimize o: x; From 04c54a412c9ec25c10cd58957ba3fe749a898bbd Mon Sep 17 00:00:00 2001 From: Daniel Rubio Date: Tue, 8 Aug 2017 16:46:24 -0400 Subject: [PATCH 387/387] Add updated packages to README.md for build compilation --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 45ed563..f4b477e 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ language detection features from a Ruby application. System Requirements ------------------- -Ohcount is supported on Ubuntu 12.04 LTS. Other Linux +Ohcount is supported on Ubuntu 14.04 LTS. Other Linux environments should also work, but your mileage may vary. Ohcount does not support Windows. @@ -63,7 +63,7 @@ Ohcount source code is available as a Git repository: Building Ohcount ---------------- -You will need ragel 6.8 or higher, bash, pcre, magic, gcc (version 4.8.2 or greater) +You will need ragel 6.8 or higher, bash, gperf, libpcre3-dev, libmagic-dev, gcc (version 4.8.2 or greater) and SWIG (2.0.11). Once you have them, go to the top directory of ohcount and run ```

    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