1 #include <Rcpp.h>
2 using namespace Rcpp;
3
4 // From http://developer.r-project.org/parseRd.pdf: The characters \, %, {,
5 // and } have special meaning in almost all parts of an Rd file. In code,
6 // strings must also match, except in comments.
7
8 // The two functions are very similar, so we use a common
9 // implementation and select the functionality via the
10 // mode argument:
11 // mode == 0: rdComplete
12 // mode == 1: findEndOfTag
13
roxygen_parse_tag(std::string string,bool is_code=false,int mode=0)14 int roxygen_parse_tag(std::string string, bool is_code = false,
15 int mode = 0) {
16 int n = string.length();
17
18 char in_string = '\0';
19 bool in_escape = false;
20 bool in_r_comment = false;
21 bool in_latex_comment = false;
22 int braces = 0, r_braces = 0;
23
24 for(int i = 0; i < n; i++) {
25 char cur = string[i];
26
27 if (in_escape) {
28 // Swallow escaped characters
29 in_escape = false;
30 } else if (in_string != '\0') {
31 // Look for end of string
32 if (cur == in_string) {
33 in_string = false;
34 } else if (cur == '\\') {
35 in_escape = true;
36 }
37 } else if (in_r_comment) {
38 // Inside R comments, braces must match.
39 // R comments are terminated by newline or } not matched by {
40 if (cur == '\n') {
41 in_r_comment = false;
42 r_braces = 0;
43 } else if (cur == '{') {
44 braces++;
45 r_braces++;
46 } else if (cur == '}') {
47 braces--;
48 r_braces--;
49 if (r_braces == 0)
50 in_r_comment = false;
51 }
52 } else if (in_latex_comment) {
53 if (cur == '\n') {
54 in_latex_comment = false;
55 }
56 } else {
57 switch(cur) {
58 case '{': braces++; break;
59 case '}': braces--; break;
60 case '\\': in_escape = true; break;
61 case '#': if (is_code) in_r_comment = true; break;
62 case '%': in_latex_comment = true; break;
63 case '\'': if (is_code) in_string = '\''; break;
64 case '"': if (is_code) in_string = '"'; break;
65 }
66 }
67
68 if (mode == 1) {
69 bool complete = braces == 0 && !in_escape && !in_string;
70 if (complete && i + 1 < n && string[i + 1] != '{') {
71 return i;
72 }
73 }
74
75 }
76
77 bool complete = braces == 0 && !in_escape && !in_string;
78
79 if (mode == 0) {
80 if (complete) return 1; else return 0;
81
82 } else {
83 if (complete) return n - 1; else return -1;
84 }
85 }
86
87 // [[Rcpp::export]]
findEndOfTag(std::string string,bool is_code=false)88 int findEndOfTag(std::string string, bool is_code = false) {
89 return roxygen_parse_tag(string, is_code, 1);
90 }
91
92 // [[Rcpp::export]]
rdComplete(std::string string,bool is_code=false)93 bool rdComplete(std::string string, bool is_code = false) {
94 return roxygen_parse_tag(string, is_code, 0) == 1 ? true : false;
95 }
96