pidgin2adium 3.0.1 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
  }