pidgin2adium 3.0.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.autotest CHANGED
@@ -1,4 +1,26 @@
1
+ require 'autotest/growl'
2
+ require 'autotest/fsevent'
3
+
1
4
  Autotest.add_hook :initialize do |at|
5
+ # Modifying ext/balance_tags_c.c triggers spec/balance_tags_c_extn_spec.rb
6
+ at.add_mapping(/ext\/.*\/(.*)\.[ch]/) do |_, m|
7
+ ["spec/#{m[1]}_extn_spec.rb"]
8
+ end
9
+
10
+ at.add_mapping(%r{lib/pidgin2adium.rb}) do |_, m|
11
+ ["spec/pidgin2adium_spec.rb"]
12
+ end
13
+
14
+ at.add_mapping(%r{lib/pidgin2adium/(.+_log_parser).rb}) do |_, m|
15
+ ["spec/#{m[1]}_spec.rb"]
16
+ end
17
+
18
+ # Re-run spec files when they change
19
+ at.add_mapping(%r{^spec/.+_spec.rb$}) do |filename, _|
20
+ filename
21
+ end
22
+
23
+ at.libs = %w{. lib spec}
2
24
  end
3
25
 
4
26
  Autotest.add_hook :run_command do |at|
data/.gitignore CHANGED
@@ -20,3 +20,10 @@ pkg
20
20
 
21
21
  ## PROJECT::SPECIFIC
22
22
  .bundle
23
+ ext/balance_tags_c/Makefile
24
+ ext/balance_tags_c/balance_tags_c.bundle
25
+ ext/balance_tags_c/balance_tags_c.o
26
+ .rvmrc
27
+ spec/output-dir
28
+ spec/nonexistent_output_dir
29
+ Gemfile.lock
@@ -1,3 +1,14 @@
1
+ === 3.1.0 / 2010-08-13
2
+ * Compatible with Ruby 1.9!
3
+ - removed dependency on "parsedate" library, which 1.9 doesn't have
4
+ * log_parser.rb has been split into separate files (1 per class, more or less)
5
+ - "require pidgin2adium/log_parser" will still pull in all of the split-up
6
+ classes
7
+ * balance_tags_c extension really does work now
8
+ * Cleans up more junk from Pidgin logfiles when parsing
9
+ * Bugfixes and more graceful handling of error states
10
+ * Fully tested (except bin/pidgin2adium, which remains tricky)
11
+
1
12
  === 3.0.1 / 2010-08-07
2
13
  Bugfix release:
3
14
  * balance_tags_c.c: Use rb_eval_string instead of rb_reg_regcomp to avoid
data/Gemfile CHANGED
@@ -1,11 +1,3 @@
1
1
  source 'http://gemcutter.org'
2
2
 
