~ubuntu-branches/debian/sid/octave3.0/sid

« back to all changes in this revision

Viewing changes to src/DLD-FUNCTIONS/regexp.cc

  • Committer: Bazaar Package Importer
  • Author(s): Rafael Laboissiere
  • Date: 2009-04-28 15:17:35 UTC
  • mfrom: (6.1.4 sid)
  • Revision ID: james.westby@ubuntu.com-20090428151735-gm59wmfcmwec3f9e
Tags: 1:3.0.5-3
debian/in/PACKAGE.postinst: Add -verbose option when calling 'pkg
rebuild' in octave and redirect stdin from /dev/null.  This is just to
help debugging the hang up on the mipsel buildd when installing
octave3.0 for building other packages (Bug#524745).

Show diffs side-by-side

added added

removed removed

Lines of Context:
52
52
#include <regex.h>
53
53
#endif
54
54
 
 
55
// Define the maximum number of retries for a pattern that 
 
56
// possibly results in an infinite recursion.
 
57
#define PCRE_MATCHLIMIT_MAX 10
 
58
 
55
59
// The regexp is constructed as a linked list to avoid resizing the
56
60
// return values in arrays at each new match.
57
61
 
80
84
 
81
85
typedef std::list<regexp_elem>::const_iterator const_iterator;
82
86
 
 
87
#define MAXLOOKBEHIND 10
 
88
static bool lookbehind_warned = false;
 
89
 
83
90
static int
84
91
octregexp_list (const octave_value_list &args, const std::string &nm, 
85
92
                bool case_insensitive, std::list<regexp_elem> &lst, 
86
 
                string_vector &named, int &nopts)
 
93
                string_vector &named, int &nopts, bool &once)
