comparison libgui/src/qtinfo/parser.cc @ 15196:017f0b2e6933

rename gui directory to libgu * libgui: Rename from gui. * .hgsub (libgui/qterminal): Rename from gui/qterminal. * Makefile.am (GUIDIR): Set to libgui instead of gui if AMCOND_BUILD_GUI is true. * configure.ac (AC_CONFIG_FILES): Update list for directory renaming. * Makefile.am (.NOTPARALLEL): Delete. List octave.html/index.html as the primary HTML target, not octave.html. (octave.html): New target for making the octave.html directory. (octave.pdf): Depend on octave.dvi. * images.awk: In generated rules for png files, depend on octave.html, not octave.html/index.html. * src/Makefile.am (OCTAVE_GUI_CPPFLAGS, OCTAVE_GUI_LIBS): Update for directory renaming. (CLEANFILES): Fix typo. * fntests.m (src_tree): Use libinterp, not src.
author John W. Eaton <jwe@octave.org>
date Sat, 18 Aug 2012 18:10:09 -0400
parents gui/src/qtinfo/parser.cc@48ae6a7c69c1
children ae9079bbc627
comparison
equal deleted inserted replaced
15195:2fc554ffbc28 15196:017f0b2e6933
1 /* Copyright (C) 2009 P.L. Lucas
2 * Copyright (C) 2012 Jacob Dawid <jacob.dawid@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20 #include "parser.h"
21 #include <QFileInfo>
22 #include <QDir>
23 #include <QFile>
24 #include <QUrl>
25 #include <QRegExp>
26 #include <QProcess>
27 #include <QBuffer>
28
29 parser::parser(QObject *parent)
30 : QObject(parent)
31 {
32 _compressors_map.insert ("bz2", "bzip2 -dc \"%1\"");
33 _compressors_map.insert ("gz", "gzip -dc \"%1\"");
34 _compressors_map.insert ("lzma", "lzma -dc \"%1\"");
35 _compressors_map.insert ("xz", "xz -dc \"%1\"");
36 _compressors_map.insert ("Z", "gunzip -c \"%1\"");
37 }
38
39 void
40 parser::set_info_path (QString infoPath)
41 {
42 this->_info_path = infoPath;
43
44 _info_files.clear ();
45
46 QFileInfo info (infoPath);
47
48 QString path = info.absolutePath ();
49 QString fileName = info.fileName ();
50
51 QDir infoDir (path);
52 QStringList filter;
53 filter.append (fileName + "*");
54
55 _info_files = infoDir.entryInfoList (filter, QDir::Files);
56 parse_info_map ();
57 }
58
59 QString
60 parser::get_info_path ()
61 {
62 return _info_path;
63 }
64
65 QIODevice *
66 parser::open_file (QFileInfo & file_info)
67 {
68 QIODevice *iodevice=NULL;
69 if ( _compressors_map.contains(file_info.suffix ()))
70 {
71 QProcess gzip;
72 gzip.start (_compressors_map.value (file_info.suffix ()).arg (file_info.absoluteFilePath ()));
73
74 if (!gzip.waitForFinished ())
75 return NULL;
76
77 QByteArray result = gzip.readAll ();
78
79 QBuffer *io = new QBuffer (this);
80 io->setData (result);
81
82 if (!io->open (QIODevice::ReadOnly | QIODevice::Text))
83 return NULL;
84
85 iodevice = io;
86 }
87 else
88 {
89 QFile *io = new QFile (file_info.absoluteFilePath ());
90 if (!io->open (QIODevice::ReadOnly | QIODevice::Text))
91 return NULL;
92 iodevice = io;
93 }
94
95 return iodevice;
96 }
97
98 int
99 parser::is_ref (QString node)
100 {
101 if (_ref_map.contains (node))
102 {
103 node_position ref = _ref_map [node];
104
105 return ref.pos-_node_map [ref._node_name].pos;
106 }
107 return -1;
108 }
109
110 QString
111 parser::search_node (QString node)
112 {
113 QFileInfo file_info;
114 QString ref;
115
116 if (_ref_map.contains (node))
117 {
118 ref = node;
119 node = _ref_map [ref]._node_name;
120 }
121
122 if (_node_map.contains (node))
123 {
124 int pos = _node_map [node].pos;
125 int realPos;
126
127 real_position (pos, file_info, realPos);
128
129 QIODevice *io = open_file (file_info);
130 if (io == NULL)
131 {
132 return QString ();
133 }
134
135 seek (io, realPos);
136
137 QString text = get_next_node (io);
138 if (!text.isEmpty())
139 {
140 return text;
141 }
142
143 io->close ();
144 delete io;
145 }
146
147 return QString ();
148 }
149
150 QString
151 parser::search_node (QString node, QIODevice *io)
152 {
153 while (!io->atEnd ())
154 {
155 QString text = get_next_node (io);
156 if(node == get_node_name (text))
157 {
158 return text;
159 }
160 }
161
162 return QString ();
163 }
164
165 QString
166 parser::get_next_node (QIODevice *io)
167 {
168 QString text;
169 while (!io->atEnd ())
170 {
171 QByteArray line = io->readLine ();
172 if (line.at(0) == 31)
173 {
174 break;
175 }
176 else
177 {
178 text.append (line);
179 }
180 }
181 return text;
182 }
183
184 static QString
185 get_first_line (QString text)
186 {
187 int n = text.indexOf ("\n");
188
189 if (n < 0)
190 {
191 return QString ();
192 }
193
194 QString first_line = text.left (n);
195 return first_line;
196 }
197
198 static QString
199 parser_node (QString text, QString node_name)
200 {
201 QString firstLine = get_first_line (text);
202 QStringList nodes = firstLine.split (",");
203 for (int i = 0;i < nodes.size (); i++)
204 {
205 QString node = nodes.at (i).trimmed ();
206
207 if (node.startsWith (node_name))
208 {
209 return node.remove (0, node_name.size ()).trimmed ();
210 }
211 }
212 return QString ();
213 }
214
215 QString
216 parser::get_node_name (QString text)
217 {
218 return parser_node (text, "Node:");
219 }
220
221 QString
222 parser::get_node_up (QString text)
223 {
224 return parser_node (text, "Up:");
225 }
226
227 QString
228 parser::get_node_next (QString text)
229 {
230 return parser_node (text, "Next:");
231 }
232
233 QString
234 parser::get_node_prev (QString text)
235 {
236 return parser_node (text, "Prev:");
237 }
238
239 static void
240 replace_links (QString &text)
241 {
242 QRegExp re ("(\\*[N|n]ote|\n\\*)([ |\n]+)([^:]+):([^:\\.,]*)([:,\\.])");
243 int i = 0, f;
244
245 while ( (i = re.indexIn (text,i)) != -1)
246 {
247 QString type = re.cap (1);
248 QString note = re.cap (3);
249 QString url_link = re.cap (4);
250 QString link = re.cap (4);
251
252 if (url_link.isEmpty ())
253 {
254 url_link = note;
255 }
256
257 url_link = url_link.trimmed ();
258 url_link.replace ("\n"," ");
259 url_link.replace (QRegExp (" +")," ");
260 url_link.replace ("<b>","");
261 url_link.replace ("</b>","");
262 url_link = QUrl::toPercentEncoding (url_link, "", "'");
263
264 QString href;
265 if (type=="\n*")
266 {
267 href="\n<img src=':/actions/icons/bookmark.png'/>";
268 }
269 else
270 {
271 href="<img src=':/actions/icons/bookmark.png'/>";
272 }
273 href += re.cap (2) + "<a href='" + url_link + "'>" + note + ":" + link + re.cap (5) + "</a>";
274 f = re.matchedLength ();
275 text.replace (i,f,href);
276 i += href.size ();
277 }
278 }
279
280 static void
281 replace_colons (QString &text)
282 {
283 QRegExp re ("`([^']+)'");
284 int i = 0, f;
285 while ( (i = re.indexIn (text, i)) != -1)
286 {
287 QString t = re.cap (1);
288 QString bold = "<b>`" + t + "</b>'";
289
290 f = re.matchedLength ();
291 text.replace (i,f,bold);
292 i += bold.size ();
293 }
294 }
295
296 static void
297 info_to_html (QString &text)
298 {
299 text.replace ("&", "&amp;");
300 text.replace ("<", "&lt;");
301 text.replace (">", "&gt;");
302
303 text.replace ("\n* Menu:", "\n<b>Menu:</b>");
304 text.replace ("*See also:*", "<b>See also:</b>");
305 replace_colons (text);
306 replace_links (text);
307 }
308
309 QString
310 parser::node_text_to_html (QString text, int anchorPos, QString anchor)
311 {
312 QString nodeName = get_node_name (text);
313 QString nodeUp = get_node_up (text);
314 QString nodeNext = get_node_next (text);
315 QString nodePrev = get_node_prev (text);
316
317 if (anchorPos > -1)
318 {
319 QString text1 = text.left (anchorPos);
320 QString text2 = text.mid (anchorPos);
321
322 int n = text1.indexOf ("\n");
323 text1.remove (0, n);
324
325 info_to_html (text1);
326 info_to_html (text2);
327
328 text = text1 + "<a name='" + anchor + "' /><img src=':/actions/icons/stop.png'>" + text2;
329 }
330 else
331 {
332 int n = text.indexOf ("\n");
333 text.remove (0, n);
334 info_to_html (text);
335 }
336
337 QString navigationLinks = QString (
338 "<img src=':/actions/icons/arrow_right.png'/> <b>Section:</b> %1<br>"
339 "<b>Previous Section:</b> <a href='%2'>%3</a><br>"
340 "<b>Next Section:</b> <a href='%4'>%5</a><br>"
341 "<b>Up:</b> <a href='%6'>%7</a><br>\n"
342 )
343 .arg (nodeName)
344 .arg (QString (QUrl::toPercentEncoding (nodePrev, "", "'")))
345 .arg (nodePrev)
346 .arg (QString (QUrl::toPercentEncoding (nodeNext, "", "'")))
347 .arg (nodeNext)
348 .arg (QString (QUrl::toPercentEncoding (nodeUp, "", "'")))
349 .arg (nodeUp);
350
351
352 text.prepend ("<hr>\n<pre>");
353 text.append ("</pre>\n<hr><hr>\n");
354 text.prepend (navigationLinks);
355 text.append (navigationLinks);
356 text.prepend ("<html><body>\n");
357 text.append ("</body></html>\n");
358 return text;
359 }
360
361 void
362 parser::parse_info_map ()
363 {
364 QRegExp re ("(Node|Ref): ([^\\0177]+)\\0177(\\d+)\n");
365 QRegExp re_files ("([^:]+): (\\d+)\n");
366 int foundCount = 0;
367
368 for(int i = 0; i < _info_files.size (); i++)
369 {
370 QFileInfo fileInfo = _info_files.at (i);
371
372 QIODevice *io = open_file (fileInfo);
373 if (io == NULL)
374 {
375 continue;
376 }
377
378 QString nodeText;
379 while (! (nodeText=get_next_node (io)).isEmpty () && foundCount < 2)
380 {
381 QString first_line = get_first_line (nodeText);
382 if (first_line.startsWith ("Tag") )
383 {
384 foundCount++;
385 int pos = 0;
386 QString last_node;
387
388 while ((pos = re.indexIn (nodeText, pos)) != -1) {
389 QString type = re.cap (1);
390 QString node = re.cap (2);
391 int index = re.cap (3).toInt ();
392
393 if (type == "Node")
394 {
395 node_map_item item;
396 item.pos = index;
397 _node_map [node] = item;
398 last_node = node;
399 }
400 else if (type == "Ref")
401 {
402 node_position item;
403 item._node_name = last_node;
404 item.pos = index;
405 _ref_map [node] = item;
406 }
407 pos += re.matchedLength ();
408 }
409 break;
410 }
411 else if (first_line.startsWith ("Indirect:"))
412 {
413 foundCount++;
414 int pos = 0;
415
416 while ( (pos = re_files.indexIn (nodeText, pos)) != -1) {
417 QString fileCap = re_files.cap (1).trimmed ();
418 int index = re_files.cap (2).toInt ();
419
420 info_file_item item;
421 for (int j = 0;j < _info_files.size (); j++)
422 {
423 QFileInfo info = _info_files.at (j);
424 if (info.fileName ().startsWith (fileCap))
425 {
426 item.file_info = info;
427 break;
428 }
429 }
430 item.real_size = index;
431 _info_file_real_size_list.append (item);
432 pos += re_files.matchedLength ();
433 }
434
435 }
436 }
437 io->close ();
438 delete io;
439 }
440 }
441
442 void
443 parser::real_position (int pos, QFileInfo & file_info, int & real_pos)
444 {
445 int header = -1, sum = 0;
446 for (int i = 0; i < _info_file_real_size_list.size (); i++)
447 {
448 info_file_item item = _info_file_real_size_list.at (i);
449 if (header == -1)
450 {
451 file_info = item.file_info;
452 header = item.real_size;
453 }
454
455 if (pos < item.real_size)
456 {
457 break;
458 }
459
460 file_info = item.file_info;
461 sum = item.real_size;
462 }
463 real_pos = pos - sum + header + 2;
464 }
465
466 void
467 parser::seek (QIODevice *io, int pos)
468 {
469 char ch;
470 while (!io->atEnd () && pos > 0)
471 {
472 io->getChar (&ch);
473 pos--;
474 }
475 }
476
477 static void
478 replace (QString &text, QRegExp re, QString after)
479 {
480 int pos = 0;
481
482 while ( (pos = re.indexIn (text, pos)) != -1)
483 {
484 QString cap = text.mid (pos,re.matchedLength ());
485 QString a (after);
486 a = a.arg (cap);
487 text.remove (pos, re.matchedLength ());
488 text.insert (pos, a);
489 pos += a.size ();
490 }
491 }
492
493 QString
494 parser::global_search (QString text, int max_founds)
495 {
496 QString results;
497 QStringList words = text.split (" ",QString::SkipEmptyParts);
498
499 QString re_program ("(" + words.at (0));
500 for (int i = 1; i < words.size (); i++)
501 {
502 re_program += "|" + words.at (i);
503 }
504 re_program += ")";
505
506 QRegExp re (re_program, Qt::CaseInsensitive);
507
508 results.append ("<html><body>\n<h1>Search results</h1>\n<b>Results for:</b> ");
509 results.append (text);
510 results.append ("<br>\n");
511
512 for (int i = 0; i < _info_files.size (); i++)
513 {
514 QFileInfo file_info = _info_files.at (i);
515 QIODevice *io = open_file (file_info);
516 if (io == NULL)
517 {
518 continue;
519 }
520
521 QString node_text;
522 while ( !(node_text = get_next_node (io)).isEmpty ())
523 {
524 QString firstLine = get_first_line (node_text);
525 QString node = get_node_name (node_text);
526 if (node.isEmpty ())
527 {
528 continue;
529 }
530
531 int n = node_text.indexOf ("\n");
532 node_text.remove (0, n);
533
534 int pos = 0;
535 int founds = 0;
536
537 for (; founds < words.size () && node_text.indexOf (words.at (founds)) >= 0; founds++)
538 { }
539
540 if (founds<words.size ())
541 {
542 continue;
543 }
544 founds = 0;
545
546 while ( (pos = re.indexIn (node_text, pos)) != -1 && founds < max_founds)
547 {
548 int line_start, line_end;
549 line_start = node_text.lastIndexOf ("\n", pos);
550 line_end = node_text.indexOf ("\n", pos);
551 QString line = node_text.mid (line_start, line_end - line_start).trimmed ();
552
553 if (founds == 0)
554 {
555 results.append(
556 "<br>\n<img src=':/actions/icons/bookmark.png'> <a href='"
557 + QString(QUrl::toPercentEncoding(node,"","'")) +
558 "'>");
559 results.append (node);
560 results.append ("</a><br>\n");
561 }
562
563 replace (line, re, "<i>%1</i>");
564 results.append (line);
565 results.append ("<br>\n");
566
567 founds++;
568
569 pos += re.matchedLength ();
570 }
571 }
572 io->close ();
573 delete io;
574 }
575
576 results.append ("</body></html>");
577 return results;
578 }