3
- group :runtime do
4
- gem "rake"
5
- end
6
-
7
- group :development do
8
- gem "bundler", ">= 0.9.26"
9
- gem "jeweler"
10
- gem "rspec", ">= 1.2.9"
11
- end
3
+ gemspec :path => '.'
data/README.rdoc CHANGED
@@ -43,47 +43,46 @@ The library style allows you to parse a log file and get back a LogFile[link:cla
43
43
  require 'pidgin2adium'
44
44
  logfile = Pidgin2Adium.parse("/path/to/log/file.html", "gabe,gbw,gabeb-w")
45
45
  if logfile == false
46
- puts "Oh no! Could not parse!"
46
+ puts "Oh no! Could not parse!"
47
47
  else
48
- logfile.each do |message|
49
- # Every message has these properties
50
- puts "Sender's screen name: #{message.sender}"
51
- puts "Time message was sent: #{message.time}"
52
- puts "Sender's alias: #{message.buddy_alias}"
53
- if [Pidgin2Adium::XMLMessage, Pidgin2Adium::AutoReplyMessage, Pidgin2Adium::Event].include?(message.class)
54
- # All of these have a body
55
- puts "Message body: #{message.body}"
56
- if message.class == Pidgin2Adium::Event
57
- puts "Event type: #{message.event_type}"
58
- end
59
- elsif message.class == Pidgin2Adium::StatusMessage
60
- # Only StatusMessage has status
61
- puts "Status: #{message.status}"
62
- end
63
- # Prints out the message in Adium log format
64
- puts message.to_s
48
+ logfile.each do |message|
49
+ # Every Message subclass has sender, time, and buddy_alias
50
+ puts "Sender's screen name: #{message.sender}"
51
+ puts "Time message was sent: #{message.time}"
52
+ puts "Sender's alias: #{message.buddy_alias}"
53
+ if message.respond_to?(:body)
54
+ puts "Message body: #{message.body}"
55
+ if message.respond_to?(:event) # Pidgin2Adium::Event class
56
+ puts "Event type: #{message.event_type}"
57
+ end
58
+ elsif message.respond_to?(:status) # Pidgin2Adium::StatusMessage
59
+ puts "Status: #{message.status}"
65
60
  end
66
- success = logfile.write_out()
67
- # To overwrite file if it exists:
68
- # logfile.write_out(overwrite = true)
69
- # To specify your own output dir (default = Pidgin2Adium::ADIUM_LOG_DIR):
70
- # logfile.write_out(false, output_dir = my_dir)
71
- # Or combine them:
72
- # logfile.write_out(true, my_dir)
73
- if success == false
74
- puts "An error occurred!"
75
- elsif success == Pidgin2Adium::FILE_EXISTS
76
- # Not returned if overwrite set to true
77
- puts "File already exists."
78
- else
79
- puts "Successfully wrote out log file!"
80
- puts "Path to output file: #{success}"
81
- end
82
- # This deletes search indexes so Adium re-indexes the new chat logs.
83
- # It is not automatically called after log_file.write_out()
84
- # Call it after converting all the logs, since it takes up a bit of
85
- # processing power.
86
- Pidgin2Adium.delete_search_indexes()
61
+ # Prints out the message in Adium log format
62
+ puts message.to_s
63
+ end
64
+
65
+ success = logfile.write_out()
66
+ # To overwrite file if it exists:
67
+ # logfile.write_out(overwrite = true)
68
+ # To specify your own output dir (default = Pidgin2Adium::ADIUM_LOG_DIR):
69
+ # logfile.write_out(false, output_dir = my_dir)
70
+ # Or combine them:
71
+ # logfile.write_out(true, my_dir)
72
+ if success == false
73
+ puts "An error occurred!"
74
+ elsif success == Pidgin2Adium::FILE_EXISTS
75
+ # Not returned if overwrite set to true
76
+ puts "File already exists."
77
+ else
78
+ puts "Successfully wrote out log file!"
79
+ puts "Path to output file: #{success}"
80
+ end
81
+ # This deletes search indexes so Adium re-indexes the new chat logs.
82
+ # It is not automatically called after log_file.write_out()
83
+ # Call it after converting all the logs, since it takes up a bit of
84
+ # processing power.
85
+ Pidgin2Adium.delete_search_indexes()
87
86
  end
88
87
 
89
88
  ===Example 2 (using library)
data/Rakefile CHANGED
@@ -1,6 +1,5 @@
1
1
  require 'rubygems'
2
2
  require 'rake'
3
- require 'bundler'
4
3
 
5
4
  begin
6
5
  require 'jeweler'
@@ -12,7 +11,9 @@ begin
12
11
  gem.homepage = "http://github.com/gabebw/pidgin2adium"
13
12
  gem.authors = ["Gabe Berke-Williams"]
14
13
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
- gem.add_bundler_dependencies
14
+ gem.add_development_dependency(%q<bundler>, [">= 0.9.26"])
15
+ gem.add_development_dependency(%q<jeweler>, [">= 0"])
16
+ gem.add_development_dependency(%q<rspec>, [">= 1.2.9"])
16
17
  end
17
18
  Jeweler::GemcutterTasks.new
18
19
  rescue LoadError
@@ -52,6 +53,7 @@ rescue Gem::LoadError
52
53
  end
53
54
 
54
55
  task :spec => :check_dependencies
56
+ task :spec => "extconf:compile"
55
57
 
56
58
  task :default => :spec
57
59
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.0.1
1
+ 3.1.0
data/bin/pidgin2adium CHANGED
@@ -21,76 +21,85 @@ Written by Gabe Berke-Williams (gbw@rubyforge.org)
21
21
  EOL
22
22
 
23
23
  options = {}
24
+
24
25
  oparser = OptionParser.new do |opts|
25
- opts.banner = "Usage: #{File.basename($0)} [options]"
26
- opts.on('-i', '--in=IN_DIR', String, 'Directory where pidgin logs are stored') do |i|
27
- options[:in] = i
28
- end
29
- opts.on('-a alias1,alias2', "--aliases alias1,alias2",
30
- "A comma-separated list of your alias(es)",
31
- "so this script knows which person in a chat",
32
- "is you. Whitespace and case do not matter.") do |aliases|
33
- options[:aliases] = aliases
34
- end
35
- opts.on('-o', '--out OUT_DIR',
36
- 'The top-level directory under which to',
37
- 'store the logs (each in its own folder',
38
- 'by screen name).',
39
- "Defaults to: #{Pidgin2Adium::ADIUM_LOG_DIR}") do |out|
40
- options[:output_dir] = out
41
- end
42
- opts.on('-f', '--force', 'If this is set, then logs in the Adium log',
43
- 'folder that have the same name as converted',
44
- 'logs will be overwritten.') do |f|
45
- options[:force] = f
46
- end
47
- opts.on("-v", "--version", "Show version information") do
48
- puts version
49
- exit
50
- end
51
- opts.on_tail("-h", "--help", "Show this message") do
52
- puts version
53
- puts opts
54
- exit
55
- end
26
+ opts.banner = "Usage: #{File.basename($0)} [options]"
27
+ opts.on('-i', '--in=IN_DIR', String, 'Directory where pidgin logs are stored') do |i|
28
+ options[:in] = i
29
+ end
30
+
31
+ opts.on('-a alias1,alias2', "--aliases alias1,alias2",
32
+ "A comma-separated list of your alias(es)",
33
+ "so this script knows which person in a chat",
34
+ "is you. Whitespace and case do not matter.") do |aliases|
35
+ options[:aliases] = aliases
36
+ end
37
+
38
+ opts.on('-o', '--out OUT_DIR',
39
+ 'The top-level directory under which to',
40
+ 'store the logs (each in its own folder',
41
+ 'by screen name).',
42
+ "Defaults to: #{Pidgin2Adium::ADIUM_LOG_DIR}") do |out|
43
+ options[:output_dir] = out
44
+ end
45
+
46
+ opts.on('-f', '--force', 'If this is set, then logs in the Adium log',
47
+ 'folder that have the same name as converted',
48
+ 'logs will be overwritten.') do |f|
49
+ options[:force] = f
50
+ end
51
+
52
+ opts.on("-v", "--version", "Show version information") do
53
+ puts version
54
+ exit
55
+ end
56
+
57
+ opts.on_tail("-h", "--help", "Show this message") do
58
+ puts version
59
+ puts opts
60
+ exit
61
+ end
56
62
  end
63
+
57
64
  begin
58
- oparser.parse!
65
+ oparser.parse!
59
66
  rescue => bang
60
- if bang.class == OptionParser::MissingArgument
61
- # No argument provided for a switch that requires an argument.
62
- puts '"%s" requires an argument.' % bang.args[0]
63
- exit 1
64
- elsif bang.class == OptionParser::InvalidOption
65
- # Provided a switch that we don't handle.
66
- puts '"%s" is not a valid switch.' % bang.args[0]
67
- elsif bang.class == OptionParser::NeedlessArgument
68
- # Raised when argument provided for a switch that doesn't take an argument.
69
- puts bang.message
70
- end
67
+ if bang.class == OptionParser::MissingArgument
68
+ # No argument provided for a switch that requires an argument.
69
+ puts '"%s" requires an argument.' % bang.args[0]
70
+ exit 1
71
+ elsif bang.class == OptionParser::InvalidOption
72
+ # Provided a switch that we don't handle.
73
+ puts '"%s" is not a valid switch.' % bang.args[0]
74
+ elsif bang.class == OptionParser::NeedlessArgument
75
+ # Raised when argument provided for a switch that doesn't take an argument.
76
+ puts bang.message
77
+ end
71
78
  end
72
79
 
73
80
  need_opts = false
74
81
  required_opts = [[:i, :in], [:a, :aliases]]
82
+
75
83
  required_opts.each do |short, long|
76
- if options.has_key?(long)
77
- next
78
- else
79
- need_opts = true
80
- puts "Required option -#{short}/--#{long} missing."
81
- end
84
+ if options.has_key?(long)
85
+ next
86
+ else
87
+ need_opts = true
88
+ puts "Required option -#{short}/--#{long} missing."
89
+ end
82
90
  end
91
+
83
92
  if need_opts
84
- puts oparser.to_s
85
- exit 1
93
+ puts oparser.to_s
94
+ exit 1
86
95
  end
87
96
 
88
97
  extra_opts = {:overwrite => options[:force]}
89
98
  if options.has_key?(:output_dir)
90
- extra_opts[:output_dir] = options[:output_dir]
99
+ extra_opts[:output_dir] = options[:output_dir]
91
100
  end
92
101
 
93
102
  log_converter = Pidgin2Adium::LogConverter.new(options[:in],
94
- options[:aliases],
95
- extra_opts)
103
+ options[:aliases],
104
+ extra_opts)
96
105
  log_converter.start