87
94
{
88
95
  int sz = 0;
89
96
#if defined (HAVE_REGEX) || defined (HAVE_PCRE) 
90
97
  int nargin = args.length();
91
 
  bool once = false;
92
98
  bool lineanchors = false;
93
99
  bool dotexceptnewline = false;
94
100
  bool freespacing = false;
95
101
 
96
102
  nopts = nargin - 2;
 
103
  once = false;
97
104
 
98
105
  std::string buffer = args(0).string_value ();
 
106
  size_t max_length = (buffer.length () > MAXLOOKBEHIND ? 
 
107
                       MAXLOOKBEHIND: buffer.length ());
 
108
 
99
109
  if (error_state)
100
110
    {
101
111
      gripe_wrong_type_arg (nm.c_str(), args(0));
190
200
 
191
201
      // named tokens "(?<name>...)" are only treated with PCRE not regex.
192
202
#if HAVE_PCRE
193
 
      // The syntax of named tokens in pcre is "(?P<name>...)" while we need
194
 
      // a syntax "(?<name>...)", so fix that here. Also an expression like
195
 
      // "(?<first>\w+)\s+(?<last>\w+)|(?<last>\w+),\s+(?<first>\w+)" should
196
 
      // be perfectly legal, while pcre does not allow the same named token
197
 
      // name on both sides of the alternative. Also fix that here by replacing
198
 
      // name tokens by dummy names, and dealing with the dummy names later.
199
203
      
200
204
      size_t pos = 0;
201
205
      size_t new_pos;
204
208
      std::ostringstream buf;
205
209
      Array<int> named_idx;
206
210
 
207
 
      while ((new_pos = pattern.find ("(?<",pos)) != NPOS)
 
211
      while ((new_pos = pattern.find ("(?",pos)) != NPOS)
208
212
        {
209
 
          size_t tmp_pos = pattern.find_first_of ('>',new_pos);
210
 
 
211
 
          if (tmp_pos == NPOS)
212
 
            {
213
 
              error ("syntax error in pattern");
214
 
              break;
215
 
            }
216
 
 
217
 
          std::string tmp_name = pattern.substr(new_pos+3,tmp_pos-new_pos-3);
218
 
          bool found = false;
219
 
 
220
 
          for (int i = 0; i < nnames; i++)
221
 
            if (named(i) == tmp_name)
222
 
              {
223
 
                named_idx.resize(inames+1);
224
 
                named_idx(inames) = i;
225
 
                found = true;
226
 
                break;
227
 
              }
228
 
          if (! found)
229
 
            {
230
 
              named_idx.resize(inames+1);
231
 
              named_idx(inames) = nnames;
232
 
              named.append(tmp_name);
233
 
              nnames++;
234
 
            }
235
 
 
236
 
          if (new_pos - pos > 0)
237
 
            buf << pattern.substr(pos,new_pos-pos);
238
 
          if (inames < 10)
239
 
            buf << "(?P<n00" << inames++;
240
 
          else if (inames < 100)
241
 
            buf << "(?P<n0" << inames++;
 
213
          if (pattern.at (new_pos + 2) == '<' &&  
 
214
              !(pattern.at (new_pos + 3) == '=' ||
 
215
                pattern.at (new_pos + 3) == '!'))
 
216
            {
 
217
              // The syntax of named tokens in pcre is "(?P<name>...)" while
 
218
              // we need a syntax "(?<name>...)", so fix that here. Also an 
 
219
              // expression like 
 
220
              // "(?<first>\w+)\s+(?<last>\w+)|(?<last>\w+),\s+(?<first>\w+)" 
 
221
              // should be perfectly legal, while pcre does not allow the same
 
222
              // named token name on both sides of the alternative. Also fix
 
223
              // that here by replacing name tokens by dummy names, and dealing
 
224
              // with the dummy names later.
 
225
 
 
226
              size_t tmp_pos = pattern.find_first_of ('>',new_pos);
 
227
 
 
228
              if (tmp_pos == NPOS)
 
229
                {
 
230
                  error ("syntax error in pattern");
 
231
                  break;
 
232
                }
 
233
 
 
234
              std::string tmp_name = 
 
235
                pattern.substr(new_pos+3,tmp_pos-new_pos-3);
 
236
              bool found = false;
 
237
 
 
238
              for (int i = 0; i < nnames; i++)
 
239
                if (named(i) == tmp_name)
 
240
                  {
 
241
                    named_idx.resize(inames+1);
 
242
                    named_idx(inames) = i;
 
243
                    found = true;
 
244
                    break;
 
245
                  }
 
246
              if (! found)
 
247
                {
 
248
                  named_idx.resize(inames+1);
 
249
                  named_idx(inames) = nnames;
 
250
                  named.append(tmp_name);
 
251
                  nnames++;
 
252
                }
 
253
 
 
254
              if (new_pos - pos > 0)
 
255
                buf << pattern.substr(pos,new_pos-pos);
 
256
              if (inames < 10)
 
257
                buf << "(?P<n00" << inames++;
 
258
              else if (inames < 100)
 
259
                buf << "(?P<n0" << inames++;
 
260
              else
 
261
                buf << "(?P<n" << inames++;
 
262
              pos = tmp_pos;
 
263
            }
 
264
          else if (pattern.at (new_pos + 2) == '<')
 
265
            {
 
266
              // Find lookbehind operators of arbitrary length (ie like 
 
267
              // "(?<=[a-z]*)") and replace with a maximum length operator 
 
268
              // as PCRE can not yet handle arbitrary length lookahead 
 
269
              // operators. Use the string length as the maximum length to 
 
270
              // avoid issues.
 
271
 
 
272
              int brackets = 1;
 
273
              size_t tmp_pos1 = new_pos + 2;
 
274
              size_t tmp_pos2 = tmp_pos1;
 
275
              while (tmp_pos1 <= pattern.length () && brackets > 0)
 
276
                {
 
277
                  char ch = pattern.at (tmp_pos1);
 
278
                  if (ch == '(')
 
279
                    brackets++;
 
280
                  else if (ch == ')')
 
281
                    {
 
282
                      if (brackets > 1)
 
283
                        tmp_pos2 = tmp_pos1;
 
284
 
 
285
                      brackets--;
 
286
                    }
 
287
                  tmp_pos1++;
 
288
                }
 
289
 
 
290
              if (brackets != 0)
 
291
                {
 
292
                  buf << pattern.substr (pos, new_pos - pos) << "(?";
 
293
                  pos = new_pos + 2;
 
294
                }
 
295
              else
 
296
                {
 
297
                  size_t tmp_pos3 = pattern.find_first_of ("*+", tmp_pos2);
 
298
                  if (tmp_pos3 != NPOS && tmp_pos3 < tmp_pos1)
 
299
                    {
 
300
                      if (!lookbehind_warned)
 
301
                        {
 
302
                          lookbehind_warned = true;
 
303
                          warning ("%s: arbitrary length lookbehind patterns are only support up to length %d", nm.c_str(), MAXLOOKBEHIND);
 
304
                        }
 
305
 
 
306
                      buf << pattern.substr (pos, new_pos - pos) << "(";
 
307
 
 
308
                      size_t i;
 
309
                      if (pattern.at (tmp_pos3) == '*')
 
310
                        i = 0;
 
311
                      else
 
312
                        i = 1;
 
313
 
 
314
                      for (; i < max_length + 1; i++)
 
315
                        {
 
316
                          buf <<pattern.substr(new_pos, tmp_pos3 - new_pos)
 
317
                              << "{" << i << "}";
 
318
                          buf << pattern.substr(tmp_pos3 + 1, 
 
319
                                                tmp_pos1 - tmp_pos3 - 1);
 
320
                          if (i != max_length)
 
321
                            buf << "|";
 
322
                        }
 
323
                      buf << ")";
 
324
                    }
 
325
                  else
 
326
                    buf << pattern.substr (pos, tmp_pos1 - pos);
 
327
                  pos = tmp_pos1;
 
328
                }
 
329
            }
242
330
          else
243
 
            buf << "(?P<n" << inames++;
244
 
          pos = tmp_pos;
 
331
            {
 
332
              buf << pattern.substr (pos, new_pos - pos) << "(?";
 
333
              pos = new_pos + 2;
 
334
            }
 
335
 
245
336
        }
246
337
 
247
338
      buf << pattern.substr(pos);
298
389
                                  (idx ? PCRE_NOTBOL : 0),
299
390
                                  ovector, (subpatterns+1)*3);
300
391
 
 
392
          if (matches == PCRE_ERROR_MATCHLIMIT)
 
393
            {
 
394
              // try harder; start with default value for MATCH_LIMIT and increase it
 
395
              warning("Your pattern caused PCRE to hit its MATCH_LIMIT.\nTrying harder now, but this will be slow.");
 
396
              pcre_extra pe;
 
397
              pcre_config(PCRE_CONFIG_MATCH_LIMIT, static_cast <void *> (&pe.match_limit));
 
398
              pe.flags = PCRE_EXTRA_MATCH_LIMIT;
 
399
 
 
400
              int i = 0;
 
401
              while (matches == PCRE_ERROR_MATCHLIMIT &&
 
402
                     i++ < PCRE_MATCHLIMIT_MAX)
 
403
                {
 
404
                  OCTAVE_QUIT;
 
405
 
 
406
                  pe.match_limit *= 10;
 
407
                  matches = pcre_exec(re, &pe, buffer.c_str(), 
 
408
                                      buffer.length(), idx, 
 
409
                                      (idx ? PCRE_NOTBOL : 0),
 
410
                                      ovector, (subpatterns+1)*3);
 
411
                }
 
412
            }
 
413
 
301
414
          if (matches < 0 && matches != PCRE_ERROR_NOMATCH)
302
415
            {
303
 
              error ("%s: internal error calling pcre_exec", nm.c_str());
 
416
              error ("%s: internal error calling pcre_exec\nError code from pcre_exec is %i", nm.c_str(), matches);
304
417
              pcre_free(re);
305
418
              return 0;
306
419
            }
451
564
  std::list<regexp_elem> lst;
452
565
  string_vector named;
453
566
  int nopts;
454
 
  int sz = octregexp_list (args, nm, case_insensitive, lst, named, nopts);
 
567
  bool once;
 
568
  int sz = octregexp_list (args, nm, case_insensitive, lst, named, nopts, once);
455
569
 
456
570
  if (! error_state)
457
571
    {
482
596
      retval(5) = Octave_map();
483
597
#endif
484
598
 
485
 
      Cell t (dim_vector(1, sz));
486
 
      i = 0;
487
 
      for (const_iterator p = lst.begin(); p != lst.end(); p++)
488
 
        t(i++) = p->t;
489
 
      retval(4) = t;
490
 
 
491
 
      Cell m (dim_vector(1, sz));
492
 
      i = 0;
493
 
      for (const_iterator p = lst.begin(); p != lst.end(); p++)
494
 
        m(i++) = p->m;
495
 
      retval(3) = m;
496
 
 
497
 
 
498
 
      Cell te (dim_vector(1, sz));
499
 
      i = 0;
500
 
      for (const_iterator p = lst.begin(); p != lst.end(); p++)
501
 
        te(i++) = p->te;
502
 
      retval(2) = te;
503
 
 
504
 
      NDArray e (dim_vector(1, sz));
505
 
      i = 0;
506
 
      for (const_iterator p = lst.begin(); p != lst.end(); p++)
507
 
        e(i++) = p->e;
508
 
      retval(1) = e;
509
 
 
 
599
      if (once)
 
600
        retval(4) = sz ? lst.front ().t : Cell();
 
601
      else
 
602
        {
 
603
          Cell t (dim_vector(1, sz));
 
604
          i = 0;
 
605
          for (const_iterator p = lst.begin(); p != lst.end(); p++)
 
606
            t(i++) = p->t;
 
607
          retval(4) = t;
 
608
        }
 
609
 
 
610
      if (once)
 
611
        retval(3) = sz ? lst.front ().m : std::string();
 
612
      else
 
613
        {
 
614
          Cell m (dim_vector(1, sz));
 
615
          i = 0;
 
616
          for (const_iterator p = lst.begin(); p != lst.end(); p++)
 
617
            m(i++) = p->m;
 
618
          retval(3) = m;
 
619
        }
 
620
 
 
621
      if (once)
 
622
        retval(2) = sz ? lst.front ().te : Matrix();
 
623
      else
 
624
        {
 
625
          Cell te (dim_vector(1, sz));
 
626
          i = 0;
 
627
          for (const_iterator p = lst.begin(); p != lst.end(); p++)
 
628
            te(i++) = p->te;
 
629
          retval(2) = te;
 
630
        }
 
631
 
 
632
      if (once)
 
633
        {
 
634
          if (sz)
 
635
            retval(1) = lst.front ().e;
 
636
          else
 
637
            retval(1) = Matrix();
 
638
        }
 
639
      else
 
640
        {
 
641
          NDArray e (dim_vector(1, sz));
 
642
          i = 0;
 
643
          for (const_iterator p = lst.begin(); p != lst.end(); p++)
 
644
            e(i++) = p->e;
 
645
          retval(1) = e;
 
646
        }
 
647
 
 
648
      if (once)
 
649
        {
 
650
          if (sz)
 
651
            retval(0) = lst.front ().s;
 
652
          else
 
653
            retval(0) = Matrix();
 
654
        }
 
655
      else
 
656
        {
510
657
      NDArray s (dim_vector(1, sz));
511
658
      i = 0;
512
659
      for (const_iterator p = lst.begin(); p != lst.end(); p++)
513
660
        s(i++) = p->s;
514
661
      retval(0) = s;
 
662
        }
515
663
 
516
664
      // Alter the order of the output arguments
517
665
      if (nopts > 0)
862
1010
 
863
1011
/*
864
1012
 
 
1013
## PCRE_ERROR_MATCHLIMIT test
 
1014
%!test
 
1015
%! s=sprintf('\t4\n0000\t-0.00\t-0.0000\t4\t-0.00\t-0.0000\t4\n0000\t-0.00\t-0.0000\t0\t-0.00\t-');
 
1016
%! ws = warning("query");
 
1017
%! unwind_protect
 
1018
%!   warning("off");
 
1019
%!   regexp(s, '(\s*-*\d+[.]*\d*\s*)+\n');
 
1020
%! unwind_protect_cleanup
 
1021
%!   warning(ws);
 
1022
%! end_unwind_protect
 
1023
 
865
1024
## seg-fault test
866
1025
%!assert(regexp("abcde","."),[1,2,3,4,5])
867
1026
 
911
1070
%! [s, e, te, m, t] = regexp('short test string','\w*r\w*','once');
912
1071
%! assert (s,1)
913
1072
%! assert (e,5)
914
 
%! assert (size(te), [1,1])
915
 
%! assert (isempty(te{1}))
916
 
%! assert (m{1},'short')
917
 
%! ## Matlab gives [1,0] here but that seems wrong.
918
 
%! assert (size(t), [1,1])
 
1073
%! assert (isempty(te))
 
1074
%! assert (m,'short')
 
1075
%! assert (isempty(t))
919
1076
 
920
1077
%!test
921
1078
%! [m, te, e, s, t] = regexp('short test string','\w*r\w*','once', 'match', 'tokenExtents', 'end', 'start', 'tokens');
922
1079
%! assert (s,1)
923
1080
%! assert (e,5)
924
 
%! assert (size(te), [1,1])
925
 
%! assert (isempty(te{1}))
926
 
%! assert (m{1},'short')
927
 
%! ## Matlab gives [1,0] here but that seems wrong.
928
 
%! assert (size(t), [1,1])
 
1081
%! assert (isempty(te))
 
1082
%! assert (m,'short')
 
1083
%! assert (isempty(t))
929
1084
 
930
1085
%!testif HAVE_PCRE
931
1086
%! ## This test is expected to fail if PCRE is not installed
1011
1166
%!assert(regexp({'asdfg-dfd';'-dfd-dfd-';'qasfdfdaq'},{'-';'f';'q'}),{6;[3,7];[1,9]})
1012
1167
%!assert(regexp('Strings',{'t','s'}),{2,7})
1013
1168
 
 
1169
## Test case for lookaround operators
 
1170
%!assert(regexp('Iraq','q(?!u)'),4)
 
1171
%!assert(regexp('quit','q(?!u)'), zeros(1,0))
 
1172
%!assert(regexp('quit','q(?=u)','match'), {'q'})
 
1173
%!assert(regexp("quit",'q(?=u+)','match'), {'q'})
 
1174
%!assert(regexp("qit",'q(?=u+)','match'), cell(1,0))
 
1175
%!assert(regexp("qit",'q(?=u*)','match'), {'q'})
 
1176
 
 
1177
%!assert(regexp('thingamabob','(?<=a)b'), 9)
 
1178
 
1014
1179
*/
1015
1180
 
1016
1181
DEFUN_DLD (regexpi, args, nargout,
1087
1252
%! [s, e, te, m, t] = regexpi('ShoRt Test String','\w*r\w*','once');
1088
1253
%! assert (s,1)
1089
1254
%! assert (e,5)
1090
 
%! assert (size(te), [1,1])
1091
 
%! assert (isempty(te{1}))
1092
 
%! assert (m{1},'ShoRt')
1093
 
%! ## Matlab gives [1,0] here but that seems wrong.
1094
 
%! assert (size(t), [1,1])
 
1255
%! assert (isempty(te))
 
1256
%! assert (m,'ShoRt')
 
1257
%! assert (isempty(t))
1095
1258
 
1096
1259
%!test
1097
1260
%! [m, te, e, s, t] = regexpi('ShoRt Test String','\w*r\w*','once', 'match', 'tokenExtents', 'end', 'start', 'tokens');
1098
1261
%! assert (s,1)
1099
1262
%! assert (e,5)
1100
 
%! assert (size(te), [1,1])
1101
 
%! assert (isempty(te{1}))
1102
 
%! assert (m{1},'ShoRt')
1103
 
%! ## Matlab gives [1,0] here but that seems wrong.
1104
 
%! assert (size(t), [1,1])
 
1263
%! assert (isempty(te))
 
1264
%! assert (m,'ShoRt')
 
1265
%! assert (isempty(t))
1105
1266
 
1106
1267
%!testif HAVE_PCRE
1107
1268
%! ## This test is expected to fail if PCRE is not installed
1237
1398
      std::list<regexp_elem> lst;
1238
1399
      string_vector named;
1239
1400
      int nopts;
1240
 
      int sz = octregexp_list (regexpargs, nm , false, lst, named, nopts);
 
1401
      bool once;
 
1402
      int sz = octregexp_list (regexpargs, nm , false, lst, named, nopts, once);
1241
1403
 
1242
1404
      if (error_state)
1243
1405
        return retval;
1323
1485
      std::list<regexp_elem> lst;
1324
1486
      string_vector named;
1325
1487
      int nopts;
1326
 
      int sz = octregexp_list (regexpargs, nm, false, lst, named,nopts);
 
1488
      bool once;
 
1489
      int sz = octregexp_list (regexpargs, nm, false, lst, named, nopts, once);
1327
1490
 
1328
1491
      if (error_state)
1329
1492
        return retval;
1540
1703
%!assert(regexprep({"abc","cba"},"b","?"),{"a?c","c?a"})
1541
1704
%!assert(regexprep({"abc","cba"},{"b","a"},{"?","!"}),{"!?c","c?!"})
1542
1705
 
 
1706
# Nasty lookbehind expression
 
1707
%!assert(regexprep('x^(-1)+y(-1)+z(-1)=0','(?<=[a-z]+)\(\-[1-9]*\)','_minus1'),'x^(-1)+y_minus1+z_minus1=0')
 
1708
 
1543
1709
*/
1544
1710
 
1545
1711
/*