1
+ /*******************************************************************************
2
+ * Copyright (c) 2022 Red Hat Inc. and others.
3
+ *
4
+ * This program and the accompanying materials are made
5
+ * available under the terms of the Eclipse Public License 2.0
6
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
7
+ *
8
+ * SPDX-License-Identifier: EPL-2.0
9
+ *
10
+ * Contributors:
11
+ * Red Hat Inc. - Initial implementation
12
+ *******************************************************************************/
13
+ package org .eclipse .linuxtools .internal .cdt .libhover .devhelp ;
14
+
15
+ import java .util .Map ;
16
+ import java .util .TreeMap ;
17
+
18
+ import org .apache .xerces .parsers .AbstractSAXParser ;
19
+ import org .apache .xerces .xni .Augmentations ;
20
+ import org .apache .xerces .xni .QName ;
21
+ import org .apache .xerces .xni .XMLAttributes ;
22
+ import org .apache .xerces .xni .XMLString ;
23
+ import org .cyberneko .html .HTMLConfiguration ;
24
+ import org .eclipse .linuxtools .cdt .libhover .FunctionInfo ;
25
+ import org .eclipse .linuxtools .internal .cdt .libhover .devhelp .preferences .FuncFoundSaxException ;
26
+
27
+ class HTMLSAXParser extends AbstractSAXParser implements DevHelpSAXParser {
28
+
29
+ private boolean begin ;
30
+ private boolean returnType ;
31
+ private boolean protoStart ;
32
+ private boolean parmStart ;
33
+ private boolean descStart ;
34
+ private boolean rowIgnore ;
35
+ private boolean srcLink ;
36
+ private boolean valid = true ;
37
+ private Map <String , String > funcs ;
38
+ private String returnValue ;
39
+ private String funcName ;
40
+ private String rowTag ;
41
+ private StringBuilder prototype = new StringBuilder ();
42
+ private StringBuilder description = new StringBuilder ();
43
+ private int divCounter ;
44
+ private int rowItemCount ;
45
+ private TreeMap <String , FunctionInfo > infos = new TreeMap <>();
46
+
47
+ public HTMLSAXParser (Map <String , String > funcs ) {
48
+ super (new HTMLConfiguration ());
49
+ this .funcs = funcs ;
50
+ }
51
+
52
+ @ Override
53
+ public void startElement (QName name , XMLAttributes a , Augmentations aug ) {
54
+ // look for a tag that matches one of the functions we are trying to find
55
+ if ("A" .equals (name .rawname )) { //$NON-NLS-1$
56
+ String classValue = a .getValue ("class" ); //$NON-NLS-1$
57
+ if (classValue != null ) {
58
+ if (classValue .equals ("anchor" )) { //$NON-NLS-1$
59
+ String href = a .getValue ("href" ); //$NON-NLS-1$
60
+ if (href != null ) {
61
+ if (href .equals ("#declaration" )) { //$NON-NLS-1$
62
+ String mapName = funcs .get ("name" ); //$NON-NLS-1$
63
+ if (mapName != null ) {
64
+ // We have found one of the functions we are looking for.
65
+ // Register the name for later and allow function parsing to begin.
66
+ funcName = mapName .trim ();
67
+ if (funcName .endsWith ("()" )) { //$NON-NLS-1$
68
+ // Remove () at end of function name and remove all space chars which might be
69
+ // non-breaking space chars which unfortunately do not get caught by the trim() method.
70
+ funcName = this .funcName .replaceAll ("\\ (\\ )" , "" ).replaceAll ("\\ p{javaSpaceChar}" ,"" ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
71
+ }
72
+ begin = true ;
73
+ }
74
+ } else if (href .equals ("#description" )) { //$NON-NLS-1$
75
+ descStart = true ;
76
+ } else if (href .equals ("#return-value" )) { //$NON-NLS-1$
77
+ descStart = true ;
78
+ } else if (href .equals ("#parameters" )) { //$NON-NLS-1$
79
+ description .append ("<br><br><h4>Parameters:</h4>" ); //$NON-NLS-1$
80
+ descStart = true ;
81
+ }
82
+ }
83
+ } else if (classValue .equals ("srclink" )) { //$NON-NLS-1$
84
+ srcLink = true ;
85
+ }
86
+ }
87
+ }
88
+ if (begin ) {
89
+ if ("DIV" .equals (name .rawname )) { //$NON-NLS-1$
90
+ ++divCounter ;
91
+ }
92
+ if (!descStart ) {
93
+ if ("SPAN" .equals (name .rawname )) { //$NON-NLS-1$
94
+ String type = a .getValue ("class" ); //$NON-NLS-1$
95
+ if (returnValue == null && type != null &&
96
+ type .equals ("n" )) { //$NON-NLS-1$
97
+ returnType = true ;
98
+ }
99
+ }
100
+ }
101
+ if (protoStart ) {
102
+ if ("P" .equals (name .rawname )) { //$NON-NLS-1$
103
+ protoStart = false ;
104
+ descStart = true ;
105
+ description .append ("<p>" ); //$NON-NLS-1$
106
+ }
107
+ } else if (descStart ) {
108
+ if ("P" .equals (name .rawname )) { //$NON-NLS-1$
109
+ description .append ("<p>" ); //$NON-NLS-1$
110
+ } else if ("TABLE" .equals (name .rawname )) { //$NON-NLS-1$
111
+ description .append ("<dl>" ); //$NON-NLS-1$
112
+ } else if ("TR" .equals (name .rawname )) { //$NON-NLS-1$
113
+ rowItemCount = 0 ;
114
+ } else if ("TD" .equals (name .rawname )) { //$NON-NLS-1$
115
+ String type = a .getValue ("class" ); //$NON-NLS-1$
116
+ if (type != null && type .equals ("listing_lines" )) { //$NON-NLS-1$
117
+ rowIgnore = true ;
118
+ } else {
119
+ rowIgnore = false ;
120
+ if (rowItemCount ++ == 0 ) {
121
+ rowTag = "<dt>" ; //$NON-NLS-1$
122
+ } else {
123
+ rowTag = "<dd>" ; //$NON-NLS-1$
124
+ }
125
+ description .append (rowTag );
126
+ }
127
+ } else if ("H4" .equals (name .rawname )) { //$NON-NLS-1$
128
+ // description.append("<br>"); //$NON-NLS-1$
129
+ }
130
+ }
131
+ }
132
+ }
133
+
134
+ @ Override
135
+ public void endElement (QName name , Augmentations aug ) {
136
+ if (srcLink ) {
137
+ if ("A" .equals (name .rawname )) { //$NON-NLS-1$
138
+ srcLink = false ;
139
+ }
140
+ } else if (begin ) {
141
+ if ("DIV" .equals (name .rawname )) { //$NON-NLS-1$
142
+ --divCounter ;
143
+ if (divCounter <= 0 ) {
144
+ // We have finished parsing the current area, reset all flags
145
+ descStart = false ;
146
+ parmStart = false ;
147
+ protoStart = false ;
148
+ }
149
+ } else if ("SECTION" .equals (name .rawname )) { //$NON-NLS-1$
150
+ // We have finished parsing the function
151
+ // If valid, create and save the function info
152
+ if (valid && returnValue != null &&
153
+ !returnValue .startsWith ("#" ) && //$NON-NLS-1$
154
+ !returnValue .startsWith ("typedef " )) { //$NON-NLS-1$
155
+ FunctionInfo info = new FunctionInfo (funcName );
156
+ info .setReturnType (returnValue );
157
+ info .setPrototype (prototype .toString ());
158
+ info .setDescription (description .toString ());
159
+ infos .put (funcName , info );
160
+ throw new FuncFoundSaxException (); // indicate we are done and stop parser
161
+ }
162
+ }
163
+ if (descStart ) {
164
+ if ("P" .equals (name .rawname )) {//$NON-NLS-1$
165
+ description .append ("</p>" ); //$NON-NLS-1$
166
+ } else if ("TABLE" .equals (name .rawname )) { //$NON-NLS-1$
167
+ description .append ("</dl>" ); //$NON-NLS-1$
168
+ } else if ("TR" .equals (name .rawname )) { //$NON-NLS-1$
169
+ rowItemCount = 0 ;
170
+ } else if ("TD" .equals (name .rawname )) { //$NON-NLS-1$
171
+ if (!rowIgnore ) {
172
+ if (rowTag != null && rowTag .equals ("<dt>" )) {//$NON-NLS-1$
173
+ description .append ("</dt>" ); //$NON-NLS-1$
174
+ } else {
175
+ description .append ("</dd>" ); //$NON-NLS-1$
176
+ }
177
+ }
178
+ rowIgnore = false ;
179
+ }
180
+ }
181
+ }
182
+ }
183
+
184
+ @ Override
185
+ public void characters (XMLString data , Augmentations aug ) {
186
+ if (begin && !srcLink ) {
187
+ if (returnType ) {
188
+ returnValue = "" ; //$NON-NLS-1$
189
+ String tmp = data .toString ().trim ();
190
+ boolean completed = false ;
191
+ if (tmp .endsWith (");" )) { //$NON-NLS-1$
192
+ completed = true ;
193
+ tmp = tmp .substring (0 , tmp .length () - 2 );
194
+ }
195
+ String [] tokens = tmp .split ("\\ s+" ); //$NON-NLS-1$
196
+ String separator = "" ; //$NON-NLS-1$
197
+ protoStart = true ;
198
+ for (int i = 0 ; i < tokens .length ; ++i ) {
199
+ String token = tokens [i ];
200
+ if (!token .equals (funcName )) {
201
+ returnValue += separator + token ;
202
+ separator = " " ; //$NON-NLS-1$
203
+ } else {
204
+ separator = "" ; //$NON-NLS-1$
205
+ for (int j = i + 1 ; j < tokens .length ; ++j ) {
206
+ String jtoken = tokens [j ];
207
+ if (j == i + 1 && jtoken .charAt (0 ) == '(' ) {
208
+ jtoken = jtoken .substring (1 );
209
+ parmStart = true ;
210
+ protoStart = false ;
211
+ }
212
+ prototype .append (separator ).append (jtoken );
213
+ separator = " " ; //$NON-NLS-1$
214
+ }
215
+ if (parmStart && completed ) {
216
+ parmStart = false ;
217
+ descStart = true ;
218
+ }
219
+ break ;
220
+ }
221
+ }
222
+ returnType = false ;
223
+ } else if (protoStart ) {
224
+ String temp = data .toString ().trim ();
225
+ boolean completed = false ;
226
+ if (temp .endsWith (");" )) { //$NON-NLS-1$
227
+ completed = true ;
228
+ temp = temp .substring (0 , temp .length () - 2 );
229
+ }
230
+ String separator = " " ; //$NON-NLS-1$
231
+ while (temp .startsWith ("*" ) || temp .startsWith ("const" )) { //$NON-NLS-1$ //$NON-NLS-2$
232
+ if (temp .charAt (0 ) == '*' ) {
233
+ returnValue += separator + "*" ; //$NON-NLS-1$
234
+ temp = temp .substring (1 ).trim ();
235
+ separator = "" ; //$NON-NLS-1$
236
+ } else {
237
+ returnValue += "const" ; //$NON-NLS-1$
238
+ temp = temp .substring (5 ).trim ();
239
+ separator = " " ; //$NON-NLS-1$
240
+ }
241
+ }
242
+ int index = temp .lastIndexOf ('(' );
243
+ int index2 = temp .lastIndexOf (')' );
244
+ if (index2 < index ) {
245
+ if (index + 1 < temp .length ()) {
246
+ temp = temp .substring (index + 1 ).trim ();
247
+ prototype .append (temp );
248
+ }
249
+ parmStart = true ;
250
+ protoStart = false ;
251
+ }
252
+ if (parmStart && completed ) {
253
+ parmStart = false ;
254
+ descStart = true ;
255
+ }
256
+ } else if (parmStart ) {
257
+ String parmData = data .toString ().trim ();
258
+ int index = parmData .indexOf (')' );
259
+ if (index >= 0 ) {
260
+ parmStart = false ;
261
+ descStart = true ;
262
+ parmData = parmData .substring (0 , index );
263
+ }
264
+ if (prototype .length () == 0 ) {
265
+ if (!parmData .equals ("," ) && !parmData .isEmpty ()) { //$NON-NLS-1$
266
+ parmData = " " + parmData ; //$NON-NLS-1$
267
+ }
268
+ }
269
+ prototype .append (parmData );
270
+ } else if (descStart ) {
271
+ if (!rowIgnore ) {
272
+ description .append (String .valueOf (data ));
273
+ }
274
+ }
275
+ }
276
+ }
277
+
278
+ @ Override
279
+ public TreeMap <String , FunctionInfo > getFunctionInfos () {
280
+ return infos ;
281
+ }
282
+
283
+ @ Override
284
+ public String toString () {
285
+ return "funcName: <" + funcName + "> returnType: <" + returnValue + //$NON-NLS-1$ //$NON-NLS-2$
286
+ "> prototype: <" + prototype + "> description: " + description ; //$NON-NLS-1$ //$NON-NLS-2$
287
+ }
288
+ }
0 commit comments