regex.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2009 Red Hat, Inc.
  35. * All rights reserved.
  36. * END COPYRIGHT BLOCK **/
  37. #ifdef HAVE_CONFIG_H
  38. # include <config.h>
  39. #endif
  40. /* number of elements in the output vector */
  41. #define OVECCOUNT 30 /* should be a multiple of 3; store up to \9 */
  42. #include "slap.h"
  43. #include "slapi-plugin.h"
  44. struct slapi_regex_handle {
  45. pcre *re_pcre; /* contains the compiled pattern */
  46. int *re_ovector; /* output vector */
  47. int re_oveccount; /* count of the elements in output vector */
  48. };
  49. /**
  50. * Compiles a regular expression pattern.
  51. *
  52. * \param pat Pattern to be compiled.
  53. * \param error The error string is set if the compile fails.
  54. * \return This function returns a pointer to the regex handler which stores
  55. * the compiled pattern. NULL if the compile fails.
  56. * \warning The regex handler should be released by slapi_re_free().
  57. */
  58. Slapi_Regex *
  59. slapi_re_comp( const char *pat, const char **error )
  60. {
  61. Slapi_Regex *re_handle = NULL;
  62. pcre *re = NULL;
  63. const char *myerror = NULL;
  64. int erroffset;
  65. re = pcre_compile(pat, 0, &myerror, &erroffset, NULL);
  66. if (error) {
  67. *error = myerror;
  68. }
  69. if (re) {
  70. re_handle = (Slapi_Regex *)slapi_ch_calloc(sizeof(Slapi_Regex), 1);
  71. re_handle->re_pcre = re;
  72. }
  73. return re_handle;
  74. }
  75. /**
  76. * Matches a compiled regular expression pattern against a given string.
  77. * A thin wrapper of pcre_exec.
  78. *
  79. * \param re_handle The regex handler returned from slapi_re_comp.
  80. * \param subject A string to be checked against the compiled pattern.
  81. * \param time_up If the current time is larger than the value, this function
  82. * returns immediately. (-1) means no time limit.
  83. * \return This function returns 0 if the string did not match.
  84. * \return This function returns 1 if the string matched.
  85. * \return This function returns other values if any error occurred.
  86. * \warning The regex handler should be released by slapi_re_free().
  87. */
  88. int
  89. slapi_re_exec( Slapi_Regex *re_handle, const char *subject, time_t time_up )
  90. {
  91. int rc;
  92. time_t curtime = current_time();
  93. if (NULL == re_handle || NULL == re_handle->re_pcre || NULL == subject) {
  94. return LDAP_PARAM_ERROR;
  95. }
  96. if ( time_up != -1 && curtime > time_up ) {
  97. return LDAP_TIMELIMIT_EXCEEDED;
  98. }
  99. if (NULL == re_handle->re_ovector) {
  100. re_handle->re_oveccount = OVECCOUNT;
  101. re_handle->re_ovector = (int *)slapi_ch_malloc(sizeof(int) * OVECCOUNT);
  102. }
  103. rc = pcre_exec( re_handle->re_pcre, /* the compiled pattern */
  104. NULL, /* no extra data */
  105. subject, /* the subject string */
  106. strlen(subject), /* the length of the subject */
  107. 0, /* start at offset 0 in the subject */
  108. 0, /* default options */
  109. re_handle->re_ovector, /* output vector for substring info */
  110. re_handle->re_oveccount ); /* number of elems in the ovector */
  111. if (rc >= 0) {
  112. return 1; /* matched */
  113. } else {
  114. return 0; /* did not match */
  115. }
  116. return rc;
  117. }
  118. /**
  119. * Substitutes '&' or '\#' in the param src with the matched string.
  120. *
  121. * \param re_handle The regex handler returned from slapi_re_comp.
  122. * \param subject A string checked against the compiled pattern.
  123. * \param src A given string which could contain the substitution symbols.
  124. * \param dst A pointer pointing to the memory which stores the output string.
  125. * \param dstlen Size of the memory dst.
  126. * \return This function returns 0 if the substitution was successful.
  127. * \return This function returns -1 if the substitution failed.
  128. * \warning The regex handler should be released by slapi_re_free().
  129. */
  130. int
  131. slapi_re_subs( Slapi_Regex *re_handle, const char *subject,
  132. const char *src, char **dst, unsigned long dstlen )
  133. {
  134. int thislen = 0;
  135. int len = 0;
  136. int pin;
  137. int *ovector;
  138. char *mydst = *dst;
  139. const char *substring_start;
  140. const char *p;
  141. if (NULL == src || NULL == re_handle || NULL == re_handle->re_ovector) {
  142. memset(*dst, '\0', dstlen);
  143. return -1;
  144. } else if (NULL == dst || NULL == *dst || 0 == dstlen) {
  145. return -1;
  146. }
  147. ovector = re_handle->re_ovector;
  148. for (p = src; *p != '\0'; p++) {
  149. if ('&' == *p) {
  150. if (re_handle->re_oveccount <= 1) {
  151. memset(*dst, '\0', dstlen);
  152. return -1;
  153. }
  154. substring_start = subject + ovector[0];
  155. thislen = ovector[1] - ovector[0];
  156. len += thislen;
  157. } else if (('\\' == *p) && ('0' <= *(p+1) && *(p+1) <= '9')) {
  158. pin = *(++p) - '0';
  159. if (re_handle->re_oveccount <= 2*pin+1) {
  160. memset(*dst, '\0', dstlen);
  161. return -1;
  162. }
  163. substring_start = subject + ovector[2*pin];
  164. thislen = ovector[2*pin+1] - ovector[2*pin];
  165. len += thislen;
  166. } else {
  167. substring_start = p;
  168. thislen = 1;
  169. len++;
  170. }
  171. if (len >= dstlen) {
  172. int offset = mydst - *dst;
  173. dstlen = len * 2;
  174. *dst = (char *)slapi_ch_realloc(*dst, dstlen);
  175. mydst = *dst + offset;
  176. }
  177. memcpy(mydst, substring_start, thislen);
  178. mydst += thislen;
  179. }
  180. *mydst = '\0';
  181. return 0;
  182. }
  183. /**
  184. * Releases the regex handler which was returned from slapi_re_comp.
  185. *
  186. * \param re_handle The regex handler to be released.
  187. * \return nothing
  188. */
  189. void
  190. slapi_re_free(Slapi_Regex *re_handle)
  191. {
  192. if (re_handle) {
  193. if (re_handle->re_pcre) {
  194. pcre_free(re_handle->re_pcre);
  195. }
  196. slapi_ch_free((void **)&re_handle->re_ovector);
  197. slapi_ch_free((void **)&re_handle);
  198. }
  199. }