@@ -28,171 +28,171 @@ static VALUE mP2A;
28
28
  * Balances tags of _text_. Returns modified text.
29
29
  */
30
30
  VALUE balance_tags_c(VALUE mod, VALUE text){
31
- if( TYPE(text) != T_STRING ){
32
- rb_raise(rb_eArgError, "bad argument to balance_tags_c, String only please.");
31
+ if( TYPE(text) != T_STRING ){
32
+ rb_raise(rb_eArgError, "bad argument to balance_tags_c, String only please.");
33
+ }
34
+ VALUE tagstack = rb_ary_new2(1);
35
+ int stacksize = 0;
36
+ VALUE tagqueue = rb_str_new2("");
37
+ VALUE ZERO = INT2FIX(0),
38
+ ONE = INT2FIX(1);
39
+ VALUE newtext = rb_str_new2("");
40
+ // Known single-entity/self-closing tags
41
+ VALUE single_tags = rb_ary_new3(5,
42
+ rb_str_new2("br"),
43
+ rb_str_new2("hr"),
44
+ rb_str_new2("img"),
45
+ rb_str_new2("input"),
46
+ rb_str_new2("meta"));
47
+ // Tags that can be immediately nested within themselves
48
+ VALUE nestable_tags = rb_ary_new3(4,
49
+ rb_str_new2("blockquote"),
50
+ rb_str_new2("div"),
51
+ rb_str_new2("span"),
52
+ rb_str_new2("font"));
53
+ // 1: tagname, with possible leading "/"
54
+ // 2: attributes
55
+ VALUE tag_regex = rb_eval_string("/<(\\/?\\w*)\\s*([^>]*)>/");
56
+ VALUE pos; // position in text
57
+ VALUE match;
58
+ VALUE tag;
59
+ VALUE attributes;
60
+ VALUE t; // loop variable when iterating over tagstack at end of while loop
61
+ int matchlen;
62
+ int done = 0;
63
+ int j, k, i; // loop counters
64
+
65
+ // WP bug fix for comments - in case you REALLY meant to type '< !--'
66
+ rb_funcall(text, rb_intern("gsub!"), 2,
67
+ rb_str_new2("< !--"),
68
+ rb_str_new2("< !--"));
69
+
70
+ // WP bug fix for LOVE <3 (and other situations with '<' before a number)
71
+ rb_funcall(text,rb_intern("gsub!"), 2,
72
+ rb_eval_string("/<([0-9]{1})/"),
73
+ rb_str_new2("&lt;\\1"));
74
+
75
+ pos = rb_funcall(text, rb_intern("=~"), 1, tag_regex);
76
+ done = (pos == Qnil);
77
+ while ( ! done ){
78
+ rb_str_concat(newtext, tagqueue);
79
+ match = rb_funcall(text, rb_intern("match"), 1, tag_regex);
80
+ tag = rb_funcall(rb_reg_nth_match(1, match), rb_intern("downcase"), 0);
81
+ attributes = rb_reg_nth_match(2, match);
82
+
83
+ matchlen = NUM2INT(rb_funcall(rb_reg_nth_match(0, match), rb_intern("size"), 0));
84
+
85
+ // clear the shifter
86
+ tagqueue = rb_str_new2("");
87
+ // Pop or Push
88
+ if (0 == rb_str_cmp(rb_str_substr(tag, 0, 1), rb_str_new2("/"))){ // End Tag
89
+ rb_funcall(tag, rb_intern("slice!"), 2, ZERO, ONE);
90
+ // if too many closing tags
91
+ if(stacksize <= 0){
92
+ tag = rb_str_new2("");
93
+ //or close to be safe: tag = '/' << tag
94
+ } else if (0 == rb_str_cmp(RARRAY_PTR(tagstack)[stacksize - 1], tag)){
95
+ // found closing tag
96
+ // if stacktop value == tag close value then pop
97
+ // Close Tag
98
+ tag = rb_str_append(rb_str_new2("</"), tag);
99
+ rb_str_concat(tag, rb_str_new2(">"));
100
+ // Pop
101
+ rb_ary_pop(tagstack);
102
+ stacksize--;
103
+ } else { // closing tag not at top, search for it
104
+ for(j=stacksize-1; j>=0; j--){
105
+ if(0 == rb_str_cmp(RARRAY_PTR(tagstack)[j], tag) ){
106
+ // add tag to tagqueue
107
+ for(k = stacksize-1;k>=j;k--){
108
+ rb_str_concat(tagqueue, rb_str_new2("</"));
109
+ rb_str_concat(tagqueue, rb_ary_pop(tagstack));
110
+ rb_str_concat(tagqueue, rb_str_new2(">"));
111
+ stacksize--;
112
+ }
113
+ break;
114
+ }
115
+ }
116
+ tag = rb_str_new2("");
117
+ }
118
+ } else {
119
+ // Begin Tag
120
+
121
+ // Tag Cleaning
122
+
123
+ if( ( RSTRING_LEN(attributes) > 0 && // test length before rb_str_substr
124
+ (0 == rb_str_cmp(rb_str_substr(attributes, -1, 1), rb_str_new2("/"))) ) ||
125
+ (0 == rb_str_cmp(tag, rb_str_new2(""))) ){
126
+ // If: self-closing or '', don't do anything.
127
+ } else if ( rb_ary_includes(single_tags, tag) ) {
128
+ // ElseIf: it's a known single-entity tag but it doesn't close itself, do so
129
+ rb_str_concat(attributes, rb_str_new2("/"));
130
+ } else {
131
+ // Push the tag onto the stack
132
+ // If the top of the stack is the same as the tag we want
133
+ // to push, close previous tag
134
+ if ( (stacksize > 0) &&
135
+ (Qfalse == rb_ary_includes(nestable_tags, tag)) &&
136
+ (0 == rb_str_cmp(rb_ary_entry(tagstack, stacksize - 1), tag))){
137
+ tagqueue = rb_str_new2("</");
138
+ rb_str_concat(tagqueue, rb_ary_pop(tagstack));
139
+ rb_str_concat(tagqueue, rb_str_new2(">"));
140
+ stacksize--;
141
+ }
142
+ rb_ary_push(tagstack, tag);
143
+ stacksize++;
144
+ }
145
+
146
+ // Attributes
147
+ if( 0 != rb_str_cmp(attributes, rb_str_new2("")) ){
148
+ attributes = rb_str_plus(rb_str_new2(" "), attributes);
149
+ }
150
+ tag = rb_str_plus(rb_str_new2("<"), tag);
151
+ rb_str_concat(tag, attributes);
152
+ rb_str_concat(tag, rb_str_new2(">"));
153
+ //If already queuing a close tag, then put this tag on, too
154
+ if( RSTRING_LEN(tagqueue) > 0 ){
155
+ rb_str_concat(tagqueue, tag);
156
+ tag = rb_str_new2("");
157
+ }
33
158
  }
34
- VALUE tagstack = rb_ary_new2(1);
35
- int stacksize = 0;
36
- VALUE tagqueue = rb_str_new2("");
37
- VALUE ZERO = INT2FIX(0),
38
- ONE = INT2FIX(1);
39
- VALUE newtext = rb_str_new2("");
40
- // Known single-entity/self-closing tags
41
- VALUE single_tags = rb_ary_new3(5,
42
- rb_str_new2("br"),
43
- rb_str_new2("hr"),
44
- rb_str_new2("img"),
45
- rb_str_new2("input"),
46
- rb_str_new2("meta"));
47
- // Tags that can be immediately nested within themselves
48
- VALUE nestable_tags = rb_ary_new3(4,
49
- rb_str_new2("blockquote"),
50
- rb_str_new2("div"),
51
- rb_str_new2("span"),
52
- rb_str_new2("font"));
53
- // 1: tagname, with possible leading "/"
54
- // 2: attributes
55
- VALUE tag_regex = rb_eval_string("/<(\\/?\\w*)\\s*([^>]*)>/");
56
- VALUE pos; // position in text
57
- VALUE match;
58
- VALUE tag;
59
- VALUE attributes;
60
- VALUE t; // loop variable when iterating over tagstack at end of while loop
61
- int matchlen;
62
- int done = 0;
63
- int j, k, i; // loop counters
64
-
65
- // WP bug fix for comments - in case you REALLY meant to type '< !--'
66
- rb_funcall(text, rb_intern("gsub!"), 2,
67
- rb_str_new2("< !--"),
68
- rb_str_new2("< !--"));
69
-
70
- // WP bug fix for LOVE <3 (and other situations with '<' before a number)
71
- rb_funcall(text,rb_intern("gsub!"), 2,
72
- rb_eval_string("/<([0-9]{1})/"),
73
- rb_str_new2("&lt;\\1"));
74
-
159
+ rb_str_concat(newtext,
160
+ rb_str_plus(rb_str_substr(text, 0, NUM2INT(pos)), tag));
161
+ text = rb_str_substr(text,
162
+ NUM2INT(pos)+matchlen,
163
+ RSTRING_LEN(text) - (NUM2INT(pos)+matchlen));
75
164
  pos = rb_funcall(text, rb_intern("=~"), 1, tag_regex);
76
165
  done = (pos == Qnil);
77
- while ( ! done ){
78
- rb_str_concat(newtext, tagqueue);
79
- match = rb_funcall(text, rb_intern("match"), 1, tag_regex);
80
- tag = rb_funcall(rb_reg_nth_match(1, match), rb_intern("downcase"), 0);
81
- attributes = rb_reg_nth_match(2, match);
82
-
83
- matchlen = NUM2INT(rb_funcall(rb_reg_nth_match(0, match), rb_intern("size"), 0));
84
-
85
- // clear the shifter
86
- tagqueue = rb_str_new2("");
87
- // Pop or Push
88
- if (0 == rb_str_cmp(rb_str_substr(tag, 0, 1), rb_str_new2("/"))){ // End Tag
89
- rb_funcall(tag, rb_intern("slice!"), 2, ZERO, ONE);
90
- // if too many closing tags
91
- if(stacksize <= 0){
92
- tag = rb_str_new2("");
93
- //or close to be safe: tag = '/' << tag
94
- } else if (0 == rb_str_cmp(RARRAY_PTR(tagstack)[stacksize - 1], tag)){
95
- // found closing tag
96
- // if stacktop value == tag close value then pop
97
- // Close Tag
98
- tag = rb_str_append(rb_str_new2("</"), tag);
99
- rb_str_concat(tag, rb_str_new2(">"));
100
- // Pop
101
- rb_ary_pop(tagstack);
102
- stacksize--;
103
- } else { // closing tag not at top, search for it
104
- for(j=stacksize-1; j>=0; j--){
105
- if(0 == rb_str_cmp(RARRAY_PTR(tagstack)[j], tag) ){
106
- // add tag to tagqueue
107
- for(k = stacksize-1;k>=j;k--){
108
- rb_str_concat(tagqueue, rb_str_new2("</"));
109
- rb_str_concat(tagqueue, rb_ary_pop(tagstack));
110
- rb_str_concat(tagqueue, rb_str_new2(">"));
111
- stacksize--;
112
- }
113
- break;
114
- }
115
- }
116
- tag = rb_str_new2("");
117
- }
118
- } else {
119
- // Begin Tag
120
-
121
- // Tag Cleaning
122
-
123
- if( ( RSTRING_LEN(attributes) > 0 && // test length before rb_str_substr
124
- (0 == rb_str_cmp(rb_str_substr(attributes, -1, 1), rb_str_new2("/"))) ) ||
125
- (0 == rb_str_cmp(tag, rb_str_new2(""))) ){
126
- // If: self-closing or '', don't do anything.
127
- } else if ( rb_ary_includes(single_tags, tag) ) {
128
- // ElseIf: it's a known single-entity tag but it doesn't close itself, do so
129
- rb_str_concat(attributes, rb_str_new2("/"));
130
- } else {
131
- // Push the tag onto the stack
132
- // If the top of the stack is the same as the tag we want
133
- // to push, close previous tag
134
- if ( (stacksize > 0) &&
135
- (Qfalse == rb_ary_includes(nestable_tags, tag)) &&
136
- (0 == rb_str_cmp(rb_ary_entry(tagstack, stacksize - 1), tag))){
137
- tagqueue = rb_str_new2("</");
138
- rb_str_concat(tagqueue, rb_ary_pop(tagstack));
139
- rb_str_concat(tagqueue, rb_str_new2(">"));
140
- stacksize--;
141
- }
142
- rb_ary_push(tagstack, tag);
143
- stacksize++;
144
- }
145
-
146
- // Attributes
147
- if( 0 != rb_str_cmp(attributes, rb_str_new2("")) ){
148
- attributes = rb_str_plus(rb_str_new2(" "), attributes);
149
- }
150
- tag = rb_str_plus(rb_str_new2("<"), tag);
151
- rb_str_concat(tag, attributes);
152
- rb_str_concat(tag, rb_str_new2(">"));
153
- //If already queuing a close tag, then put this tag on, too
154
- if( RSTRING_LEN(tagqueue) > 0 ){
155
- rb_str_concat(tagqueue, tag);
156
- tag = rb_str_new2("");
157
- }
158
- }
159
- rb_str_concat(newtext,
160
- rb_str_plus(rb_str_substr(text, 0, pos-1), tag));
161
- text = rb_str_substr(text,
162
- NUM2INT(pos)+matchlen,
163
- RSTRING_LEN(text) - (NUM2INT(pos)+matchlen));
164
- pos = rb_funcall(text, rb_intern("=~"), 1, tag_regex);
165
- done = (pos == Qnil);
166
- }
167
-
168
- // Clear Tag Queue
169
- rb_str_concat(newtext, tagqueue);
170
-
171
- // Add Remaining text
172
- rb_str_concat(newtext, text);
173
-
174
- i = NUM2INT(rb_funcall(tagstack, rb_intern("length"), 0)) - 1;
175
- // Empty Stack
176
- for(; i >= 0; i--){
177
- // Add remaining tags to close
178
- t = RARRAY_PTR(tagstack)[i];
179
- rb_str_concat(newtext, rb_str_new2("</"));
180
- rb_str_concat(newtext, t);
181
- rb_str_concat(newtext, rb_str_new2(">"));
182
- }
183
-
184
- // WP fix for the bug with HTML comments
185
- rb_funcall(newtext, rb_intern("gsub!"), 2,
186
- rb_str_new2("< !--"),
187
- rb_str_new2("<!--"));
188
- rb_funcall(newtext, rb_intern("gsub!"), 2,
189
- rb_str_new2("< !--"),
190
- rb_str_new2("< !--"));
191
-
192
- return newtext;
166
+ }
167
+
168
+ // Clear Tag Queue
169
+ rb_str_concat(newtext, tagqueue);
170
+
171
+ // Add Remaining text
172
+ rb_str_concat(newtext, text);
173
+
174
+ i = NUM2INT(rb_funcall(tagstack, rb_intern("length"), 0)) - 1;
175
+ // Empty Stack
176
+ for(; i >= 0; i--){
177
+ // Add remaining tags to close
178
+ t = RARRAY_PTR(tagstack)[i];
179
+ rb_str_concat(newtext, rb_str_new2("</"));
180
+ rb_str_concat(newtext, t);
181
+ rb_str_concat(newtext, rb_str_new2(">"));
182
+ }
183
+
184
+ // WP fix for the bug with HTML comments
185
+ rb_funcall(newtext, rb_intern("gsub!"), 2,
186
+ rb_str_new2("< !--"),
187
+ rb_str_new2("<!--"));
188
+ rb_funcall(newtext, rb_intern("gsub!"), 2,
189
+ rb_str_new2("< !--"),
190
+ rb_str_new2("< !--"));
191
+
192
+ return newtext;
193
193
  }
194
194
 
195
195
  void Init_balance_tags_c(){
196
- mP2A = rb_define_module("Pidgin2Adium");
197
- rb_define_module_function(mP2A, "balance_tags_c", balance_tags_c, 1);
196
+ mP2A = rb_define_module("Pidgin2Adium");
197
+ rb_define_module_function(mP2A, "balance_tags_c", balance_tags_c, 1);
198
198
  }