GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
parser.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2009 P. L. Lucas
4 Copyright (C) 2012-2016 Jacob Dawid
5 
6 This file is part of Octave.
7 
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 // Author: P. L. Lucas
25 // Author: Jacob Dawid <jacob.dawid@cybercatalyst.com>
26 
27 #if defined (HAVE_CONFIG_H)
28 # include "config.h"
29 #endif
30 
31 #include "parser.h"
32 #include "procstream.h"
33 #include <QFileInfo>
34 #include <QDir>
35 #include <QFile>
36 #include <QUrl>
37 #include <QRegExp>
38 #include <QBuffer>
39 
41  : QObject(p)
42 {
43  _compressors_map.insert ("bz2", "bzip2 -dc \"%1\"");
44  _compressors_map.insert ("gz", "gzip -dc \"%1\"");
45  _compressors_map.insert ("lzma", "lzma -dc \"%1\"");
46  _compressors_map.insert ("xz", "xz -dc \"%1\"");
47  _compressors_map.insert ("Z", "gunzip -c \"%1\"");
48 }
49 
50 bool
51 parser::set_info_path (const QString& infoPath)
52 {
53  this->_info_path = infoPath;
54 
55  _info_files.clear ();
56 
57  QFileInfo info (infoPath);
58 
59  bool info_file_exists = info.exists ();
60  QHash<QString, QString>::iterator it;
61  for (it = _compressors_map.begin (); it != _compressors_map.end (); it++)
62  {
63  if (info_file_exists)
64  break;
65  info_file_exists = QFileInfo (info.absoluteFilePath () + "." +
66  it.key ()).exists ();
67  }
68 
69  if (info_file_exists)
70  {
71  QString path = info.absolutePath ();
72  QString fileName = info.fileName ();
73 
74  QDir infoDir (path);
75  QStringList filter;
76  filter.append (fileName + "*");
77 
78  _info_files = infoDir.entryInfoList (filter, QDir::Files);
79 
80  parse_info_map ();
81 
82  return true;
83  }
84  else
85  return false;
86 }
87 
88 QString
90 {
91  return _info_path;
92 }
93 
94 QIODevice *
95 parser::open_file (QFileInfo & file_info)
96 {
97  QIODevice *iodevice = 0;
98  if (_compressors_map.contains (file_info.suffix ()))
99  {
100  QString command = _compressors_map.value (file_info.suffix ()).arg (
101  file_info.absoluteFilePath ());
102  iprocstream ips (command.toStdString ());
103 
104  if (ips.bad ())
105  return 0;
106 
107  QByteArray result;
108  char buffer[1024];
109 
110  while (! ips.eof ())
111  {
112  ips.read (buffer, sizeof (buffer));
113  result.append (buffer, ips.gcount ());
114  }
115 
116  QBuffer *io = new QBuffer (this);
117  io->setData (result);
118 
119  if (! io->open (QIODevice::ReadOnly | QIODevice::Text))
120  return 0;
121 
122  iodevice = io;
123  }
124  else
125  {
126  QFile *io = new QFile (file_info.absoluteFilePath ());
127  if (! io->open (QIODevice::ReadOnly | QIODevice::Text))
128  return 0;
129  iodevice = io;
130  }
131 
132  return iodevice;
133 }
134 
135 int
136 parser::is_ref (const QString& node)
137 {
138  if (_ref_map.contains (node))
139  {
140  node_position ref = _ref_map [node];
141 
142  return ref.pos-_node_map [ref._node_name].pos;
143  }
144  if (_node_map.contains (node))
145  {
146  return 0; // node: show from the beginning
147  }
148  return -1;
149 }
150 
151 QString
152 parser::search_node (const QString& node_arg)
153 {
154  QString node = node_arg;
155 
156  QFileInfo file_info;
157  QString ref;
158 
159  if (_ref_map.contains (node))
160  {
161  ref = node;
162  node = _ref_map [ref]._node_name;
163  }
164 
165  if (_node_map.contains (node))
166  {
167  int pos = _node_map [node].pos;
168  int realPos;
169 
170  real_position (pos, file_info, realPos);
171 
172  QIODevice *io = open_file (file_info);
173  if (! io)
174  {
175  return QString ();
176  }
177 
178  seek (io, realPos);
179 
180  QString text = get_next_node (io);
181  if (! text.isEmpty())
182  {
183  return text;
184  }
185 
186  io->close ();
187  delete io;
188  }
189 
190  return QString ();
191 }
192 
193 QString
194 parser::search_node (const QString& node, QIODevice *io)
195 {
196  while (! io->atEnd ())
197  {
198  QString text = get_next_node (io);
199  if (node == get_node_name (text))
200  {
201  return text;
202  }
203  }
204 
205  return QString ();
206 }
207 
208 QString
209 parser::get_next_node (QIODevice *io)
210 {
211  QString text;
212  QByteArray line, line_buffer;
213  char c;
214  int i;
215 
216  while (! io->atEnd ())
217  {
218  io->getChar (&c);
219  if (c)
220  {
221  // first char is not equal 0
222  io->ungetChar (c);
223  line = io->readLine ();
224  }
225  else
226  {
227  // 0 was read -> image -> text length changes
228  line_buffer = io->readLine (); // image tag that is not needed
229  line = io->readLine (); // firsts line of text message
230  for (i=1; i<line_buffer.size ()+6; i++) // correct the size
231  line.insert (line.size ()-1,QByteArray(" ")); // by adding blanks
232  }
233 
234  if (line.at (0) == '"' && line.size () == 5) // end of image construct
235  line = " ";
236 
237  if (line.at(0) == 31)
238  {
239  break;
240  }
241  else
242  {
243  text.append (QString::fromUtf8 (line));
244  }
245  }
246  return text;
247 }
248 
249 static QString
250 get_first_line (const QString& text)
251 {
252  int n = text.indexOf ("\n");
253 
254  if (n < 0)
255  {
256  return QString ();
257  }
258 
259  QString first_line = text.left (n);
260  return first_line;
261 }
262 
263 static QString
264 parser_node (const QString& text, const QString& node_name)
265 {
266  QString firstLine = get_first_line (text);
267  QStringList nodes = firstLine.split (",");
268  for (int i = 0; i < nodes.size (); i++)
269  {
270  QString node = nodes.at (i).trimmed ();
271 
272  if (node.startsWith (node_name))
273  {
274  return node.remove (0, node_name.size ()).trimmed ();
275  }
276  }
277  return QString ();
278 }
279 
280 QString
281 parser::get_node_name (const QString& text)
282 {
283  return parser_node (text, "Node:");
284 }
285 
286 QString
287 parser::get_node_up (const QString& text)
288 {
289  return parser_node (text, "Up:");
290 }
291 
292 QString
293 parser::get_node_next (const QString& text)
294 {
295  return parser_node (text, "Next:");
296 }
297 
298 QString
299 parser::get_node_prev (const QString& text)
300 {
301  return parser_node (text, "Prev:");
302 }
303 
304 static void
305 replace_links (QString& text)
306 {
307  QRegExp re ("(\\*[N|n]ote|\n\\*)([ |\n]+)([^:]+):([^:\\.,]*)([:,\\.]+)");
308  int i = 0, f;
309 
310  while ((i = re.indexIn (text,i)) != -1)
311  {
312  QString type = re.cap (1);
313  QString note = re.cap (3);
314  QString url_link = re.cap (4);
315  QString term = re.cap (5);
316 
317  if (url_link.isEmpty ())
318  {
319  url_link = note;
320  }
321 
322  term.replace(":","");
323  note.replace(":","");
324  note.replace (QRegExp ("`([^']+)'"),"\\1"); // no extra format in links
325 
326  QRegExp re_break ("(\n[ ]*)");
327 
328  if (note == "fig" || note == "tab")
329  url_link.prepend("#");
330 
331  QString href;
332  if (type == "\n*")
333  href="\n";
334 
335  if (re_break.indexIn (url_link) != -1)
336  term += re_break.cap (1);
337  else if (re_break.indexIn (re.cap (2)) != -1)
338  href = re_break.cap (1) + " ";
339  else if (re_break.indexIn (note) != -1)
340  term += re_break.cap (1);
341  note.replace(re_break,"&nbsp;");
342 
343  url_link = url_link.trimmed ();
344  url_link.replace ("\n"," ");
345  url_link.replace (QRegExp (" +")," ");
346  url_link.replace ("<b>","");
347  url_link.replace ("</b>","");
348 
349  href += "<font style=\"color:DarkGray; font-weight:bold;\">&raquo;</font>";
350  href += "&nbsp;<a href='" + url_link + "'>" + note + "</a>" + term;
351  f = re.matchedLength ();
352  text.replace (i,f,href);
353  i += href.size ();
354  }
355 }
356 
357 static void
359 {
360  QRegExp re ("`([^']+)'");
361  int i = 0, f;
362  while ((i = re.indexIn (text, i)) != -1)
363  {
364  QString t = re.cap (1);
365  QString bold = "<font style=\"color:SteelBlue;font-weight:bold\">" + t +
366  "</font>";
367 
368  f = re.matchedLength ();
369  text.replace (i,f,bold);
370  i += bold.size ();
371  }
372 }
373 
374 static void
375 info_to_html (QString& text)
376 {
377  text.replace ("&", "&amp;");
378  text.replace ("<", "&lt;");
379  text.replace (">", "&gt;");
380 
381  text.replace ("\n* Menu:",
382  "\n<font style=\"color:DarkRed;font-weight:bold\">Menu:</font>");
383  text.replace ("See also:",
384  "<font style=\"color:DarkRed;font-style:italic;font-weight:bold\">See also:</font>");
385  replace_links (text);
386  replace_colons (text);
387 }
388 
389 QString
390 parser::node_text_to_html (const QString& text_arg, int anchorPos,
391  const QString& anchor)
392 {
393  QString text = text_arg;
394 
395  QString nodeName = get_node_name (text);
396  QString nodeUp = get_node_up (text);
397  QString nodeNext = get_node_next (text);
398  QString nodePrev = get_node_prev (text);
399 
400  if (anchorPos > -1)
401  {
402  QString text1 = text.left (anchorPos);
403  QString text2 = text.mid (anchorPos);
404 
405  int n = text1.indexOf ("\n");
406  text1.remove (0, n);
407 
408  info_to_html (text1);
409  info_to_html (text2);
410 
411  text = text1 + "<a name='" + anchor
412  + "'/><font style=\"color:DarkBlue; font: bold monospace large;\">&diams;</font><br>&nbsp;"
413  + text2;
414  }
415  else
416  {
417  int n = text.indexOf ("\n");
418  text.remove (0, n);
419  info_to_html (text);
420  }
421 
422  QString navigationLinks = QString (
423  "<b>Section:</b> <font style=\"color:DarkRed\">%1</font><br>"
424  "<b>Previous Section:</b> <a href='%2'>%3</a><br>"
425  "<b>Next Section:</b> <a href='%4'>%5</a><br>"
426  "<b>Up:</b> <a href='%6'>%7</a><br>\n"
427  )
428  .arg (nodeName, nodePrev, nodePrev, nodeNext, nodeNext, nodeUp, nodeUp);
429 
430  text.prepend ("<hr>\n<pre style=\"font-family:monospace\">");
431  text.append ("</pre>\n<hr><hr>\n");
432  text.prepend (navigationLinks);
433  text.append (navigationLinks);
434  text.prepend ("<html><body>\n");
435  text.append ("</body></html>\n");
436 
437  return text;
438 
439 }
440 
441 void
443 {
444  QRegExp re ("(Node|Ref): ([^\\0177]+)\\0177(\\d+)\n");
445  QRegExp re_files ("([^:]+): (\\d+)\n");
446  int foundCount = 0;
447 
448  for (int i = 0; i < _info_files.size (); i++)
449  {
450  QFileInfo fileInfo = _info_files.at (i);
451 
452  QIODevice *io = open_file (fileInfo);
453  if (! io)
454  {
455  continue;
456  }
457 
458  QString nodeText;
459  while (! (nodeText=get_next_node (io)).isEmpty () && foundCount < 2)
460  {
461  QString first_line = get_first_line (nodeText);
462  if (first_line.startsWith ("Tag"))
463  {
464  foundCount++;
465  int pos = 0;
466  QString last_node;
467 
468  while ((pos = re.indexIn (nodeText, pos)) != -1)
469  {
470  QString type = re.cap (1);
471  QString node = re.cap (2);
472  int index = re.cap (3).toInt ();
473 
474  if (type == "Node")
475  {
476  node_map_item item;
477  item.pos = index;
478  _node_map [node] = item;
479  last_node = node;
480  }
481  else if (type == "Ref")
482  {
483  node_position item;
484  item._node_name = last_node;
485  item.pos = index;
486  _ref_map [node] = item;
487  }
488  pos += re.matchedLength ();
489  }
490  break;
491  }
492  else if (first_line.startsWith ("Indirect:"))
493  {
494  foundCount++;
495  int pos = 0;
496 
497  while ((pos = re_files.indexIn (nodeText, pos)) != -1)
498  {
499  QString fileCap = re_files.cap (1).trimmed ();
500  int index = re_files.cap (2).toInt ();
501 
502  info_file_item item;
503  for (int j = 0; j < _info_files.size (); j++)
504  {
505  QFileInfo info = _info_files.at (j);
506  if (info.fileName ().startsWith (fileCap))
507  {
508  item.file_info = info;
509  break;
510  }
511  }
512  item.real_size = index;
513  _info_file_real_size_list.append (item);
514  pos += re_files.matchedLength ();
515  }
516 
517  }
518  }
519  io->close ();
520  delete io;
521  }
522 }
523 
524 void
525 parser::real_position (int pos, QFileInfo & file_info, int & real_pos)
526 {
527  int header = -1;
528  int sum = 0;
529  for (int i = 0; i < _info_file_real_size_list.size (); i++)
530  {
532  if (header == -1)
533  {
534  file_info = item.file_info;
535  header = item.real_size;
536  }
537 
538  if (pos < item.real_size)
539  {
540  break;
541  }
542 
543  file_info = item.file_info;
544  sum = item.real_size;
545  }
546  real_pos = pos - sum + header + 2;
547 }
548 
549 void
550 parser::seek (QIODevice *io, int pos)
551 {
552  char ch;
553  while (! io->atEnd () && pos > 0)
554  {
555  io->getChar (&ch);
556  pos--;
557  }
558 }
559 
560 static void
561 replace (QString& text, const QRegExp& re, const QString& after)
562 {
563  int pos = 0;
564 
565  while ((pos = re.indexIn (text, pos)) != -1)
566  {
567  QString cap = text.mid (pos,re.matchedLength ());
568  QString a (after);
569  a = a.arg (cap);
570  text.remove (pos, re.matchedLength ());
571  text.insert (pos, a);
572  pos += a.size ();
573  }
574 }
575 
576 QString
577 parser::global_search (const QString& text, int max_founds)
578 {
579  QString results;
580  QStringList words = text.split (" ",QString::SkipEmptyParts);
581 
582  QString re_program ("(" + QRegExp::escape (words.at (0)));
583  for (int i = 1; i < words.size (); i++)
584  {
585  re_program += "|" + QRegExp::escape (words.at (i));
586  }
587  re_program += ")";
588 
589  QRegExp re (re_program, Qt::CaseInsensitive);
590 
591  results.append ("<html><body>\n<h1>Search results</h1>\n<b>Results for:</b> ");
592  results.append (text);
593  results.append ("<br>\n");
594 
595  for (int i = 0; i < _info_files.size (); i++)
596  {
597  QFileInfo file_info = _info_files.at (i);
598  QIODevice *io = open_file (file_info);
599  if (! io)
600  {
601  continue;
602  }
603 
604  QString node_text;
605  while (! (node_text = get_next_node (io)).isEmpty ())
606  {
607  QString firstLine = get_first_line (node_text);
608  QString node = get_node_name (node_text);
609  if (node.isEmpty ())
610  {
611  continue;
612  }
613 
614  int n = node_text.indexOf ("\n");
615  node_text.remove (0, n);
616 
617  int pos = 0;
618  int founds = 0;
619 
620  for (; founds < words.size ()
621  && node_text.indexOf (words.at (founds)) >= 0; founds++)
622  { }
623 
624  if (founds<words.size ())
625  {
626  continue;
627  }
628  founds = 0;
629 
630  while ((pos = re.indexIn (node_text, pos)) != -1
631  && founds < max_founds)
632  {
633  int line_start, line_end;
634  line_start = node_text.lastIndexOf ("\n", pos);
635  line_end = node_text.indexOf ("\n", pos);
636  QString line = node_text.mid (line_start,
637  line_end - line_start).trimmed ();
638  pos += re.matchedLength ();
639 
640  if (founds == 0)
641  {
642  results.append(
643  "<br>\n<font style=\"color:DarkGray; font-weight:bold;\">&raquo;</font> <a href='"
644  + node +
645  "'>");
646  results.append (node);
647  results.append ("</a><br>\n");
648  }
649 
650  replace (line, re, "<i>%1</i>");
651  results.append (line);
652  results.append ("<br>\n");
653 
654  founds++;
655  }
656  }
657  io->close ();
658  delete io;
659  }
660 
661  results.append ("</body></html>");
662  return results;
663 }
664 
665 QString
666 parser::find_ref (const QString &ref_name)
667 {
668  QString text = "";
669 
670  QHash<QString,node_position>::iterator it;
671  for (it=_ref_map.begin (); it!=_ref_map.end (); ++it)
672  {
673  QString k = it.key ();
674  node_position p = it.value ();
675 
676  if (k == "XREF" + ref_name)
677  {
678  // found ref, so return its name
679  text = "XREF" + ref_name;
680  break;
681  }
682  }
683 
684  if (text.isEmpty ()) // try the statement-nodes
685  {
686  QHash<QString, node_map_item>::iterator itn;
687  for (itn=_node_map.begin (); itn!=_node_map.end (); ++itn)
688  {
689  QString k = itn.key ();
690  if (k == "The " + ref_name + " Statement")
691  {
692  // found ref, so return its name
693  text = k;
694  break;
695  }
696  }
697  }
698 
699  return text;
700 }
QList< info_file_item > _info_file_real_size_list
Definition: parser.h:122
QString get_node_name(const QString &text)
Definition: parser.cc:281
QString _node_name
Definition: parser.h:80
the element is set to zero In other words
Definition: data.cc:5342
void seek(QIODevice *io, int pos)
Seeks to position pos.
Definition: parser.cc:550
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE const F77_DBLE * f
QString global_search(const QString &text, int maxFounds)
Definition: parser.cc:577
QString get_next_node(QIODevice *io)
Definition: parser.cc:209
for large enough k
Definition: lu.cc:606
QFileInfo file_info
Definition: parser.h:91
QIODevice * open_file(QFileInfo &fileInfo)
Open info files and uncompress them.
Definition: parser.cc:95
QString get_node_next(const QString &text)
Definition: parser.cc:293
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function t
Definition: ov-usr-fcn.cc:935
to define functions rather than attempting to enter them directly on the command line The block of commands is executed as soon as you exit the editor To avoid executing any simply delete all the lines from the buffer before leaving the editor When invoked with no edit the previously executed command
Definition: oct-hist.cc:587
QHash< QString, node_position > _ref_map
Definition: parser.h:121
octave_value arg
Definition: pr-output.cc:3440
calling an anonymous function involves an overhead quite comparable to the overhead of an m file function Passing a handle to a built in function is because the interpreter is not involved in the internal loop For a
Definition: cellfun.cc:398
QHash< QString, QString > _compressors_map
Definition: parser.h:123
static QString get_first_line(const QString &text)
Definition: parser.cc:250
static void replace_links(QString &text)
Definition: parser.cc:305
QString get_info_path()
Definition: parser.cc:89
QFileInfoList _info_files
Definition: parser.h:119
static void replace(QString &text, const QRegExp &re, const QString &after)
Definition: parser.cc:561
void parse_info_map()
Parses info files and gets map of node positions.
Definition: parser.cc:442
void real_position(int pos, QFileInfo &file_info, int &real_pos)
Calculates real position of nodes.
Definition: parser.cc:525
QString _info_path
Definition: parser.h:118
idx type
Definition: ov.cc:3129
static QString parser_node(const QString &text, const QString &node_name)
Definition: parser.cc:264
MArray< T > filter(MArray< T > &b, MArray< T > &a, MArray< T > &x, MArray< T > &si, int dim=0)
Definition: filter.cc:43
the sparsity preserving column transformation such that that defines the pivoting threshold can be given in which case it defines the c
Definition: lu.cc:138
parser(QObject *parent=0)
Definition: parser.cc:40
With real return the complex result
Definition: data.cc:3375
QHash< QString, node_map_item > _node_map
Definition: parser.h:120
QString node_text_to_html(const QString &text, int anchorPos=-1, const QString &anchor=QString())
Translates text of node to Html.
Definition: parser.cc:390
OCTAVE_EXPORT octave_value_list the first data row corresponds to an index of zero The a spreadsheet style form such as the file is read until end of file is reached The such as text
Definition: dlmread.cc:191
int is_ref(const QString &node)
Checks if this node is reference.
Definition: parser.cc:136
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
bool set_info_path(const QString &_info_path)
Definition: parser.cc:51
p
Definition: lu.cc:138
QString find_ref(const QString &name)
Definition: parser.cc:666
QString get_node_prev(const QString &text)
Definition: parser.cc:299
static void info_to_html(QString &text)
Definition: parser.cc:375
QString search_node(const QString &node)
Definition: parser.cc:152
QString get_node_up(const QString &text)
Definition: parser.cc:287
static void replace_colons(QString &text)
Definition: parser.cc:358