/[pcre]/code/trunk/pcre_exec.c
ViewVC logotype

Diff of /code/trunk/pcre_exec.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1312 by ph10, Tue Apr 23 09:48:25 2013 UTC revision 1361 by ph10, Fri Sep 6 17:47:32 2013 UTC
# Line 811  for (;;) Line 811  for (;;)
811      RRETURN(MATCH_SKIP);      RRETURN(MATCH_SKIP);
812    
813      /* Note that, for Perl compatibility, SKIP with an argument does NOT set      /* Note that, for Perl compatibility, SKIP with an argument does NOT set
814      nomatch_mark. When a pattern match ends with a SKIP_ARG for which there was      nomatch_mark. When a pattern match ends with a SKIP_ARG for which there was
815      not a matching mark, we have to re-run the match, ignoring the SKIP_ARG      not a matching mark, we have to re-run the match, ignoring the SKIP_ARG
816      that failed and any that preceed it (either they also failed, or were not      that failed and any that precede it (either they also failed, or were not
817      triggered). To do this, we maintain a count of executed SKIP_ARGs. If a      triggered). To do this, we maintain a count of executed SKIP_ARGs. If a
818      SKIP_ARG gets to top level, the match is re-run with md->ignore_skip_arg      SKIP_ARG gets to top level, the match is re-run with md->ignore_skip_arg
819      set to the count of the one that failed. */      set to the count of the one that failed. */
820    
# Line 828  for (;;) Line 828  for (;;)
828      RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode] + ecode[1], offset_top, md,      RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode] + ecode[1], offset_top, md,
829        eptrb, RM57);        eptrb, RM57);
830      if (rrc != MATCH_NOMATCH) RRETURN(rrc);      if (rrc != MATCH_NOMATCH) RRETURN(rrc);
831    
832      /* Pass back the current skip name by overloading md->start_match_ptr and      /* Pass back the current skip name by overloading md->start_match_ptr and
833      returning the special MATCH_SKIP_ARG return code. This will either be      returning the special MATCH_SKIP_ARG return code. This will either be
834      caught by a matching MARK, or get to the top, where it causes a rematch      caught by a matching MARK, or get to the top, where it causes a rematch
# Line 1604  for (;;) Line 1604  for (;;)
1604      else condassert = FALSE;      else condassert = FALSE;
1605    
1606      /* Loop for each branch */      /* Loop for each branch */
1607    
1608      do      do
1609        {        {
1610        RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, NULL, RM4);        RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, NULL, RM4);
1611    
1612        /* A match means that the assertion is true; break out of the loop        /* A match means that the assertion is true; break out of the loop
1613        that matches its alternatives. */        that matches its alternatives. */
1614    
1615        if (rrc == MATCH_MATCH || rrc == MATCH_ACCEPT)        if (rrc == MATCH_MATCH || rrc == MATCH_ACCEPT)
1616          {          {
1617          mstart = md->start_match_ptr;   /* In case \K reset it */          mstart = md->start_match_ptr;   /* In case \K reset it */
1618          break;          break;
1619          }          }
1620    
1621        /* If not matched, restore the previous mark setting. */        /* If not matched, restore the previous mark setting. */
1622    
1623        md->mark = save_mark;        md->mark = save_mark;
1624    
1625        /* See comment in the code for capturing groups above about handling        /* See comment in the code for capturing groups above about handling
# Line 1632  for (;;) Line 1632  for (;;)
1632              (*ecode == OP_ALT || *next == OP_ALT))              (*ecode == OP_ALT || *next == OP_ALT))
1633            rrc = MATCH_NOMATCH;            rrc = MATCH_NOMATCH;
1634          }          }
1635    
1636        /* Anything other than NOMATCH causes the entire assertion to fail,        /* Anything other than NOMATCH causes the entire assertion to fail,
1637        passing back the return code. This includes COMMIT, SKIP, PRUNE and an        passing back the return code. This includes COMMIT, SKIP, PRUNE and an
1638        uncaptured THEN, which means they take their normal effect. This        uncaptured THEN, which means they take their normal effect. This
# Line 1643  for (;;) Line 1643  for (;;)
1643        ecode += GET(ecode, 1);        ecode += GET(ecode, 1);
1644        }        }
1645      while (*ecode == OP_ALT);   /* Continue for next alternative */      while (*ecode == OP_ALT);   /* Continue for next alternative */
1646    
1647      /* If we have tried all the alternative branches, the assertion has      /* If we have tried all the alternative branches, the assertion has
1648      failed. If not, we broke out after a match. */      failed. If not, we broke out after a match. */
1649    
1650      if (*ecode == OP_KET) RRETURN(MATCH_NOMATCH);      if (*ecode == OP_KET) RRETURN(MATCH_NOMATCH);
1651    
# Line 1661  for (;;) Line 1661  for (;;)
1661      offset_top = md->end_offset_top;      offset_top = md->end_offset_top;
1662      continue;      continue;
1663    
1664      /* Negative assertion: all branches must fail to match for the assertion to      /* Negative assertion: all branches must fail to match for the assertion to
1665      succeed. */      succeed. */
1666    
1667      case OP_ASSERT_NOT:      case OP_ASSERT_NOT:
# Line 1675  for (;;) Line 1675  for (;;)
1675      else condassert = FALSE;      else condassert = FALSE;
1676    
1677      /* Loop for each alternative branch. */      /* Loop for each alternative branch. */
1678    
1679      do      do
1680        {        {
1681        RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, NULL, RM5);        RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, NULL, RM5);
1682        md->mark = save_mark;   /* Always restore the mark setting */        md->mark = save_mark;   /* Always restore the mark setting */
1683    
1684        switch(rrc)        switch(rrc)
1685          {          {
1686          case MATCH_MATCH:            /* A successful match means */          case MATCH_MATCH:            /* A successful match means */
1687          case MATCH_ACCEPT:           /* the assertion has failed. */          case MATCH_ACCEPT:           /* the assertion has failed. */
1688          RRETURN(MATCH_NOMATCH);          RRETURN(MATCH_NOMATCH);
1689    
1690          case MATCH_NOMATCH:          /* Carry on with next branch */          case MATCH_NOMATCH:          /* Carry on with next branch */
1691          break;          break;
1692    
1693          /* See comment in the code for capturing groups above about handling          /* See comment in the code for capturing groups above about handling
1694          THEN. */          THEN. */
# Line 1697  for (;;) Line 1697  for (;;)
1697          next = ecode + GET(ecode,1);          next = ecode + GET(ecode,1);
1698          if (md->start_match_ptr < next &&          if (md->start_match_ptr < next &&
1699              (*ecode == OP_ALT || *next == OP_ALT))              (*ecode == OP_ALT || *next == OP_ALT))
1700            {            {
1701            rrc = MATCH_NOMATCH;            rrc = MATCH_NOMATCH;
1702            break;            break;
1703            }            }
1704          /* Otherwise fall through. */          /* Otherwise fall through. */
1705    
1706          /* COMMIT, SKIP, PRUNE, and an uncaptured THEN cause the whole          /* COMMIT, SKIP, PRUNE, and an uncaptured THEN cause the whole
1707          assertion to fail to match, without considering any more alternatives.          assertion to fail to match, without considering any more alternatives.
1708          Failing to match means the assertion is true. This is a consistent          Failing to match means the assertion is true. This is a consistent
# Line 1710  for (;;) Line 1710  for (;;)
1710    
1711          case MATCH_COMMIT:          case MATCH_COMMIT:
1712          case MATCH_SKIP:          case MATCH_SKIP:
1713          case MATCH_SKIP_ARG:          case MATCH_SKIP_ARG:
1714          case MATCH_PRUNE:          case MATCH_PRUNE:
1715          do ecode += GET(ecode,1); while (*ecode == OP_ALT);          do ecode += GET(ecode,1); while (*ecode == OP_ALT);
1716          goto NEG_ASSERT_TRUE;   /* Break out of alternation loop */          goto NEG_ASSERT_TRUE;   /* Break out of alternation loop */
1717    
1718          /* Anything else is an error */          /* Anything else is an error */
1719    
1720          default:          default:
1721          RRETURN(rrc);          RRETURN(rrc);
1722          }          }
1723    
1724        /* Continue with next branch */        /* Continue with next branch */
1725    
1726        ecode += GET(ecode,1);        ecode += GET(ecode,1);
1727        }        }
1728      while (*ecode == OP_ALT);      while (*ecode == OP_ALT);
1729    
1730      /* All branches in the assertion failed to match. */      /* All branches in the assertion failed to match. */
1731    
1732      NEG_ASSERT_TRUE:      NEG_ASSERT_TRUE:
1733      if (condassert) RRETURN(MATCH_MATCH);  /* Condition assertion */      if (condassert) RRETURN(MATCH_MATCH);  /* Condition assertion */
1734      ecode += 1 + LINK_SIZE;                /* Continue with current branch */      ecode += 1 + LINK_SIZE;                /* Continue with current branch */
# Line 1896  for (;;) Line 1896  for (;;)
1896          /* PCRE does not allow THEN, SKIP, PRUNE or COMMIT to escape beyond a          /* PCRE does not allow THEN, SKIP, PRUNE or COMMIT to escape beyond a
1897          recursion; they cause a NOMATCH for the entire recursion. These codes          recursion; they cause a NOMATCH for the entire recursion. These codes
1898          are defined in a range that can be tested for. */          are defined in a range that can be tested for. */
1899    
1900          if (rrc >= MATCH_BACKTRACK_MIN && rrc <= MATCH_BACKTRACK_MAX)          if (rrc >= MATCH_BACKTRACK_MIN && rrc <= MATCH_BACKTRACK_MAX)
1901            RRETURN(MATCH_NOMATCH);            RRETURN(MATCH_NOMATCH);
1902    
1903          /* Any return code other than NOMATCH is an error. */          /* Any return code other than NOMATCH is an error. */
1904    
1905          if (rrc != MATCH_NOMATCH)          if (rrc != MATCH_NOMATCH)
# Line 2742  for (;;) Line 2742  for (;;)
2742      similar code to character type repeats - written out again for speed.      similar code to character type repeats - written out again for speed.
2743      However, if the referenced string is the empty string, always treat      However, if the referenced string is the empty string, always treat
2744      it as matched, any number of times (otherwise there could be infinite      it as matched, any number of times (otherwise there could be infinite
2745      loops). */      loops). If the reference is unset, there are two possibilities:
   
     case OP_REF:  
     case OP_REFI:  
     caseless = op == OP_REFI;  
     offset = GET2(ecode, 1) << 1;               /* Doubled ref number */  
     ecode += 1 + IMM2_SIZE;  
   
     /* If the reference is unset, there are two possibilities:  
2746    
2747      (a) In the default, Perl-compatible state, set the length negative;      (a) In the default, Perl-compatible state, set the length negative;
2748      this ensures that every attempt at a match fails. We can't just fail      this ensures that every attempt at a match fails. We can't just fail
# Line 2760  for (;;) Line 2752  for (;;)
2752      so that the back reference matches an empty string.      so that the back reference matches an empty string.
2753    
2754      Otherwise, set the length to the length of what was matched by the      Otherwise, set the length to the length of what was matched by the
2755      referenced subpattern. */      referenced subpattern.
2756    
2757        The OP_REF and OP_REFI opcodes are used for a reference to a numbered group
2758        or to a non-duplicated named group. For a duplicated named group, OP_DNREF
2759        and OP_DNREFI are used. In this case we must scan the list of groups to
2760        which the name refers, and use the first one that is set. */
2761    
2762        case OP_DNREF:
2763        case OP_DNREFI:
2764        caseless = op == OP_DNREFI;
2765          {
2766          int count = GET2(ecode, 1+IMM2_SIZE);
2767          pcre_uchar *slot = md->name_table + GET2(ecode, 1) * md->name_entry_size;
2768          ecode += 1 + 2*IMM2_SIZE;
2769    
2770          while (count-- > 0)
2771            {
2772            offset = GET2(slot, 0) << 1;
2773            if (offset < offset_top && md->offset_vector[offset] >= 0) break;
2774            slot += md->name_entry_size;
2775            }
2776          if (count < 0)
2777            length = (md->jscript_compat)? 0 : -1;
2778          else
2779            length = md->offset_vector[offset+1] - md->offset_vector[offset];
2780          }
2781        goto REF_REPEAT;
2782    
2783        case OP_REF:
2784        case OP_REFI:
2785        caseless = op == OP_REFI;
2786        offset = GET2(ecode, 1) << 1;               /* Doubled ref number */
2787        ecode += 1 + IMM2_SIZE;
2788    
2789    
2790      if (offset >= offset_top || md->offset_vector[offset] < 0)      if (offset >= offset_top || md->offset_vector[offset] < 0)
2791        length = (md->jscript_compat)? 0 : -1;        length = (md->jscript_compat)? 0 : -1;
# Line 2769  for (;;) Line 2794  for (;;)
2794    
2795      /* Set up for repetition, or handle the non-repeated case */      /* Set up for repetition, or handle the non-repeated case */
2796    
2797        REF_REPEAT:
2798      switch (*ecode)      switch (*ecode)
2799        {        {
2800        case OP_CRSTAR:        case OP_CRSTAR:
# Line 3387  for (;;) Line 3413  for (;;)
3413      max = rep_max[c];                 /* zero for max => infinity */      max = rep_max[c];                 /* zero for max => infinity */
3414      if (max == 0) max = INT_MAX;      if (max == 0) max = INT_MAX;
3415    
3416      /* Common code for all repeated single-character matches. We first check      /* Common code for all repeated single-character matches. We first check
3417      for the minimum number of characters. If the minimum equals the maximum, we      for the minimum number of characters. If the minimum equals the maximum, we
3418      are done. Otherwise, if minimizing, check the rest of the pattern for a      are done. Otherwise, if minimizing, check the rest of the pattern for a
3419      match; if there isn't one, advance up to the maximum, one character at a      match; if there isn't one, advance up to the maximum, one character at a
3420      time.      time.
3421    
3422      If maximizing, advance up to the maximum number of matching characters,      If maximizing, advance up to the maximum number of matching characters,
3423      until eptr is past the end of the maximum run. If possessive, we are      until eptr is past the end of the maximum run. If possessive, we are
3424      then done (no backing up). Otherwise, match at this position; anything      then done (no backing up). Otherwise, match at this position; anything
3425      other than no match is immediately returned. For nomatch, back up one      other than no match is immediately returned. For nomatch, back up one
3426      character, unless we are matching \R and the last thing matched was      character, unless we are matching \R and the last thing matched was
3427      \r\n, in which case, back up two bytes. When we reach the first optional      \r\n, in which case, back up two bytes. When we reach the first optional
3428      character position, we can save stack by doing a tail recurse.      character position, we can save stack by doing a tail recurse.
3429    
3430      The various UTF/non-UTF and caseful/caseless cases are handled separately,      The various UTF/non-UTF and caseful/caseless cases are handled separately,
3431      for speed. */      for speed. */
3432    
# Line 3590  for (;;) Line 3616  for (;;)
3616            if (fc != cc && foc != cc) break;            if (fc != cc && foc != cc) break;
3617            eptr++;            eptr++;
3618            }            }
   
