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 +22 -0
- data/.gitignore +7 -0
- data/{History.txt → ChangeLog} +11 -0
- data/Gemfile +1 -9
- data/README.rdoc +38 -39
- data/Rakefile +4 -2
- data/VERSION +1 -1
- data/bin/pidgin2adium +63 -54
- data/ext/balance_tags_c/balance_tags_c.c +161 -161
- data/lib/pidgin2adium.rb +97 -97
- data/lib/pidgin2adium/balance_tags.rb +2 -2
- data/lib/pidgin2adium/basic_parser.rb +412 -0
- data/lib/pidgin2adium/html_log_parser.rb +125 -0
- data/lib/pidgin2adium/log_converter.rb +12 -13
- data/lib/pidgin2adium/log_file.rb +1 -1
- data/lib/pidgin2adium/log_parser.rb +3 -618
- data/lib/pidgin2adium/message.rb +97 -0
- data/lib/pidgin2adium/text_log_parser.rb +39 -0
- data/pidgin2adium.gemspec +31 -9
- data/spec/balance_tags_c_extn_spec.rb +47 -0
- data/spec/basic_parser_spec.rb +217 -0
- data/spec/html_log_parser_spec.rb +150 -0
- data/spec/log_converter_spec.rb +48 -0
- data/spec/log_file_spec.rb +168 -0
- data/spec/logfiles/2006-12-21.223606.txt +3 -0
- data/spec/logfiles/2008-01-15.071445-0500PST.htm +5 -0
- data/spec/logfiles/2008-01-15.071445-0500PST.html +5 -0
- data/spec/pidgin2adium_spec.rb +248 -3
- data/spec/spec_helper.rb +69 -16
- data/spec/test-output/README.md +1 -0
- data/spec/test-output/html_log_output.xml +6 -0
- data/spec/test-output/text_log_output.xml +4 -0
- data/spec/text_log_parser_spec.rb +42 -0
- data/tasks/extconf/balance_tags_c.rake +5 -1
- metadata +40 -26
- data/bin/pidgin2adium_profiler +0 -1
- data/tasks/build_profiler.rake +0 -49
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
data/{History.txt → ChangeLog}
RENAMED
@@ -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
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
|
-
|
46
|
+
puts "Oh no! Could not parse!"
|
47
47
|
else
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
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.
|
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
|
+
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
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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
|
-
|
65
|
+
oparser.parse!
|
59
66
|
rescue => bang
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
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
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
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
|
-
|
85
|
-
|
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
|
-
|
99
|
+
extra_opts[:output_dir] = options[:output_dir]
|
91
100
|
end
|
92
101
|
|
93
102
|
log_converter = Pidgin2Adium::LogConverter.new(options[:in],
|
94
|
-
|
95
|
-
|
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
|
-
|
32
|
-
|
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("<\\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
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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("<\\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
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
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
|
-
|
197
|
-
|
196
|
+
mP2A = rb_define_module("Pidgin2Adium");
|
197
|
+
rb_define_module_function(mP2A, "balance_tags_c", balance_tags_c, 1);
|
198
198
|
}
|