breakout_parser 0.0.23 → 0.0.31

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.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YTU3NTk2NGQ1ZTEyMjFlOTFiYmI4NDY0ZDIzOWFkNzRiMTFiNTdiYQ==
5
+ data.tar.gz: !binary |-
6
+ OGMwYTA0YjBiOTI2MDZmODc2M2NkYjk2OTQzN2QzMWI0NTg4OTlmMQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MjIzYjUyMzE3ZTE3MWIxMDIxMzgzMmJhYWI1ZTk0ZmQyZGQ1YmU5NDFhMzdm
10
+ NWUxODM5MzhmZTg0YjEzODg5MGFkMWFiODE0ZDgzN2EyYTY5ZTk5MTBhMTA3
11
+ Zjk2NzJhYzM4YzI4NmM0ZGY3NzcwN2ZkZDczMTY1YjgyMzM0MmE=
12
+ data.tar.gz: !binary |-
13
+ Nzk1MGE5YTVlYzY4NDJjZTI4YTE0NjYxYmE4ZWRkYmRjNDJmOWExNzA5MzQ5
14
+ YjkwMDRkNTQxMWJlZDc1NGQ1ODJmYTc0ZjViZjRjZGYyYWM4NGMxYTQwZWNj
15
+ NzA5MzY0NDlmYzQ5MmY5ZjY2MjU0ZGIyMzk3ZjIwNDA2MDBmZTk=
data/ChangeLog CHANGED
@@ -1,3 +1,22 @@
1
+ * Rollback code that leaks RAM for LI processing
2
+ * Fixed RAM leaks in process_snippet_link()
3
+
4
+ [ 0.0.30 ]
5
+ * added ability to chain unordered lists inside ordered lists and vice-versa
6
+ * added ability to insert ordered lists that use letters instead numbers (with '%' instead '#')
7
+
8
+ [ 0.0.29 ]
9
+ * fixed unescaped characters in URL links
10
+
11
+ [ 0.0.28 ]
12
+ * fixed bold or italic texts at the beginning or (un)ordered lists
13
+
14
+ [ 0.0.26 ]
15
+ * fixed list parser for multilevel lists
16
+
17
+ [ 0.0.24 ]
18
+ * Ruby 1.9.3 compatibility
19
+
1
20
  [ 0.0.21 ]
2
21
  * emit correct urls for external svn links