3619          if (possessive) continue;       /* No backtracking */          if (possessive) continue;       /* No backtracking */
3620          for (;;)          for (;;)
3621            {            {
3622            if (eptr == pp) goto TAIL_RECURSE;            if (eptr == pp) goto TAIL_RECURSE;
3623            RMATCH(eptr, ecode, offset_top, md, eptrb, RM25);            RMATCH(eptr, ecode, offset_top, md, eptrb, RM25);
3624            eptr--;            eptr--;
3625            if (rrc != MATCH_NOMATCH) RRETURN(rrc);            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
3626            }            }
3627          RRETURN(MATCH_NOMATCH);          /* Control never gets here */
3628          }          }
       /* Control never gets here */  
3629        }        }
3630    
3631      /* Caseful comparisons (includes all multi-byte characters) */      /* Caseful comparisons (includes all multi-byte characters) */
# Line 3657  for (;;) Line 3681  for (;;)
3681            eptr--;            eptr--;
3682            if (rrc != MATCH_NOMATCH) RRETURN(rrc);            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
3683            }            }
3684          RRETURN(MATCH_NOMATCH);          /* Control never gets here */
3685          }          }
3686        }        }
3687      /* Control never gets here */      /* Control never gets here */
# Line 3942  for (;;) Line 3966  for (;;)
3966              eptr--;              eptr--;
3967              }              }
3968            }            }
3969            /* Control never gets here */
         RRETURN(MATCH_NOMATCH);  
