home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / gnurx.zip / rx / rxposix.c < prev    next >
C/C++ Source or Header  |  1995-12-31  |  10KB  |  419 lines

  1. /***********************************************************
  2.  
  3. Copyright 1995 by Tom Lord
  4.  
  5.                         All Rights Reserved
  6.  
  7. Permission to use, copy, modify, and distribute this software and its 
  8. documentation for any purpose and without fee is hereby granted, 
  9. provided that the above copyright notice appear in all copies and that
  10. both that copyright notice and this permission notice appear in 
  11. supporting documentation, and that the name of the copyright holder not be
  12. used in advertising or publicity pertaining to distribution of the
  13. software without specific, written prior permission.  
  14.  
  15. Tom Lord DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  16. INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  17. EVENT SHALL TOM LORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  18. CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  19. USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  20. OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  21. PERFORMANCE OF THIS SOFTWARE.
  22.  
  23. ******************************************************************/
  24.  
  25.  
  26.  
  27. #include "rxall.h"
  28. #include "rxposix.h"
  29. #include "rxgnucomp.h"
  30. #include "rxbasic.h"
  31. #include "rxsimp.h"
  32.  
  33. /* regcomp takes a regular expression as a string and compiles it.
  34.  *
  35.  * PATTERN is the address of the pattern string.
  36.  *
  37.  * CFLAGS is a series of bits which affect compilation.
  38.  *
  39.  *   If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
  40.  *   use POSIX basic syntax.
  41.  *
  42.  *   If REG_NEWLINE is set, then . and [^...] don't match newline.
  43.  *   Also, regexec will try a match beginning after every newline.
  44.  *
  45.  *   If REG_ICASE is set, then we considers upper- and lowercase
  46.  *   versions of letters to be equivalent when matching.
  47.  *
  48.  *   If REG_NOSUB is set, then when PREG is passed to regexec, that
  49.  *   routine will report only success or failure, and nothing about the
  50.  *   registers.
  51.  *
  52.  * It returns 0 if it succeeds, nonzero if it doesn't.  (See regex.h for
  53.  * the return codes and their meanings.)  
  54.  */
  55.  
  56.  
  57. #ifdef __STDC__
  58. int
  59. regcomp (regex_t * preg, const char * pattern, int cflags)
  60. #else
  61. int
  62. regcomp (preg, pattern, cflags)
  63.     regex_t * preg;
  64.     const char * pattern;
  65.     int cflags;
  66. #endif
  67. {
  68.   reg_errcode_t ret;
  69.   unsigned int syntax;
  70.   unsigned char xlate[256];
  71.  
  72.   bzero (preg, sizeof (*preg));
  73.   syntax = ((cflags & REG_EXTENDED)
  74.         ? RE_SYNTAX_POSIX_EXTENDED
  75.         : RE_SYNTAX_POSIX_BASIC);
  76.  
  77.   if (!(cflags & REG_ICASE))
  78.     preg->translate = 0;
  79.   else
  80.     {
  81.       unsigned i;
  82.  
  83.       preg->translate = (unsigned char *) malloc (256);
  84.       if (!preg->translate)
  85.         return (int) REG_ESPACE;
  86.  
  87.       /* Map uppercase characters to corresponding lowercase ones.  */
  88.       for (i = 0; i < CHAR_SET_SIZE; i++)
  89.         preg->translate[i] = isupper (i) ? tolower (i) : i;
  90.     }
  91.  
  92.  
  93.   /* If REG_NEWLINE is set, newlines are treated differently.  */
  94.   if (!(cflags & REG_NEWLINE))
  95.     preg->newline_anchor = 0;
  96.   else
  97.     {
  98.       /* REG_NEWLINE implies neither . nor [^...] match newline.  */
  99.       syntax &= ~RE_DOT_NEWLINE;
  100.       syntax |= RE_HAT_LISTS_NOT_NEWLINE;
  101.       /* It also changes the matching behavior.  */
  102.       preg->newline_anchor = 1;
  103.     }
  104.  
  105.   preg->no_sub = !!(cflags & REG_NOSUB);
  106.  
  107.   /* POSIX says a null character in the pattern terminates it, so we
  108.    * can use strlen here in compiling the pattern.  
  109.    */
  110.  
  111.   ret = rx_parse (&preg->pattern,
  112.           pattern, strlen (pattern),
  113.           syntax,
  114.           256,
  115.           preg->translate);
  116.  
  117.   /* POSIX doesn't distinguish between an unmatched open-group and an
  118.    * unmatched close-group: both are REG_EPAREN.
  119.    */
  120.   if (ret == REG_ERPAREN)
  121.     ret = REG_EPAREN;
  122.  
  123.   if (!ret)
  124.     {
  125.       preg->n_subexps = 1;
  126.       preg->subexps = 0;
  127.       rx_posix_analyze_rexp (&preg->subexps,
  128.                  &preg->n_subexps,
  129.                  preg->pattern,
  130.                  0);
  131.       rx_fill_in_fastmap (256,
  132.               preg->fastmap,
  133.               preg->pattern);
  134.  
  135.       preg->is_anchored = rx_is_anchored_p (preg->pattern);
  136.     }
  137.  
  138.   return (int) ret;
  139. }
  140.  
  141.  
  142.  
  143.  
  144. /* Returns a message corresponding to an error code, ERRCODE, returned
  145.    from either regcomp or regexec.   */
  146.  
  147. #ifdef __STDC__
  148. size_t
  149. regerror (int errcode, const regex_t *preg,
  150.       char *errbuf, size_t errbuf_size)
  151. #else
  152. size_t
  153. regerror (errcode, preg, errbuf, errbuf_size)
  154.     int errcode;
  155.     const regex_t *preg;
  156.     char *errbuf;
  157.     size_t errbuf_size;
  158. #endif
  159. {
  160.   const char *msg;
  161.   size_t msg_size;
  162.  
  163.   msg = rx_error_msg[errcode] == 0 ? "Success" : rx_error_msg[errcode];
  164.   msg_size = strlen (msg) + 1; /* Includes the 0.  */
  165.   if (errbuf_size != 0)
  166.     {
  167.       if (msg_size > errbuf_size)
  168.         {
  169.           strncpy (errbuf, msg, errbuf_size - 1);
  170.           errbuf[errbuf_size - 1] = 0;
  171.         }
  172.       else
  173.         strcpy (errbuf, msg);
  174.     }
  175.   return msg_size;
  176. }
  177.  
  178.  
  179.  
  180. #ifdef __STDC__
  181. int
  182. rx_regmatch (regmatch_t pmatch[],
  183.          regex_t *preg,
  184.          struct rx_context_rules * rules,
  185.          int start, int end, char *string)
  186. #else
  187. int
  188. rx_regmatch (pmatch, preg, rules, start, end, string)
  189.      regmatch_t pmatch[];
  190.      regex_t *preg;
  191.      struct rx_context_rules * rules;
  192.      int start;
  193.      int end;
  194.      char *string;
  195. #endif
  196. {
  197.   struct rx_solutions * solutions;
  198.   enum rx_answers answer;
  199.   struct rx_context_rules local_rules;
  200.   int orig_end;
  201.   
  202.   local_rules = *rules;
  203.   orig_end = end;
  204.  
  205.   while (end >= start)
  206.     {
  207.       local_rules.not_eol = (rules->not_eol
  208.                  ? (   (end == orig_end)
  209.                 || !local_rules.newline_anchor
  210.                 || (string[end] != '\n'))
  211.                  : (   (end != orig_end)
  212.                 && (!local_rules.newline_anchor
  213.                     || (string[end] != '\n'))));
  214.       solutions = rx_basic_make_solutions (pmatch, preg->pattern, preg->subexps,
  215.                        start, end, &local_rules, string);
  216.       if (!solutions)
  217.     return REG_ESPACE;
  218.       
  219.       do
  220.     {
  221.       answer = rx_next_solution (solutions);
  222.     }
  223.       while (answer == rx_maybe);
  224.  
  225.       rx_basic_free_solutions (solutions);
  226.       if (answer == rx_yes)
  227.     {
  228.       if (pmatch)
  229.         {
  230.           pmatch[0].rm_so = start;
  231.           pmatch[0].rm_eo = end;
  232.         }
  233.       return 0;
  234.     }
  235.       --end;
  236.     }
  237.  
  238.   switch (answer)
  239.     {
  240.     default:
  241.     case rx_bogus:
  242.       return REG_ESPACE;
  243.  
  244.     case rx_no:
  245.     case rx_maybe:
  246.       return REG_NOMATCH;
  247.     }
  248. }
  249.  
  250.  
  251. #ifdef __STDC__
  252. int
  253. rx_regexec (regmatch_t pmatch[],
  254.         regex_t *preg,
  255.         struct rx_context_rules * rules,
  256.         int start,
  257.         int end,
  258.         char *string)
  259. #else
  260. int
  261. rx_regexec (pmatch, preg, rules, start, end, string)
  262.      regmatch_t pmatch[];
  263.      regex_t *preg;
  264.      struct rx_context_rules * rules;
  265.      int start;
  266.      int end;
  267.      char *string;
  268. #endif
  269. {
  270.   int x;
  271.   int stat;
  272.   int anchored;
  273.  
  274.   anchored = preg->is_anchored;
  275.   for (x = start; x <= end; ++x)
  276.     {
  277.       if (preg->fastmap[((unsigned char *)string)[x]])
  278.     {
  279.       stat = rx_regmatch (pmatch, preg, rules, x, end, string);
  280.       if (!stat || (stat != REG_NOMATCH))
  281.         return stat;
  282.     }
  283.       if (anchored)
  284.     return REG_NOMATCH;
  285.     }
  286.   return REG_NOMATCH;
  287. }
  288.  
  289.  
  290.  
  291. /* regexec searches for a given pattern, specified by PREG, in the
  292.  * string STRING.
  293.  *
  294.  * If NMATCH is zero or REG_NOSUB was set in the cflags argument to
  295.  * `regcomp', we ignore PMATCH.  Otherwise, we assume PMATCH has at
  296.  * least NMATCH elements, and we set them to the offsets of the
  297.  * corresponding matched substrings.
  298.  *
  299.  * EFLAGS specifies `execution flags' which affect matching: if
  300.  * REG_NOTBOL is set, then ^ does not match at the beginning of the
  301.  * string; if REG_NOTEOL is set, then $ does not match at the end.
  302.  *
  303.  * We return 0 if we find a match and REG_NOMATCH if not.  
  304.  */
  305.  
  306. #ifdef __STDC__
  307. int
  308. regnexec (regex_t *preg, int len, char *string,
  309.      size_t nmatch, regmatch_t pmatch[],
  310.      int eflags)
  311. #else
  312. int
  313. regnexec (preg, len, string, nmatch, pmatch, eflags)
  314.      regex_t *preg;
  315.      int len;
  316.      char *string;
  317.      size_t nmatch;
  318.      regmatch_t pmatch[];
  319.      int eflags;
  320. #endif
  321. {
  322.   int want_reg_info;
  323.   struct rx_context_rules rules;
  324.   regmatch_t * regs;
  325.   int nregs;
  326.   int stat;
  327.  
  328.   want_reg_info = (!preg->no_sub && (nmatch > 0));
  329.  
  330.   rules.newline_anchor = preg->newline_anchor;
  331.   rules.not_bol = !!(eflags & REG_NOTBOL);
  332.   rules.not_eol = !!(eflags & REG_NOTEOL);
  333.  
  334.   if (nmatch >= preg->n_subexps)
  335.     {
  336.       regs = pmatch;
  337.       nregs = nmatch;
  338.     }
  339.   else
  340.     {
  341.       regs = (regmatch_t *)malloc (preg->n_subexps * sizeof (*regs));
  342.       nregs = preg->n_subexps;
  343.     }
  344.  
  345.   {
  346.     int x;
  347.     for (x = 0; x < nregs; ++x)
  348.       regs[x].rm_so = regs[x].rm_eo = -1;
  349.   }
  350.  
  351.  
  352.   stat = rx_regexec (pmatch, preg, &rules, 0, len, string);
  353.  
  354.   if (!stat && want_reg_info && (regs != pmatch))
  355.     {
  356.       int x;
  357.       for (x = 0; x < nmatch; ++x)
  358.     pmatch[x] = regs[x];
  359.  
  360.       free (regs);
  361.     }
  362.  
  363.   return ((stat == rx_yes)
  364.       ? 0
  365.       : REG_NOMATCH);
  366. }
  367.  
  368. #ifdef __STDC__
  369. int
  370. regexec (regex_t *preg, char *string,
  371.      size_t nmatch, regmatch_t pmatch[],
  372.      int eflags)
  373. #else
  374. int
  375. regexec (preg, string, nmatch, pmatch, eflags)
  376.      regex_t *preg;
  377.      char *string;
  378.      size_t nmatch;
  379.      regmatch_t pmatch[];
  380.      int eflags;
  381. #endif
  382. {
  383.   return regnexec (preg,
  384.            strlen (string),
  385.            string,
  386.            nmatch,
  387.            pmatch,
  388.            eflags);
  389. }
  390.  
  391.  
  392. /* Free dynamically allocated space used by PREG.  */
  393.  
  394. #ifdef __STDC__
  395. void
  396. regfree (regex_t *preg)
  397. #else
  398. void
  399. regfree (preg)
  400.     regex_t *preg;
  401. #endif
  402. {
  403.   if (preg->pattern)
  404.     {
  405.       rx_free_rexp (preg->pattern);
  406.       preg->pattern = 0;
  407.     }
  408.   if (preg->subexps)
  409.     {
  410.       free (preg->subexps);
  411.       preg->subexps = 0;
  412.     }
  413.   if (preg->translate != 0)
  414.     {
  415.       free (preg->translate);
  416.       preg->translate = 0;
  417.     }
  418. }
  419.