3
22
  (https://www.assembla.com/spaces/breakout/tickets/8472)
data/README CHANGED
@@ -1,5 +1,5 @@
1
- Breakout Parser
2
- ===============
1
+ Breakout Parser
2
+ ===============
3
3
 
4
4
  - simplified Textile parser with some Assembla-specific features
5
5
  - converts Textile into HTML
@@ -7,27 +7,39 @@ Breakout Parser
7
7
  Build dependencies
8
8
  ==================
9
9
 
10
- You will need Flex, Bison, GCC, and GNU Make to build this gem.
10
+ - You will need Flex, Bison, GCC, and GNU Make to build this gem.
11
+
12
+ Development
13
+ ================
14
+
15
+ Compiling and testing
16
+ - just run 'rake' in the repos root dir
11
17
 
18
+ Just compiling
19
+ - just run 'rake build_ext'
20
+
21
+ Testing
22
+ - just run 'rspec' or 'rspec spec/'
12
23
 
13
24
  Usage
14
25
  ===============
15
26
 
16
27
  require 'breakout_parser'
17
- puts BreakoutParser.parse("h1. xxx", "my_space")
28
+ puts BreakoutParser.parse("h1. xxx", "my_space")
18
29
  # prints: <h1 id="h-xxx">xxx</h1>
19
30
 
20
- puts BreakoutParser.parse_links_only("h1. http://xxx", "my_space")
31
+ puts BreakoutParser.parse_links_only("h1. http://xxx", "my_space")
21
32
  # prints: h1. <a rel="nofollow" href="http://xxx">http://xxx</a>
22
33
 
23
-
24
-
25
34
  Arguments
26
35
  ===============
27
36
 
28
37
  BreakoutParser.parse(
29
- data, # data to parse
30
- space_name, # space name - for links parsing
31
- site_url, # [optional] global site url
32
- vcs_url # [optional] custom VCS url - f.ex. for github-hosted repos
38
+ data, # data to parse
39
+ space_name, # space name - for links parsing
40
+ site_url, # [optional] global site url
41
+ vcs_url, # [optional] custom VCS url - f.ex. for github-hosted repos
42
+ absolute_urls, # [optional] boolean value that denotes if URLs have to be absolute
43
+ large_files_url, # [optional] URL used for large files (i.e. when using ADN/CDN)
44
+ data_attributes, # [optional] hash of data attributes that would be added to links
33
45
  )
@@ -12,12 +12,17 @@ dir_config(extension_name)
12
12
  if RUBY_PLATFORM['mswin32']
13
13
  $defs << "-MT" # link statically - avoid usage of MSVCR90.dll
14
14
  end
15
+
16
+ # Add RUBY_19 constant if it's Ruby 1.9
17
+ if RUBY_VERSION =~ /1.9/ then
18
+ $CPPFLAGS += " -DRUBY_19"
19
+ end
15
20
  create_makefile(([extension_name]*2).join('/'))
16
21
 
17
22
  def check_version name, need_ver
18
23
  exe = find_executable name
19
24
  return false unless exe
20
- exe_ver = `#{exe} -V`[/\d+\.\d+\.\d+/]
25
+ exe_ver = `#{exe} -V`[/\d+\.\d+(\.\d+)?/]
21
26
  unless exe_ver
22
27
  puts "[?] cannot determine #{name} version"
23
28
  return false
@@ -27,20 +32,20 @@ def check_version name, need_ver
27
32
  r = (exe_ver[0] > need_ver[0]) || (
28
33
  (exe_ver[0] == need_ver[0]) && (
29
34
  (exe_ver[1] > need_ver[1]) ||
30
- (exe_ver[1] == need_ver[1] && exe_ver[2] >= need_ver[2])
35
+ (exe_ver[1] == need_ver[1] && (exe_ver[2] || 0) >= need_ver[2])
31
36
  )
32
37
  )
33
38
  puts "[-] wanted #{name} >= #{need_ver.join('.')}, but got only #{exe_ver.join('.')}" unless r
34
39
  r
35
40
  end
36
41
 
37
- if !windows && File.exist?('Makefile') && check_version('bison','2.4.0') && check_version('lex','2.5.30')
42
+ if !windows && File.exist?('Makefile') && check_version('bison','2.3.0') && check_version('lex','2.5.30')
38
43
  File.open('Makefile','a') do |f|
39
44
  f.puts
40
45
  f.puts "parser.tab.c parser.tab.h: parser.y"
41
- f.puts "\tbison -d parser.y"
46
+ f.puts "\tbison -d $(srcdir)/parser.y"
42
47
  f.puts
43
48
  f.puts "lex.yy.c: parser.l"
44
- f.puts "\tlex parser.l"
49
+ f.puts "\tflex $(srcdir)/parser.l"
45
50
  end
46
51
  end
@@ -0,0 +1,27 @@
1
+ void process_url(const char *url);
2
+ void process_email(const char *url);
3
+ void process_inline_code(const char *p);
4
+ void revert_bold();
5
+ void revert_italic();
6
+ void process_ticket_link(const char *ticket_id);
7
+ void process_svn_link(const char *target, int numbered_repo);
8
+ void process_git_link(const char *target, int numbered_repo);
9
+ void process_url_link(const char *target,const char *proto);
10
+ void process_wiki_link(const char *target);
11
+ void process_anchor_link(const char *target);
12
+ void process_file_link(const char *target);
13
+ void process_image_link(const char *target);
14
+ void process_snippet_link(const char *space_id_and_snippet_id);
15
+ void concat_escaped_char(int c);
16
+ void process_header(const char *title);
17
+ int closing_list_stack_push(const char * term);
18
+ const char * closing_list_stack_pop();
19
+ void close_opened_lists();
20
+ void process_list_item(int level, int type);
21
+ const char *unconcat(const char *term);
22
+ int is_ending_with(const char *term);
23
+ void concat_raw_char(int c);
24
+ int concat_custom_vcs_url(const char *rev);
25
+ void set_numeric_ticket_id(const char *ticket_id, char *numeric_ticket_id);
26
+ void process_data_attributes(char *ticket_id);
27
+ void add_data_attribute(char *name, char *value);
@@ -113,7 +113,7 @@ extern size_t in_buf_len;
113
113
  [ \t]+@[^\r\n\xff@]+@/[ \t\r\n,.\xff] { yylval.svalue = yytext; return INLINE_CODE; }
114
114
 
115
115
  ^h[1-5]\.[ \t]+[^ \t\r\n][^\r\n]*/[\r\n\xff] {
116
- yylval.svalue = yytext+4;
116
+ yylval.svalue = yytext+4;
117
117
  switch(yytext[1]){
118
118
  case '1': return H1;
119
119
  case '2': return H2;
@@ -121,17 +121,31 @@ extern size_t in_buf_len;
121
121
  case '4': return H4;
122
122
  case '5': return H5;
123
123
  }
124
- return H1;
124
+ return H1;
125
125
  }
126
126
 
127
- ^[ \t]*\*\*\*[ ]+ { yylval.ivalue=3; return ULI; }
128
- ^[ \t]*\*\*[ ]+ { yylval.ivalue=2; return ULI; }
127
+ /* PS1: being nice to bold and italic markup in the beginning of LI items */
128
+ ^[ \t]*\*{3}/[ ]+(?:\*|_) { yylval.ivalue=3; return ULI; /* PS1 */ }
129
+ ^[ \t]*\*{3}[ ]+ { yylval.ivalue=3; return ULI; }
130
+ ^[ \t]*\*{2}/[ ]+(?:\*|_) { yylval.ivalue=2; return ULI; /* PS1 */ }
131
+ ^[ \t]*\*{2}[ ]+ { yylval.ivalue=2; return ULI; }
132
+ ^[ \t]*\*/[ ]+(?:\*|_) { yylval.ivalue=1; return ULI; /* PS1 */ }
129
133
  ^[ \t]*\*[ ]+ { yylval.ivalue=1; return ULI; }
130
134
 
131
- ^[ \t]*###[ ]+ { yylval.ivalue=3; return OLI; }
132
- ^[ \t]*##[ ]+ { yylval.ivalue=2; return OLI; }
135
+ ^[ \t]*#{3}/[ ]+(?:\*|_) { yylval.ivalue=3; return OLI; /* PS1 */ }
136
+ ^[ \t]*#{3}[ ]+ { yylval.ivalue=3; return OLI; }
137
+ ^[ \t]*#{2}/[ ]+(?:\*|_) { yylval.ivalue=2; return OLI; /* PS1 */ }
138
+ ^[ \t]*#{2}[ ]+ { yylval.ivalue=2; return OLI; }
139
+ ^[ \t]*#/[ ]+(?:\*|_) { yylval.ivalue=1; return OLI; /* PS1 */ }
133
140
  ^[ \t]*#[ ]+ { yylval.ivalue=1; return OLI; }
134
141
 
142
+ ^[ \t]*%{3}/[ ]+(?:\*|_) { yylval.ivalue=3; return OLI2; /* PS1 */ }
143
+ ^[ \t]*%{3}[ ]+ { yylval.ivalue=3; return OLI2; }
144
+ ^[ \t]*%{2}/[ ]+(?:\*|_) { yylval.ivalue=2; return OLI2; /* PS1 */ }
145
+ ^[ \t]*%{2}[ ]+ { yylval.ivalue=2; return OLI2; }
146
+ ^[ \t]*%/[ ]+(?:\*|_) { yylval.ivalue=1; return OLI2; /* PS1 */ }
147
+ ^[ \t]*%[ ]+ { yylval.ivalue=1; return OLI2; }
148
+
135
149
 
136
150
  <INITIAL,_LINKS_ONLY,_BOLD,_ITALIC>{
137
151
  (https?:\/\/|www\.)[^ \r\n<>"(){}*]+[^ \r\n<>"(){}*,.\[\]] { yylval.svalue = yytext; return URL; }
@@ -164,6 +178,8 @@ extern size_t in_buf_len;
164
178
  \[\[file:[a-zA-Z0-9_.-]+(\|[^\[\]]+)?\]\] { yylval.svalue = yytext+7; return FILE_LINK; }
165
179
  \[\[image:[a-zA-Z0-9_.-]+(\|[^\[\]]+)?\]\] { yylval.svalue = yytext+8; return IMAGE_LINK; }
166
180
 
181
+ \[\[snippet:[a-zA-Z0-9_.-]+:[0-9]+\]\] { yylval.svalue = yytext+10; return SNIPPET_LINK; }
182
+
167
183
  ^[ \t]+ ; /* skip spaces at line start */
168
184
  [ \t]+ { yylval.ivalue = ' '; return T_CHAR; }
169
185
 
@@ -1,13 +1,16 @@
1
1
  // vim:ts=4:sw=4:expandtab
2
- %{
2
+ %{
3
3
  #include <stdio.h>
4
4
  #include <stdlib.h>
5
5
  #include <string.h>
6
-
7
- #ifdef RUBY_VERSION
6
+ #include <time.h>
7
+ #include "parser.h"
8
8
  #include "ruby.h"
9
+
10
+ #ifdef RUBY_19
11
+ #include "ruby/st.h"
9
12
  #else
10
- #define REALLOC_N(ptr,type,n) ptr=realloc(ptr,sizeof(type)*n)
13
+ #include "st.h"
11
14
  #endif
12
15
 
13
16
  extern int yylex();
@@ -24,13 +27,20 @@ size_t space_name_len = 0;
24
27
  const char *site_url = NULL;
25
28
  size_t site_url_len = 0;
26
29
 
30
+ const char *large_files_url = NULL;
31
+ size_t large_files_url_len = 0;
32
+
33
+ VALUE meta_attributes;
34
+
27
35
  extern VALUE vcs_url;
28
36
 
37
+ const char ** closing_list_stack = NULL;
38
+ int closing_list_stack_size = 0;
29
39
  int list_level = 1;
30
40
  int absolute_urls = 0;
31
41
 
32
42
  #define CHECK_BUF_SIZE(len) \
33
- if( (bufptr - buf + len + 1) >= bufsize ){ \
43
+ if( (size_t)(bufptr - buf + len + 1) >= bufsize ){ \
34
44
  /*printf("[.] REALLOC oldsz=%d, newsz=%d\n",bufsize, (bufsize+((len > 0x1000) ? (len+0x1000) : 0x1000)));*/ \
35
45
  char *oldbuf = buf; \
36
46
  bufsize += (len > 0x1000) ? (len+0x1000) : 0x1000; \
@@ -38,18 +48,16 @@ int absolute_urls = 0;
38
48
  bufptr = buf + (bufptr-oldbuf); \
39
49
  }
40
50
 
41
- concat(const char*what, size_t len){
42
- // printf("[.] concat: w=\"%s\", l=%d\n",what,len);
51
+ void concat(const char*what, size_t len){
43
52
  CHECK_BUF_SIZE(len);
44
53
  memcpy(bufptr, what, len);
45
54
  bufptr += len;
46
- // printf("[.] concat OK\n");
47
55
  }
48
56
 
49
57
  // it's better to use concat(), especially if "what"'s length is always predefined
50
- concat2(const char*what){
58
+ void concat2(const char * what) {
51
59
  size_t len = strlen(what);
52
- concat(what,len);
60
+ concat(what, len);
53
61
  }
54
62
 
55
63
  // better error reporting
@@ -70,13 +78,13 @@ void yyerror(const char *msg)
70
78
  %union {
71
79
  double dvalue;
72
80
  int ivalue;
73
- char const* svalue;
81
+ const char* svalue;
74
82
  }
75
83
 
76
84
 
77
85
  %token <ivalue> T_CHAR BOLD_START ITALIC_START
78
86
  %token <ivalue> BOLD_ITALIC_START ITALIC_BOLD_START
79
- %token <ivalue> ULI OLI
87
+ %token <ivalue> ULI OLI OLI2
80
88
  %token <svalue> T_WORD TICKET_LINK LINK SVN_REVISION_LINK GIT_REVISION_LINK WIKI_LINK ANCHOR_LINK
81
89
  %token <svalue> SVN_N_REVISION_LINK GIT_N_REVISION_LINK
82
90
  %token <svalue> URL_WITH_PROTO_LINK URL_WITHOUT_PROTO_LINK
@@ -85,146 +93,197 @@ void yyerror(const char *msg)
85
93
  %token <svalue> UL
86
94
  %token <svalue> H1 H2 H3 H4 H5
87
95
  %token <svalue> INLINE_CODE
88
- %token SPACE BR /*BRBR*/
96
+ %token SPACE BR
89
97
  %token PRE_CODE_START PRE_CODE_END PRE_START PRE_END CODE_START CODE_END
90
98
  %token NOTEXTILE_START NOTEXTILE_END
91
99
  %token BOLD_END ITALIC_END
92
100
  %token REVERT_BOLD REVERT_ITALIC
101
+ %token <svalue> SNIPPET_LINK
93
102
 
94
103
  //%type <dvalue> expression
95
104
  //%type <dvalue> term
96
105
  //%type <dvalue> varornum
97
106
  %%
98
- text :
107
+ text :
99
108
  | textitem text
100
109
 
101
110
 
102
111
  textitem: br
103
112
  | words
104
- | h1 {concat("</h1>",5)}
105
- | h2 {concat("</h2>",5)}
106
- | h3 {concat("</h3>",5)}
107
- | h4 {concat("</h4>",5)}
108
- | h5 {concat("</h5>",5)}
109
- | {
110
- list_level=1;
111
- concat("<ul>",4)
112
- } ulist {
113
- concat("</ul>",5);
114
- for(; list_level>1 && list_level<4; list_level--) concat("</li></ul>",10);
115
- } textitem
116
- | {
117
- list_level=1;
118
- concat("<ol>",4)
119
- } olist {
120
- concat("</ol>",5);
121
- for(; list_level>1 && list_level<4; list_level--) concat("</li></ol>",10);
122
- } textitem
113
+ | h1 {concat("</h1>",5);}
114
+ | h2 {concat("</h2>",5);}
115
+ | h3 {concat("</h3>",5);}
116
+ | h4 {concat("</h4>",5);}
117
+ | h5 {concat("</h5>",5);}
118
+ | listitem { concat("</li>", 5); close_opened_lists(); }
123
119
  | code
124
120
 
125
- ulist: ulitem {concat("</li>",5)}
126
- | ulist ulitem {concat("</li>",5)}
121
+ listitem: ulitem
122
+ | olitem
123
+ | olitem2
127
124
 
128
125
  ulitem: uli words
129
126
  | uli words BR
130
127
 
131
- olist: olitem {concat("</li>",5)}
132
- | olist olitem {concat("</li>",5)}
133
-
134
128
  olitem: oli words
135
129
  | oli words BR
136
130
 
131
+ olitem2: oli2 words
132
+ | oli2 words BR
133
+
137
134
  words: word
138
135
  | word words
139
136
 
140
137
  word : chars
141
138
  | link
142
- | T_WORD {concat2($1)} // TODO: somehow pass T_WORD's length here
143
- | URL {process_url($1)}
144
- | EMAIL {process_email($1)}
145
- | BOLD_START {$1 ? concat(" <strong>",9) : concat("<strong>",8)}
146
- | BOLD_END {concat("</strong>",9)}
147
- | ITALIC_START {$1 ? concat(" <em>",5) : concat("<em>",4)}
148
- | ITALIC_END {concat("</em>",5)}
149
- | BOLD_ITALIC_START {$1 ? concat(" <strong><em>",13) : concat("<strong><em>",12)}
150
- | ITALIC_BOLD_START {$1 ? concat(" <em><strong>",13) : concat("<em><strong>",12)}
151
- | INLINE_CODE {process_inline_code($1)}
152
- | REVERT_BOLD {revert_bold()}
153
- | REVERT_ITALIC {revert_italic()}
154
-
155
- link: TICKET_LINK {process_ticket_link($1)}
156
- | SVN_REVISION_LINK {process_svn_link($1,0)}
157
- | GIT_REVISION_LINK {process_git_link($1,0)}
158
- | SVN_N_REVISION_LINK {process_svn_link($1,1)}
159
- | GIT_N_REVISION_LINK {process_git_link($1,1)}
160
- | URL_WITH_PROTO_LINK {process_url_link($1,NULL)}
161
- | URL_WITHOUT_PROTO_LINK {process_url_link($1,"http://")}
162
- | WIKI_LINK {process_wiki_link($1)}
163
- | ANCHOR_LINK {process_anchor_link($1)}
164
- | FILE_LINK {process_file_link($1)}
165
- | IMAGE_LINK {process_image_link($1)}
139
+ | T_WORD {concat2($1);} // TODO: somehow pass T_WORD's length here
140
+ | URL {process_url($1);}
141
+ | EMAIL {process_email($1);}
142
+ | BOLD_START {$1 ? concat(" <strong>",9) : concat("<strong>",8);}
143
+ | BOLD_END {concat("</strong>",9);}
144
+ | ITALIC_START {$1 ? concat(" <em>",5) : concat("<em>",4);}
145
+ | ITALIC_END {concat("</em>",5);}
146
+ | BOLD_ITALIC_START {$1 ? concat(" <strong><em>",13) : concat("<strong><em>",12);}
147
+ | ITALIC_BOLD_START {$1 ? concat(" <em><strong>",13) : concat("<em><strong>",12);}
148
+ | INLINE_CODE {process_inline_code($1);}
149
+ | REVERT_BOLD {revert_bold();}
150
+ | REVERT_ITALIC {revert_italic();}
151
+
152
+ link: TICKET_LINK {process_ticket_link($1);}
153
+ | SVN_REVISION_LINK {process_svn_link($1,0);}
154
+ | GIT_REVISION_LINK {process_git_link($1,0);}
155
+ | SVN_N_REVISION_LINK {process_svn_link($1,1);}
156
+ | GIT_N_REVISION_LINK {process_git_link($1,1);}
157
+ | URL_WITH_PROTO_LINK {process_url_link($1,NULL);}
158
+ | URL_WITHOUT_PROTO_LINK {process_url_link($1,"http://");}
159
+ | WIKI_LINK {process_wiki_link($1);}
160
+ | ANCHOR_LINK {process_anchor_link($1);}
161
+ | FILE_LINK {process_file_link($1);}
162
+ | IMAGE_LINK {process_image_link($1);}
163
+ | SNIPPET_LINK {process_snippet_link($1);}
166
164
 
167
165
  chars:
168
166
  | char chars
169
167
 
170
- char : T_CHAR {concat_escaped_char($1)}
168
+ char : T_CHAR {concat_escaped_char($1);}
171
169
 
172
170
  //raw_chars:
173
171
  // | raw_char raw_chars
174
172
 
175
173
  //raw_char : T_CHAR {concat_raw_char($1)}
176
174
 
177
- h1 : H1 {concat("<h1 id=\"h-",10); process_header($1)}
178
- h2 : H2 {concat("<h2 id=\"h-",10); process_header($1)}
179
- h3 : H3 {concat("<h3 id=\"h-",10); process_header($1)}
180
- h4 : H4 {concat("<h4 id=\"h-",10); process_header($1)}
181
- h5 : H5 {concat("<h5 id=\"h-",10); process_header($1)}
182
- //ul : UL {concat("<ul>",4)}
183
- oli : OLI {process_oli($1)}
184
- uli : ULI {process_uli($1)}
185
- br : BR {concat("<br />",6)}
186
- // | BRBR {concat("<br /><br />",12)}
187
-
188
- code : PRE_CODE_START {concat("<pre><code>",11)} chars PRE_CODE_END {concat("</code></pre>",13)}
175
+ h1 : H1 {concat("<h1 id=\"h-",10); process_header($1);}
176
+ h2 : H2 {concat("<h2 id=\"h-",10); process_header($1);}
177
+ h3 : H3 {concat("<h3 id=\"h-",10); process_header($1);}
178
+ h4 : H4 {concat("<h4 id=\"h-",10); process_header($1);}
179
+ h5 : H5 {concat("<h5 id=\"h-",10); process_header($1);}
180
+ uli : ULI {process_list_item($1, 1);}
181
+ oli : OLI {process_list_item($1, 2);}
182
+ oli2 : OLI2 {process_list_item($1, 3);}
183
+ br : BR {concat("<br />",6);}
184
+
185
+ code : PRE_CODE_START {concat("<pre><code>",11);} chars PRE_CODE_END {concat("</code></pre>",13);}
189
186
  | NOTEXTILE_START chars NOTEXTILE_END
190
- | PRE_START {concat("<pre>",5)} chars PRE_END {concat("</pre>",6)}
191
- | CODE_START {concat("<code>",6)} chars CODE_END {concat("</code>",7)}
187
+ | PRE_START {concat("<pre>",5);} chars PRE_END {concat("</pre>",6);}
188
+ | CODE_START {concat("<code>",6);} chars CODE_END {concat("</code>",7);}
192
189
 
193
190
  //word : T_WORD { process_word($1); }
194
191
 
195
192
  %%
196
193
 
197
- process_uli(int level){
198
- if( level == list_level ){
199
- concat("<li>",4);
200
- } else if( level < list_level ){
201
- list_level--;
202
- //unconcat("</li>");
203
- concat("</ul></li><li>",14);
194
+ int closing_list_stack_push(const char * term) {
195
+ closing_list_stack_size++;
196
+ if( closing_list_stack != NULL ) {
197
+ closing_list_stack = REALLOC_N(closing_list_stack, const char *, closing_list_stack_size);
204
198
  } else {
205
- // if(level > list_level)
206
- list_level++;
207
- unconcat("</li>");
208
- concat("<ul><li>",8);
199
+ closing_list_stack = ALLOC(const char *);
209
200
  }
201
+ *(closing_list_stack + closing_list_stack_size - 1) = (const char *) strdup(term);
202
+ xfree((void *) term);
203
+ return closing_list_stack_size;
210
204
  }
211
205
 
212
- process_oli(int level){
213
- if( level == list_level ){
214
- concat("<li>",4);
215
- } else if( level < list_level ){
216
- list_level = level;
217
- //unconcat("</li>");
218
- concat("</ol></li><li>",14);
206
+ const char * closing_list_stack_pop() {
207
+ const char *term = NULL;
208
+ if( !closing_list_stack_size ) return NULL;
209
+ term = *(closing_list_stack + --closing_list_stack_size);
210
+ REALLOC_N(closing_list_stack, const char *, closing_list_stack_size);
211
+ return term;
212
+ }
213
+
214
+ void close_opened_lists() {
215
+ const char *term = NULL;
216
+ while( ( term = closing_list_stack_pop() ) != NULL ) {
217
+ concat2(term);
218
+ xfree((void *) term);
219
+ }
220
+ }
221
+
222
+ void process_list_item(int level, int type) {
223
+ int insert_start_tag = 0, unconcat_steps, level_diff = list_level - level;
224
+ const char *removed_term = NULL;
225
+ char * start_tag = NULL, * closing_tag = NULL;
226
+
227
+ switch( type ) {
228
+ case 1:
229
+ start_tag = strdup("<ul>");
230
+ closing_tag = strdup("</ul>");
231
+ break;
232
+ case 2:
233
+ start_tag = strdup("<ol>");
234
+ closing_tag = strdup("</ol>");
235
+ break;
236
+ case 3:
237
+ start_tag = strdup("<ol class='letters'>");
238
+ closing_tag = strdup("</ol>");
239
+ break;
240
+ }
241
+
242
+ if( !is_ending_with("</ul>") && !is_ending_with("</ol>") ) {
243
+ insert_start_tag = 1;
244
+ list_level = 1;
245
+ level_diff = list_level - level;
246
+ if( level_diff < 0 ) {
247
+ level_diff = 0;
248
+ level = 1;
249
+ }
250
+ }
251
+ if( level_diff < -1 ) level = list_level + 1;
252
+
253
+ if( level_diff >= 0 ) {
254
+ unconcat_steps = level;
255
+ for( ; unconcat_steps; --unconcat_steps ) {
256
+ if( unconcat_steps > 1 ) {
257
+ removed_term = unconcat("</li></ul>");
258
+ if( removed_term == NULL ) removed_term = unconcat("</li></ol>");
259
+ } else {
260
+ removed_term = unconcat("</ul>");
261
+ if( removed_term == NULL ) removed_term = unconcat("</ol>");
262
+ if( removed_term != NULL ) {
263
+ xfree((void *) removed_term);
264
+ removed_term = NULL; // we don't want to push this closing tag into the stack in this case
265
+ }
266
+ }
267
+ if( removed_term != NULL ) closing_list_stack_push(removed_term);
268
+ }
269
+ if( insert_start_tag ) concat2(start_tag);
270
+ concat2("<li>");
219
271
  } else {
220
- // if(level > list_level)
221
- list_level = level;
222
- unconcat("</li>");
223
- concat("<ol><li>",8);
272
+ unconcat_steps = level - 1;
273
+ for( ; unconcat_steps; --unconcat_steps ) {
274
+ if( ( removed_term = unconcat("</li></ul>") ) || ( removed_term = unconcat("</li></ol>") ) ) {
275
+ closing_list_stack_push(removed_term);
276
+ }
277
+ }
278
+ concat2(start_tag);
279
+ concat2("<li>");
224
280
  }
281
+ list_level = level;
282
+ closing_list_stack_push(closing_tag);
283
+ xfree(start_tag);
225
284
  }
226
285
 
227
- concat_hex_char(char c){
286
+ void concat_hex_char(char c){
228
287
  unsigned char d;
229
288
  d = ((unsigned char)c)>>4;
230
289
  concat_raw_char(d>9 ? ('a'+d-10) : '0'+d);
@@ -232,12 +291,12 @@ concat_hex_char(char c){
232
291
  concat_raw_char(d>9 ? ('a'+d-10) : '0'+d);
233
292
  }
234
293
 
235
- need_hex_convert(const char*p, const char*pend){
294
+ int need_hex_convert(const char*p, const char*pend){
236
295
  // scan for non alphanum chars first
237
296
  for(; *p && p<=pend; p++){
238
- if( *p == ' ' ||
239
- *p == '_' ||
240
- *p == '-' ||
297
+ if( *p == ' ' ||
298
+ *p == '_' ||
299
+ *p == '-' ||
241
300
  *p == '.' ||
242
301
  (*p >= '0' && *p <= '9') ||
243
302
  (*p >= 'a' && *p <= 'z') ||
@@ -252,7 +311,7 @@ need_hex_convert(const char*p, const char*pend){
252
311
  return 0;
253
312
  }
254
313
 
255
- process_inline_code(const char*p){
314
+ void process_inline_code(const char*p){
256
315
  if( *p == ' ' || *p == 9 ){
257
316
  concat_raw_char(' ');
258
317
  while( *p == ' ' || *p == 9 ) p++;
@@ -266,7 +325,7 @@ process_inline_code(const char*p){
266
325
  concat("</code>",7);
267
326
  }
268
327
 
269
- process_header(const char*title){
328
+ void process_header(const char*title){
270
329
  const char*p,*pend;
271
330
 
272
331
  // skip heading spaces
@@ -287,7 +346,7 @@ process_header(const char*title){
287
346
  for(p = title; *p && p<=pend; p++) concat_escaped_char( *p );
288
347
  }
289
348
 
290
- process_link_tail(const char*text,const char*pend,const char*prepend){
349
+ void process_link_tail(const char*text,const char*pend,const char*prepend){
291
350
  const char*p;
292
351
 
293
352
  concat("\">",2);
@@ -311,7 +370,7 @@ process_link_tail(const char*text,const char*pend,const char*prepend){
311
370
  concat("</a>",4);
312
371
  }
313
372
 
314
- process_anchor_link(const char*target){
373
+ void process_anchor_link(const char*target){
315
374
  const char *p,*pend;
316
375
 
317
376
  // skip tail
@@ -333,7 +392,7 @@ process_anchor_link(const char*target){
333
392
  process_link_tail(target,NULL,"#");
334
393
  }
335
394
 
336
- process_url_link(const char*target,const char* proto){
395
+ void process_url_link(const char*target,const char* proto){
337
396
  const char *c;
338
397
  concat("<a rel=\"nofollow\" href=\"",24);
339
398
  if(proto){
@@ -345,17 +404,23 @@ process_url_link(const char*target,const char* proto){
345
404
  if(*(bufptr-1) == '/') bufptr--; // skip redundant '/'
346
405
  }
347
406
  }
348
- for(c=target; *c && *c != ']' && *c != '|'; c++) concat_raw_char(*c);
407
+ for(c=target; *c && *c != ']' && *c != '|'; c++) concat_escaped_char(*c);
349
408
  process_link_tail(target,NULL,proto);
350
409
  }
351
410
 
352
- concat_site_url(){
411
+ void concat_site_url(){
353
412
  if( site_url && site_url_len > 0 ){
354
413
  concat(site_url, site_url_len);
355
414
  }
356
415
  }
357
416
 
358
- process_svn_link(const char*target, int numbered_repo){
417
+ void concat_large_files_url(){
418
+ if( large_files_url && large_files_url_len > 0 ){
419
+ concat(large_files_url, large_files_url_len);
420
+ }
421
+ }
422
+
423
+ void process_svn_link(const char*target, int numbered_repo){
359
424
  const char *c;
360
425
  // can use sprintf here.. but I think it's a way slower than raw concat
361
426
  concat("<a href=\"",9);
@@ -397,7 +462,7 @@ int concat_custom_vcs_url(const char*rev){
397
462
  return 0;
398
463
  }
399
464
 
400
- process_git_link(const char*target, int numbered_repo){
465
+ void process_git_link(const char*target, int numbered_repo){
401
466
  const char *c;
402
467
  // can use sprintf here.. but I think it's a way slower than raw concat
403
468
  concat("<a href=\"",9);
@@ -418,7 +483,7 @@ process_git_link(const char*target, int numbered_repo){
418
483
  process_link_tail(target,NULL,"revision:");
419
484
  }
420
485
 
421
- process_wiki_link(const char*target){
486
+ void process_wiki_link(const char*target){
422
487
  const char *c;
423
488
  // can use sprintf here.. but I think it's a way slower than raw concat
424
489
  concat("<a class=\"wiki_link\" title=\"",28);
@@ -441,11 +506,12 @@ process_wiki_link(const char*target){
441
506
  process_link_tail(target,NULL,NULL);
442
507
  }
443
508
 
444
- process_file_link(const char*target){
509
+ void process_file_link(const char*target){
445
510
  const char *c;
446
511
  // can use sprintf here.. but I think it's a way slower than raw concat
447
512
  concat("<a href=\"",9);
448
513
  concat_site_url();
514
+ concat_large_files_url();
449
515
  concat("/spaces/",8);
450
516
  concat(space_name,space_name_len);
451
517
  concat("/documents/download/",20);
@@ -453,11 +519,12 @@ process_file_link(const char*target){
453
519
  process_link_tail(target,NULL,"file:");
454
520
  }
455
521
 
456
- process_image_link(const char*target){
522
+ void process_image_link(const char*target){
457
523
  const char *c, *p;
458
524
  // can use sprintf here.. but I think it's a way slower than raw concat
459
525
  concat("<img src=\"",10);
460
526
  concat_site_url();
527
+ concat_large_files_url();
461
528
  concat("/spaces/",8);
462
529
  concat(space_name,space_name_len);
463
530
  concat("/documents/download/",20);
@@ -471,7 +538,7 @@ process_image_link(const char*target){
471
538
  concat("\" />",4);
472
539
  }
473
540
 
474
- process_ticket_link(const char*ticket_id){
541
+ void process_ticket_link(const char*ticket_id){
475
542
  const char *c;
476
543
  while(*ticket_id && (*ticket_id < '0' || *ticket_id > '9') ) ticket_id++;
477
544
  // can use sprintf here.. but I think it's a way slower than raw concat
@@ -481,10 +548,102 @@ process_ticket_link(const char*ticket_id){
481
548
  concat(space_name,space_name_len);
482
549
  concat("/tickets/",9);
483
550
  for(c=ticket_id; *c && *c>='0' && *c<='9'; c++) concat_raw_char(*c);
551
+
552
+ if (RHASH_SIZE(meta_attributes) > 0) {
553
+ char *numeric_ticket_id = ALLOC_N(char, strlen(ticket_id));
554
+ set_numeric_ticket_id(ticket_id, numeric_ticket_id);
555
+
556
+ process_data_attributes(numeric_ticket_id);
557
+ xfree(numeric_ticket_id);
558
+ }
559
+
484
560
  process_link_tail(ticket_id,NULL,"#");
485
561
  }
486
562
 
487
- concat_escaped_char(int c){
563
+ void process_snippet_link(const char *space_id_with_snippet_id) {
564
+ size_t len = strlen(space_id_with_snippet_id);
565
+ char *space_id = ALLOC_N(char, len);
566
+ char *snippet_id = ALLOC_N(char, len);
567
+ char *pch;
568
+ char *timeval = ALLOC_N(char, 20);
569
+ int i = 0;
570
+ pch = strtok((char *)space_id_with_snippet_id, ":]");
571
+ // Extract only first two tokens: space_id and snippet_id
572
+ while (i < 2) {
573
+ i == 0 ? strcpy(space_id, pch) : strcpy(snippet_id, pch);
574
+ pch = strtok(NULL, ":]");
575
+ i += 1;
576
+ }
577
+
578
+ concat("<script async=\"true\" id=\"snippet-", 33);
579
+ concat(snippet_id, strlen(snippet_id));
580
+ concat("\" src=\"", 7);
581
+ concat_site_url();
582
+ concat_large_files_url();
583
+ concat("/spaces/", 8);
584
+ concat2(space_id);
585
+ concat("/snippets/", 10);
586
+ concat2(snippet_id);
587
+ concat(".js?_=", 6);
588
+ sprintf(timeval, "%ld", (long)time(NULL));
589
+ concat2(timeval);
590
+ concat("\"></script>", 11);
591
+ xfree(timeval);
592
+ xfree(space_id);
593
+ xfree(snippet_id);
594
+ }
595
+
596
+ int iterate_attributes_hash(VALUE key, VALUE record, st_data_t arg) {
597
+ add_data_attribute(RSTRING_PTR(key), RSTRING_PTR(record));
598
+ return ST_CONTINUE;
599
+ }
600
+
601
+ // NOTE: Data attributes work for tickets only right now
602
+ // Nevertheless, it's really easy to extend this method to
603
+ // add data attributes to any desired object
604
+ void process_data_attributes(char *ticket_id) {
605
+ VALUE meta_attributes_hash;
606
+
607
+ if (st_lookup(RHASH_TBL(meta_attributes), rb_str_new2(ticket_id), &meta_attributes_hash) == 1) {
608
+ // We found something for that ticket id
609
+ if (TYPE(meta_attributes_hash) == T_HASH) {
610
+ int meta_attributes_len = RHASH_SIZE(meta_attributes_hash);
611
+ if (meta_attributes_len > 0) {
612
+ st_data_t result = 0;
613
+ concat("\"", 1); // Close href quotation mark
614
+ st_foreach(RHASH_TBL(meta_attributes_hash), iterate_attributes_hash, result);
615
+ unconcat("\""); // Remove final quotation mark as it will be added by process_link_tail
616
+ };
617
+ } else {
618
+ rb_raise(rb_eTypeError, "Expected instance of Hash, %0x given", TYPE(meta_attributes_hash));
619
+ }
620
+ }
621
+ }
622
+
623
+ // Add data attribute to link
624
+ void add_data_attribute(char *attribute_name, char *attribute_value) {
625
+ concat(" data-", 6);
626
+ concat2(attribute_name);
627
+ concat("=\"", 2);
628
+ concat2(attribute_value);
629
+ concat("\"", 1);
630
+ }
631
+
632
+ void set_numeric_ticket_id(const char *ticket_id, char *numeric_ticket_id) {
633
+ char *c, *mutable_ticket_id;
634
+ int i = 0;
635
+
636
+ mutable_ticket_id = ALLOC_N(char, strlen(ticket_id));
637
+ memcpy(mutable_ticket_id, ticket_id, strlen(ticket_id));
638
+ for (c = mutable_ticket_id; *c && *c >= '0' && *c <= '9'; c++) {
639
+ *(numeric_ticket_id + i) = *c;
640
+ i++;
641
+ }
642
+ xfree(mutable_ticket_id);
643
+ *(numeric_ticket_id + i) = '\0';
644
+ }
645
+
646
+ void concat_escaped_char(int c){
488
647
  switch(c){
489
648
  case '<':
490
649
  concat("&lt;",4);
@@ -505,12 +664,12 @@ concat_escaped_char(int c){
505
664
  }
506
665
 
507
666
 
508
- concat_raw_char(int c){
667
+ void concat_raw_char(int c){
509
668
  CHECK_BUF_SIZE(1);
510
669
  *bufptr++ = c;
511
670
  }
512
671
 
513
- process_url(const char*url){
672
+ void process_url(const char*url){
514
673
  const char *p;
515
674
 
516
675
  concat("<a rel=\"nofollow\" href=\"",24);
@@ -524,7 +683,7 @@ process_url(const char*url){
524
683
  process_link_tail(url,NULL,NULL);
525
684
  }
526
685
 
527
- process_email(const char*url){
686
+ void process_email(const char*url){
528
687
  const char *p;
529
688
 
530
689
  concat("<a href=\"mailto:",16);
@@ -532,12 +691,21 @@ process_email(const char*url){
532
691
  process_link_tail(url,NULL,NULL);
533
692
  }
534
693
 
535
- unconcat(const char*what){
536
- int l = strlen(what);
537
- if( bufptr-buf > l && strncmp(bufptr-l,what,l) == 0 ) bufptr -= l;
694
+ const char *unconcat(const char *term){
695
+ int str_size = is_ending_with(term);
696
+ if( str_size ) {
697
+ bufptr -= str_size;
698
+ return (const char *) strndup(term, str_size + 1);
699
+ }
700
+ return (const char *) NULL;
701
+ }
702
+ int is_ending_with(const char *term) {
703
+ int str_size = (int) strlen(term);
704
+ if( bufptr - buf > str_size && strncmp(bufptr - str_size, term, str_size) == 0 ) return str_size;
705
+ return 0;
538
706
  }
539
707
 
540
- revert_bold(){
708
+ void revert_bold(){
541
709
  char *p;
542
710
  for( p=bufptr-1; p >= (buf+7) ; p--){
543
711
  if( 0 == strncmp(p-7, "<strong>", 8) ){
@@ -547,7 +715,7 @@ revert_bold(){
547
715
  }
548
716
  }
549
717
 
550
- revert_italic(){
718
+ void revert_italic(){
551
719
  char *p;
552
720
  for( p=bufptr-1; p >= (buf+3) ; p--){
553
721
  if( 0 == strncmp(p-3, "<em>", 4) ){