3970          }          }
       /* Control never gets here */  
3971        }        }
3972    
3973      /* Caseful comparisons */      /* Caseful comparisons */
# Line 4073  for (;;) Line 4095  for (;;)
4095            if (possessive) continue;    /* No backtracking */            if (possessive) continue;    /* No backtracking */
4096            for (;;)            for (;;)
4097              {              {
4098              if (eptr == pp) goto TAIL_RECURSE;              if (eptr == pp) goto TAIL_RECURSE;
4099              RMATCH(eptr, ecode, offset_top, md, eptrb, RM35);              RMATCH(eptr, ecode, offset_top, md, eptrb, RM35);
4100              if (rrc != MATCH_NOMATCH) RRETURN(rrc);              if (rrc != MATCH_NOMATCH) RRETURN(rrc);
4101              eptr--;              eptr--;
4102              }              }
4103            }            }
4104            /* Control never gets here */
         RRETURN(MATCH_NOMATCH);  
4105          }          }
4106        }        }
4107      /* Control never gets here */      /* Control never gets here */
# Line 5642  for (;;) Line 5663  for (;;)
5663            }            }
5664          }          }
5665    
5666        /* Match extended Unicode sequences. We will get here only if the        /* Match extended Unicode grapheme clusters. We will get here only if the
5667        support is in the binary; otherwise a compile-time error occurs. */        support is in the binary; otherwise a compile-time error occurs. */
5668    
5669        else if (ctype == OP_EXTUNI)        else if (ctype == OP_EXTUNI)
# Line 5675  for (;;) Line 5696  for (;;)
5696          /* eptr is now past the end of the maximum run */          /* eptr is now past the end of the maximum run */
5697    
5698          if (possessive) continue;    /* No backtracking */          if (possessive) continue;    /* No backtracking */
5699    
5700          for(;;)          for(;;)
5701            {            {
5702            if (eptr == pp) goto TAIL_RECURSE;            int lgb, rgb;
5703              PCRE_PUCHAR fptr;
5704    
5705              if (eptr == pp) goto TAIL_RECURSE;   /* At start of char run */
5706            RMATCH(eptr, ecode, offset_top, md, eptrb, RM45);            RMATCH(eptr, ecode, offset_top, md, eptrb, RM45);
5707            if (rrc != MATCH_NOMATCH) RRETURN(rrc);            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
5708            eptr--;  
5709            for (;;)                        /* Move back over one extended */            /* Backtracking over an extended grapheme cluster involves inspecting
5710              the previous two characters (if present) to see if a break is
5711              permitted between them. */
5712    
5713              eptr--;
5714              if (!utf) c = *eptr; else
5715              {              {
5716              if (!utf) c = *eptr; else              BACKCHAR(eptr);
5717                {              GETCHAR(c, eptr);
5718                BACKCHAR(eptr);              }
5719                GETCHAR(c, eptr);            rgb = UCD_GRAPHBREAK(c);
5720                }  
5721              if (UCD_CATEGORY(c) != ucp_M) break;            for (;;)
5722              eptr--;              {
5723                if (eptr == pp) goto TAIL_RECURSE;   /* At start of char run */
5724                fptr = eptr - 1;
5725                if (!utf) c = *fptr; else
5726                  {
5727                  BACKCHAR(fptr);
5728                  GETCHAR(c, fptr);
5729                  }
5730                lgb = UCD_GRAPHBREAK(c);
5731                if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break;
5732                eptr = fptr;
5733                rgb = lgb;
5734              }              }
5735            }            }
5736          }          }
# Line 5958  for (;;) Line 5999  for (;;)
5999          if (possessive) continue;    /* No backtracking */          if (possessive) continue;    /* No backtracking */
6000          for(;;)          for(;;)
6001            {            {
6002            if (eptr == pp) goto TAIL_RECURSE;            if (eptr == pp) goto TAIL_RECURSE;
6003            RMATCH(eptr, ecode, offset_top, md, eptrb, RM46);            RMATCH(eptr, ecode, offset_top, md, eptrb, RM46);
6004            if (rrc != MATCH_NOMATCH) RRETURN(rrc);            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
6005            eptr--;            eptr--;
# Line 6210  for (;;) Line 6251  for (;;)
6251                eptr[-1] == CHAR_CR) eptr--;                eptr[-1] == CHAR_CR) eptr--;
6252            }            }
6253          }          }
6254    
6255        /* Get here if we can't make it match with any permitted repetitions */        /* Control never gets here */
   
       RRETURN(MATCH_NOMATCH);  
