dvander@2762: /************************************************* dvander@2762: * Perl-Compatible Regular Expressions * dvander@2762: *************************************************/ dvander@2762: dvander@2762: /* PCRE is a library of functions to support regular expressions whose syntax dvander@2762: and semantics are as close as possible to those of the Perl 5 language. dvander@2762: dvander@2762: Written by Philip Hazel dvander@2762: Copyright (c) 1997-2008 University of Cambridge dvander@2762: dvander@2762: ----------------------------------------------------------------------------- dvander@2762: Redistribution and use in source and binary forms, with or without dvander@2762: modification, are permitted provided that the following conditions are met: dvander@2762: dvander@2762: * Redistributions of source code must retain the above copyright notice, dvander@2762: this list of conditions and the following disclaimer. dvander@2762: dvander@2762: * Redistributions in binary form must reproduce the above copyright dvander@2762: notice, this list of conditions and the following disclaimer in the dvander@2762: documentation and/or other materials provided with the distribution. dvander@2762: dvander@2762: * Neither the name of the University of Cambridge nor the names of its dvander@2762: contributors may be used to endorse or promote products derived from dvander@2762: this software without specific prior written permission. dvander@2762: dvander@2762: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" dvander@2762: AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE dvander@2762: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE dvander@2762: ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE dvander@2762: LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR dvander@2762: CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF dvander@2762: SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS dvander@2762: INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN dvander@2762: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) dvander@2762: ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE dvander@2762: POSSIBILITY OF SUCH DAMAGE. dvander@2762: ----------------------------------------------------------------------------- dvander@2762: */ dvander@2762: dvander@2762: dvander@2762: /* This module contains some convenience functions for extracting substrings dvander@2762: from the subject string after a regex match has succeeded. The original idea dvander@2762: for these functions came from Scott Wimer. */ dvander@2762: dvander@2762: dvander@2762: #ifdef HAVE_CONFIG_H dvander@2762: #include "config.h" dvander@2762: #endif dvander@2762: dvander@2762: #include "pcre_internal.h" dvander@2762: dvander@2762: dvander@2762: /************************************************* dvander@2762: * Find number for named string * dvander@2762: *************************************************/ dvander@2762: dvander@2762: /* This function is used by the get_first_set() function below, as well dvander@2762: as being generally available. It assumes that names are unique. dvander@2762: dvander@2762: Arguments: dvander@2762: code the compiled regex dvander@2762: stringname the name whose number is required dvander@2762: dvander@2762: Returns: the number of the named parentheses, or a negative number dvander@2762: (PCRE_ERROR_NOSUBSTRING) if not found dvander@2762: */ dvander@2762: dvander@2762: PCRE_EXP_DEFN int PCRE_CALL_CONVENTION dvander@2762: pcre_get_stringnumber(const pcre *code, const char *stringname) dvander@2762: { dvander@2762: int rc; dvander@2762: int entrysize; dvander@2762: int top, bot; dvander@2762: uschar *nametable; dvander@2762: dvander@2762: if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0) dvander@2762: return rc; dvander@2762: if (top <= 0) return PCRE_ERROR_NOSUBSTRING; dvander@2762: dvander@2762: if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0) dvander@2762: return rc; dvander@2762: if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0) dvander@2762: return rc; dvander@2762: dvander@2762: bot = 0; dvander@2762: while (top > bot) dvander@2762: { dvander@2762: int mid = (top + bot) / 2; dvander@2762: uschar *entry = nametable + entrysize*mid; dvander@2762: int c = strcmp(stringname, (char *)(entry + 2)); dvander@2762: if (c == 0) return (entry[0] << 8) + entry[1]; dvander@2762: if (c > 0) bot = mid + 1; else top = mid; dvander@2762: } dvander@2762: dvander@2762: return PCRE_ERROR_NOSUBSTRING; dvander@2762: } dvander@2762: dvander@2762: dvander@2762: dvander@2762: /************************************************* dvander@2762: * Find (multiple) entries for named string * dvander@2762: *************************************************/ dvander@2762: dvander@2762: /* This is used by the get_first_set() function below, as well as being dvander@2762: generally available. It is used when duplicated names are permitted. dvander@2762: dvander@2762: Arguments: dvander@2762: code the compiled regex dvander@2762: stringname the name whose entries required dvander@2762: firstptr where to put the pointer to the first entry dvander@2762: lastptr where to put the pointer to the last entry dvander@2762: dvander@2762: Returns: the length of each entry, or a negative number dvander@2762: (PCRE_ERROR_NOSUBSTRING) if not found dvander@2762: */ dvander@2762: dvander@2762: PCRE_EXP_DEFN int PCRE_CALL_CONVENTION dvander@2762: pcre_get_stringtable_entries(const pcre *code, const char *stringname, dvander@2762: char **firstptr, char **lastptr) dvander@2762: { dvander@2762: int rc; dvander@2762: int entrysize; dvander@2762: int top, bot; dvander@2762: uschar *nametable, *lastentry; dvander@2762: dvander@2762: if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0) dvander@2762: return rc; dvander@2762: if (top <= 0) return PCRE_ERROR_NOSUBSTRING; dvander@2762: dvander@2762: if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0) dvander@2762: return rc; dvander@2762: if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0) dvander@2762: return rc; dvander@2762: dvander@2762: lastentry = nametable + entrysize * (top - 1); dvander@2762: bot = 0; dvander@2762: while (top > bot) dvander@2762: { dvander@2762: int mid = (top + bot) / 2; dvander@2762: uschar *entry = nametable + entrysize*mid; dvander@2762: int c = strcmp(stringname, (char *)(entry + 2)); dvander@2762: if (c == 0) dvander@2762: { dvander@2762: uschar *first = entry; dvander@2762: uschar *last = entry; dvander@2762: while (first > nametable) dvander@2762: { dvander@2762: if (strcmp(stringname, (char *)(first - entrysize + 2)) != 0) break; dvander@2762: first -= entrysize; dvander@2762: } dvander@2762: while (last < lastentry) dvander@2762: { dvander@2762: if (strcmp(stringname, (char *)(last + entrysize + 2)) != 0) break; dvander@2762: last += entrysize; dvander@2762: } dvander@2762: *firstptr = (char *)first; dvander@2762: *lastptr = (char *)last; dvander@2762: return entrysize; dvander@2762: } dvander@2762: if (c > 0) bot = mid + 1; else top = mid; dvander@2762: } dvander@2762: dvander@2762: return PCRE_ERROR_NOSUBSTRING; dvander@2762: } dvander@2762: dvander@2762: dvander@2762: dvander@2762: /************************************************* dvander@2762: * Find first set of multiple named strings * dvander@2762: *************************************************/ dvander@2762: dvander@2762: /* This function allows for duplicate names in the table of named substrings. dvander@2762: It returns the number of the first one that was set in a pattern match. dvander@2762: dvander@2762: Arguments: dvander@2762: code the compiled regex dvander@2762: stringname the name of the capturing substring dvander@2762: ovector the vector of matched substrings dvander@2762: dvander@2762: Returns: the number of the first that is set, dvander@2762: or the number of the last one if none are set, dvander@2762: or a negative number on error dvander@2762: */ dvander@2762: dvander@2762: static int dvander@2762: get_first_set(const pcre *code, const char *stringname, int *ovector) dvander@2762: { dvander@2762: const real_pcre *re = (const real_pcre *)code; dvander@2762: int entrysize; dvander@2762: char *first, *last; dvander@2762: uschar *entry; dvander@2762: if ((re->options & PCRE_DUPNAMES) == 0 && (re->flags & PCRE_JCHANGED) == 0) dvander@2762: return pcre_get_stringnumber(code, stringname); dvander@2762: entrysize = pcre_get_stringtable_entries(code, stringname, &first, &last); dvander@2762: if (entrysize <= 0) return entrysize; dvander@2762: for (entry = (uschar *)first; entry <= (uschar *)last; entry += entrysize) dvander@2762: { dvander@2762: int n = (entry[0] << 8) + entry[1]; dvander@2762: if (ovector[n*2] >= 0) return n; dvander@2762: } dvander@2762: return (first[0] << 8) + first[1]; dvander@2762: } dvander@2762: dvander@2762: dvander@2762: dvander@2762: dvander@2762: /************************************************* dvander@2762: * Copy captured string to given buffer * dvander@2762: *************************************************/ dvander@2762: dvander@2762: /* This function copies a single captured substring into a given buffer. dvander@2762: Note that we use memcpy() rather than strncpy() in case there are binary zeros dvander@2762: in the string. dvander@2762: dvander@2762: Arguments: dvander@2762: subject the subject string that was matched dvander@2762: ovector pointer to the offsets table dvander@2762: stringcount the number of substrings that were captured dvander@2762: (i.e. the yield of the pcre_exec call, unless dvander@2762: that was zero, in which case it should be 1/3 dvander@2762: of the offset table size) dvander@2762: stringnumber the number of the required substring dvander@2762: buffer where to put the substring dvander@2762: size the size of the buffer dvander@2762: dvander@2762: Returns: if successful: dvander@2762: the length of the copied string, not including the zero dvander@2762: that is put on the end; can be zero dvander@2762: if not successful: dvander@2762: PCRE_ERROR_NOMEMORY (-6) buffer too small dvander@2762: PCRE_ERROR_NOSUBSTRING (-7) no such captured substring dvander@2762: */ dvander@2762: dvander@2762: PCRE_EXP_DEFN int PCRE_CALL_CONVENTION dvander@2762: pcre_copy_substring(const char *subject, int *ovector, int stringcount, dvander@2762: int stringnumber, char *buffer, int size) dvander@2762: { dvander@2762: int yield; dvander@2762: if (stringnumber < 0 || stringnumber >= stringcount) dvander@2762: return PCRE_ERROR_NOSUBSTRING; dvander@2762: stringnumber *= 2; dvander@2762: yield = ovector[stringnumber+1] - ovector[stringnumber]; dvander@2762: if (size < yield + 1) return PCRE_ERROR_NOMEMORY; dvander@2762: memcpy(buffer, subject + ovector[stringnumber], yield); dvander@2762: buffer[yield] = 0; dvander@2762: return yield; dvander@2762: } dvander@2762: dvander@2762: dvander@2762: dvander@2762: /************************************************* dvander@2762: * Copy named captured string to given buffer * dvander@2762: *************************************************/ dvander@2762: dvander@2762: /* This function copies a single captured substring into a given buffer, dvander@2762: identifying it by name. If the regex permits duplicate names, the first dvander@2762: substring that is set is chosen. dvander@2762: dvander@2762: Arguments: dvander@2762: code the compiled regex dvander@2762: subject the subject string that was matched dvander@2762: ovector pointer to the offsets table dvander@2762: stringcount the number of substrings that were captured dvander@2762: (i.e. the yield of the pcre_exec call, unless dvander@2762: that was zero, in which case it should be 1/3 dvander@2762: of the offset table size) dvander@2762: stringname the name of the required substring dvander@2762: buffer where to put the substring dvander@2762: size the size of the buffer dvander@2762: dvander@2762: Returns: if successful: dvander@2762: the length of the copied string, not including the zero dvander@2762: that is put on the end; can be zero dvander@2762: if not successful: dvander@2762: PCRE_ERROR_NOMEMORY (-6) buffer too small dvander@2762: PCRE_ERROR_NOSUBSTRING (-7) no such captured substring dvander@2762: */ dvander@2762: dvander@2762: PCRE_EXP_DEFN int PCRE_CALL_CONVENTION dvander@2762: pcre_copy_named_substring(const pcre *code, const char *subject, int *ovector, dvander@2762: int stringcount, const char *stringname, char *buffer, int size) dvander@2762: { dvander@2762: int n = get_first_set(code, stringname, ovector); dvander@2762: if (n <= 0) return n; dvander@2762: return pcre_copy_substring(subject, ovector, stringcount, n, buffer, size); dvander@2762: } dvander@2762: dvander@2762: dvander@2762: dvander@2762: /************************************************* dvander@2762: * Copy all captured strings to new store * dvander@2762: *************************************************/ dvander@2762: dvander@2762: /* This function gets one chunk of store and builds a list of pointers and all dvander@2762: of the captured substrings in it. A NULL pointer is put on the end of the list. dvander@2762: dvander@2762: Arguments: dvander@2762: subject the subject string that was matched dvander@2762: ovector pointer to the offsets table dvander@2762: stringcount the number of substrings that were captured dvander@2762: (i.e. the yield of the pcre_exec call, unless dvander@2762: that was zero, in which case it should be 1/3 dvander@2762: of the offset table size) dvander@2762: listptr set to point to the list of pointers dvander@2762: dvander@2762: Returns: if successful: 0 dvander@2762: if not successful: dvander@2762: PCRE_ERROR_NOMEMORY (-6) failed to get store dvander@2762: */ dvander@2762: dvander@2762: PCRE_EXP_DEFN int PCRE_CALL_CONVENTION dvander@2762: pcre_get_substring_list(const char *subject, int *ovector, int stringcount, dvander@2762: const char ***listptr) dvander@2762: { dvander@2762: int i; dvander@2762: int size = sizeof(char *); dvander@2762: int double_count = stringcount * 2; dvander@2762: char **stringlist; dvander@2762: char *p; dvander@2762: dvander@2762: for (i = 0; i < double_count; i += 2) dvander@2762: size += sizeof(char *) + ovector[i+1] - ovector[i] + 1; dvander@2762: dvander@2762: stringlist = (char **)(pcre_malloc)(size); dvander@2762: if (stringlist == NULL) return PCRE_ERROR_NOMEMORY; dvander@2762: dvander@2762: *listptr = (const char **)stringlist; dvander@2762: p = (char *)(stringlist + stringcount + 1); dvander@2762: dvander@2762: for (i = 0; i < double_count; i += 2) dvander@2762: { dvander@2762: int len = ovector[i+1] - ovector[i]; dvander@2762: memcpy(p, subject + ovector[i], len); dvander@2762: *stringlist++ = p; dvander@2762: p += len; dvander@2762: *p++ = 0; dvander@2762: } dvander@2762: dvander@2762: *stringlist = NULL; dvander@2762: return 0; dvander@2762: } dvander@2762: dvander@2762: dvander@2762: dvander@2762: /************************************************* dvander@2762: * Free store obtained by get_substring_list * dvander@2762: *************************************************/ dvander@2762: dvander@2762: /* This function exists for the benefit of people calling PCRE from non-C dvander@2762: programs that can call its functions, but not free() or (pcre_free)() directly. dvander@2762: dvander@2762: Argument: the result of a previous pcre_get_substring_list() dvander@2762: Returns: nothing dvander@2762: */ dvander@2762: dvander@2762: PCRE_EXP_DEFN void PCRE_CALL_CONVENTION dvander@2762: pcre_free_substring_list(const char **pointer) dvander@2762: { dvander@2762: (pcre_free)((void *)pointer); dvander@2762: } dvander@2762: dvander@2762: dvander@2762: dvander@2762: /************************************************* dvander@2762: * Copy captured string to new store * dvander@2762: *************************************************/ dvander@2762: dvander@2762: /* This function copies a single captured substring into a piece of new dvander@2762: store dvander@2762: dvander@2762: Arguments: dvander@2762: subject the subject string that was matched dvander@2762: ovector pointer to the offsets table dvander@2762: stringcount the number of substrings that were captured dvander@2762: (i.e. the yield of the pcre_exec call, unless dvander@2762: that was zero, in which case it should be 1/3 dvander@2762: of the offset table size) dvander@2762: stringnumber the number of the required substring dvander@2762: stringptr where to put a pointer to the substring dvander@2762: dvander@2762: Returns: if successful: dvander@2762: the length of the string, not including the zero that dvander@2762: is put on the end; can be zero dvander@2762: if not successful: dvander@2762: PCRE_ERROR_NOMEMORY (-6) failed to get store dvander@2762: PCRE_ERROR_NOSUBSTRING (-7) substring not present dvander@2762: */ dvander@2762: dvander@2762: PCRE_EXP_DEFN int PCRE_CALL_CONVENTION dvander@2762: pcre_get_substring(const char *subject, int *ovector, int stringcount, dvander@2762: int stringnumber, const char **stringptr) dvander@2762: { dvander@2762: int yield; dvander@2762: char *substring; dvander@2762: if (stringnumber < 0 || stringnumber >= stringcount) dvander@2762: return PCRE_ERROR_NOSUBSTRING; dvander@2762: stringnumber *= 2; dvander@2762: yield = ovector[stringnumber+1] - ovector[stringnumber]; dvander@2762: substring = (char *)(pcre_malloc)(yield + 1); dvander@2762: if (substring == NULL) return PCRE_ERROR_NOMEMORY; dvander@2762: memcpy(substring, subject + ovector[stringnumber], yield); dvander@2762: substring[yield] = 0; dvander@2762: *stringptr = substring; dvander@2762: return yield; dvander@2762: } dvander@2762: dvander@2762: dvander@2762: dvander@2762: /************************************************* dvander@2762: * Copy named captured string to new store * dvander@2762: *************************************************/ dvander@2762: dvander@2762: /* This function copies a single captured substring, identified by name, into dvander@2762: new store. If the regex permits duplicate names, the first substring that is dvander@2762: set is chosen. dvander@2762: dvander@2762: Arguments: dvander@2762: code the compiled regex dvander@2762: subject the subject string that was matched dvander@2762: ovector pointer to the offsets table dvander@2762: stringcount the number of substrings that were captured dvander@2762: (i.e. the yield of the pcre_exec call, unless dvander@2762: that was zero, in which case it should be 1/3 dvander@2762: of the offset table size) dvander@2762: stringname the name of the required substring dvander@2762: stringptr where to put the pointer dvander@2762: dvander@2762: Returns: if successful: dvander@2762: the length of the copied string, not including the zero dvander@2762: that is put on the end; can be zero dvander@2762: if not successful: dvander@2762: PCRE_ERROR_NOMEMORY (-6) couldn't get memory dvander@2762: PCRE_ERROR_NOSUBSTRING (-7) no such captured substring dvander@2762: */ dvander@2762: dvander@2762: PCRE_EXP_DEFN int PCRE_CALL_CONVENTION dvander@2762: pcre_get_named_substring(const pcre *code, const char *subject, int *ovector, dvander@2762: int stringcount, const char *stringname, const char **stringptr) dvander@2762: { dvander@2762: int n = get_first_set(code, stringname, ovector); dvander@2762: if (n <= 0) return n; dvander@2762: return pcre_get_substring(subject, ovector, stringcount, n, stringptr); dvander@2762: } dvander@2762: dvander@2762: dvander@2762: dvander@2762: dvander@2762: /************************************************* dvander@2762: * Free store obtained by get_substring * dvander@2762: *************************************************/ dvander@2762: dvander@2762: /* This function exists for the benefit of people calling PCRE from non-C dvander@2762: programs that can call its functions, but not free() or (pcre_free)() directly. dvander@2762: dvander@2762: Argument: the result of a previous pcre_get_substring() dvander@2762: Returns: nothing dvander@2762: */ dvander@2762: dvander@2762: PCRE_EXP_DEFN void PCRE_CALL_CONVENTION dvander@2762: pcre_free_substring(const char *pointer) dvander@2762: { dvander@2762: (pcre_free)((void *)pointer); dvander@2762: } dvander@2762: dvander@2762: /* End of pcre_get.c */