6256        }        }
     /* Control never gets here */  
6257    
6258      /* There's been some horrible disaster. Arrival here can only mean there is      /* There's been some horrible disaster. Arrival here can only mean there is
6259      something seriously wrong in the code above or the OP_xxx definitions. */      something seriously wrong in the code above or the OP_xxx definitions. */
# Line 6410  const pcre_uint8 *start_bits = NULL; Line 6448  const pcre_uint8 *start_bits = NULL;
6448  PCRE_PUCHAR start_match = (PCRE_PUCHAR)subject + start_offset;  PCRE_PUCHAR start_match = (PCRE_PUCHAR)subject + start_offset;
6449  PCRE_PUCHAR end_subject;  PCRE_PUCHAR end_subject;
6450  PCRE_PUCHAR start_partial = NULL;  PCRE_PUCHAR start_partial = NULL;
6451  PCRE_PUCHAR match_partial;  PCRE_PUCHAR match_partial = NULL;
6452  PCRE_PUCHAR req_char_ptr = start_match - 1;  PCRE_PUCHAR req_char_ptr = start_match - 1;
6453    
6454  const pcre_study_data *study;  const pcre_study_data *study;
# Line 6540  md->callout_data = NULL; Line 6578  md->callout_data = NULL;
6578    
6579  tables = re->tables;  tables = re->tables;
6580    
6581    /* The two limit values override the defaults, whatever their value. */
6582    
6583  if (extra_data != NULL)  if (extra_data != NULL)
6584    {    {
6585    register unsigned int flags = extra_data->flags;    register unsigned int flags = extra_data->flags;
# Line 6554  if (extra_data != NULL) Line 6594  if (extra_data != NULL)
6594    if ((flags & PCRE_EXTRA_TABLES) != 0) tables = extra_data->tables;    if ((flags & PCRE_EXTRA_TABLES) != 0) tables = extra_data->tables;
6595    }    }
6596    
6597    /* Limits in the regex override only if they are smaller. */
6598    
6599    if ((re->flags & PCRE_MLSET) != 0 && re->limit_match < md->match_limit)
6600      md->match_limit = re->limit_match;
6601    
6602    if ((re->flags & PCRE_RLSET) != 0 &&
6603        re->limit_recursion < md->match_limit_recursion)
6604      md->match_limit_recursion = re->limit_recursion;
6605    
6606  /* If the exec call supplied NULL for tables, use the inbuilt ones. This  /* If the exec call supplied NULL for tables, use the inbuilt ones. This
6607  is a feature that makes it possible to save compiled regex and re-use them  is a feature that makes it possible to save compiled regex and re-use them
6608  in other programs later. */  in other programs later. */
# Line 7167  if (rc != MATCH_NOMATCH && rc != PCRE_ER Line 7216  if (rc != MATCH_NOMATCH && rc != PCRE_ER
7216    
7217  /* Handle partial matches - disable any mark data */  /* Handle partial matches - disable any mark data */
7218    
7219  if (start_partial != NULL)  if (match_partial != NULL)
7220    {    {
7221    DPRINTF((">>>> returning PCRE_ERROR_PARTIAL\n"));    DPRINTF((">>>> returning PCRE_ERROR_PARTIAL\n"));
7222    md->mark = NULL;    md->mark = NULL;

Legend:
Removed from v.1312  
changed lines
  Added in v.1361

  ViewVC Help
Powered by ViewVC 1.1.5