/** Extract a named subcapture value from the request * * @note This is the PCRE variant of the function. * * @param[in] ctx To allocate subcapture buffer in. * @param[out] out Where to write the subcapture string. * @param[in] request to extract. * @param[in] name of subcapture. * @return * - 0 on success. * - -1 on notfound. */ int regex_request_to_sub_named(TALLOC_CTX *ctx, char **out, REQUEST *request, char const *name) { fr_regcapture_t *rc; char const *p; int ret; rc = request_data_reference(request, request, REQUEST_DATA_REGEX); if (!rc) { RDEBUG4("No subcapture data found"); *out = NULL; return 1; } ret = pcre_get_named_substring(rc->preg->compiled, rc->regmatch->subject, (int *)rc->regmatch->match_data, (int)rc->regmatch->used, name, &p); switch (ret) { case PCRE_ERROR_NOMEMORY: MEM(NULL); /* * We can't really fall through, but GCC 7.3 is * too stupid to realise that we can never get * here despite _fr_exit_now being marked as * NEVER_RETURNS. * * If we did anything else, compilers and static * analysis tools would probably complain about * code that could never be executed *sigh*. */ /* FALL-THROUGH */ /* * Not finding a substring is fine */ case PCRE_ERROR_NOSUBSTRING: RDEBUG4("No named capture group \"%s\"", name); *out = NULL; return -1; default: if (ret < 0) { *out = NULL; return -1; } /* * Check libpcre really is using our overloaded * memory allocation and freeing talloc wrappers. */ talloc_set_type(p, char); talloc_steal(ctx, p); RDEBUG4("Found \"%s\": %pV (%zu)", name, fr_box_strvalue_buffer(p), talloc_array_length(p) - 1); memcpy(out, &p, sizeof(*out)); break; } return 0; }
std::string Pattern::group (const std::string& groupName) { const char * stringPtr = NULL; int rc = pcre_get_named_substring ( _re, _subject.substr (_offset[0]).c_str(), _ovector, _count, groupName.c_str(), &stringPtr); if (rc < 0) { switch (rc) { case PCRE_ERROR_NOSUBSTRING: break; case PCRE_ERROR_NOMEMORY: throw match_error ("Memory exhausted."); default: throw match_error ("Failed to get named substring."); } } std::string matchedStr; if (stringPtr) { matchedStr = stringPtr; pcre_free_substring (stringPtr); } else { matchedStr = ""; } return matchedStr; }
int sss_parse_name(TALLOC_CTX *memctx, struct sss_names_ctx *snctx, const char *orig, char **_domain, char **_name) { pcre *re = snctx->re; const char *result; int ovec[30]; int origlen; int ret, strnum; origlen = strlen(orig); ret = pcre_exec(re, NULL, orig, origlen, 0, PCRE_NOTEMPTY, ovec, 30); if (ret == PCRE_ERROR_NOMATCH) { return ERR_REGEX_NOMATCH; } else if (ret < 0) { DEBUG(SSSDBG_MINOR_FAILURE, "PCRE Matching error, %d\n", ret); return EINVAL; } if (ret == 0) { DEBUG(SSSDBG_CRIT_FAILURE, "Too many matches, the pattern is invalid.\n"); } strnum = ret; if (_name != NULL) { result = NULL; ret = pcre_get_named_substring(re, orig, ovec, strnum, "name", &result); if (ret < 0 || !result) { DEBUG(SSSDBG_OP_FAILURE, "Name not found!\n"); return EINVAL; } *_name = talloc_strdup(memctx, result); pcre_free_substring(result); if (!*_name) return ENOMEM; } if (_domain != NULL) { result = NULL; ret = pcre_get_named_substring(re, orig, ovec, strnum, "domain", &result); if (ret < 0 || !result) { DEBUG(SSSDBG_CONF_SETTINGS, "Domain not provided!\n"); *_domain = NULL; } else { /* ignore "" string */ if (*result) { *_domain = talloc_strdup(memctx, result); pcre_free_substring(result); if (!*_domain) return ENOMEM; } else { pcre_free_substring(result); *_domain = NULL; } } } return EOK; }
pcre_error_code pcre_private(char *INPUT_LINE, char *INPUT_PAT, int *Output_Start, int *Output_End, char*** _pstCapturedString, int* _piCapturedStringCount) { /* ALL strings are managed as UTF-8 by default */ int options = PCRE_UTF8; int size_offsets = 45; int size_offsets_max; int *offsets = NULL; int all_use_dfa = 0; BOOL LOOP_PCRE_TST = FALSE; /* These vectors store, end-to-end, a list of captured substring names. Assume that 1024 is plenty long enough for the few names we'll be testing. */ char copynames[1024]; char getnames[1024]; char *copynamesptr = NULL; char *getnamesptr = NULL; int rc = 0; (void)pcre_config(PCRE_CONFIG_UTF8, &rc); if (rc != 1) { return UTF8_NOT_SUPPORTED; } /* bug 3891 */ /* backslash characters are not interpreted for input */ buffer = strsub(INPUT_LINE, "\\", "\\\\"); size_offsets_max = size_offsets; offsets = (int *)MALLOC(size_offsets_max * sizeof(int)); if (offsets == NULL) { if (buffer) { FREE(buffer); buffer = NULL; } return NOT_ENOUGH_MEMORY_FOR_VECTOR; } /* Main loop */ LOOP_PCRE_TST = FALSE; while (!LOOP_PCRE_TST) { pcre *re = NULL; pcre_extra *extra = NULL; const char *error = NULL; char *back_p = NULL; char *p = NULL; char *pp = NULL; char *ppp = NULL; const unsigned char *tables = NULL; int do_G = 0; int do_g = 0; int erroroffset = 0, len = 0, delimiter; LOOP_PCRE_TST = TRUE; p = strdup(INPUT_PAT); back_p = p; while (isspace(*p)) { p++; } if (*p == 0) { continue; } /* In-line pattern (the usual case). Get the delimiter and seek the end of the pattern; if is isn't complete, read more. */ delimiter = *p++; if (isalnum(delimiter) || delimiter == '\\') { if (buffer) { FREE(buffer); buffer = NULL; } if (offsets) { FREE(offsets); offsets = NULL; } if (back_p) { FREE(back_p); back_p = NULL; } return DELIMITER_NOT_ALPHANUMERIC; } pp = p; while (*pp != 0) { if (*pp == '\\' && pp[1] != 0) { pp++; } else if (*pp == delimiter) { break; } pp++; } /* If the delimiter can't be found, it's a syntax error */ if (*pp == 0) { if (buffer) { FREE(buffer); buffer = NULL; } if (offsets) { FREE(offsets); offsets = NULL; } if (back_p) { FREE(back_p); back_p = NULL; } if (offsets) { FREE(offsets); } return CAN_NOT_COMPILE_PATTERN; } /* If the first character after the delimiter is backslash, make the pattern end with backslash. This is purely to provide a way of testing for the error message when a pattern ends with backslash. */ if (pp[1] == '\\') { *pp++ = '\\'; } /* Terminate the pattern at the delimiter, and save a copy of the pattern for callouts. */ *pp++ = 0; /* Look for options after final delimiter */ //options = 8192; while (*pp != 0) { switch (*pp++) { case 'f': options |= PCRE_FIRSTLINE; break; case 'g': do_g = 1; break; case 'i': options |= PCRE_CASELESS; break; case 'm': options |= PCRE_MULTILINE; break; case 's': options |= PCRE_DOTALL; break; case 'x': options |= PCRE_EXTENDED; break; case '+': break; case 'A': options |= PCRE_ANCHORED; break; case 'B': break; case 'C': options |= PCRE_AUTO_CALLOUT; break; case 'D': break; case 'E': options |= PCRE_DOLLAR_ENDONLY; break; case 'F': break; case 'G': do_G = 1; break; case 'I': break; case 'J': options |= PCRE_DUPNAMES; break; case 'M': break; case 'N': options |= PCRE_NO_AUTO_CAPTURE; break; case 'S': break; case 'U': options |= PCRE_UNGREEDY; break; case 'X': options |= PCRE_EXTRA; break; case 'Z': break; case '8': { int rc = 0; (void)pcre_config(PCRE_CONFIG_UTF8, &rc); if (rc != 1) { if (buffer) { FREE(buffer); buffer = NULL; } if (offsets) { FREE(offsets); } return UTF8_NOT_SUPPORTED; } options |= PCRE_UTF8; } break; case '?': options |= PCRE_NO_UTF8_CHECK; break; case 'L': ppp = pp; /* The '\r' test here is so that it works on Windows. */ /* The '0' test is just in case this is an unterminated line. */ while (*ppp != 0 && *ppp != '\n' && *ppp != '\r' && *ppp != ' ') { ppp++; } *ppp = 0; if (setlocale(LC_CTYPE, (const char *)pp) == NULL) { goto SKIP_DATA; } tables = pcre_maketables(); pp = ppp; break; case '>': while (*pp != 0) { pp++; } while (isspace(pp[-1])) { pp--; } *pp = 0; break; case '<': { while (*pp++ != '>') { ; } } break; case '\r': /* So that it works in Windows */ case '\n': case ' ': break; default: goto SKIP_DATA; } } /* Handle compiling via the POSIX interface, which doesn't support the timing, showing, or debugging options, nor the ability to pass over local character tables. */ { re = pcre_compile((char *)p, options, &error, &erroroffset, tables); /* Compilation failed; go back for another re, skipping to blank line if non-interactive. */ if (re == NULL) { SKIP_DATA: if (buffer) { FREE(buffer); buffer = NULL; } if (offsets) { FREE(offsets); offsets = NULL; } if (tables) { (*pcre_free)((void*)tables); tables = NULL; } if (extra) { FREE(extra); extra = NULL; } if (back_p) { FREE(back_p); back_p = NULL; } return CAN_NOT_COMPILE_PATTERN; } } /* End of non-POSIX compile */ /* Read data lines and test them */ { char *q = NULL; char *bptr = NULL; int *use_offsets = offsets; int use_size_offsets = size_offsets; int callout_data = 0; int callout_data_set = 0; int count = 0; int c = 0; int copystrings = 0; int find_match_limit = 0; int getstrings = 0; int gmatched = 0; int start_offset = 0; int g_notempty = 0; int use_dfa = 0; options = 0; *copynames = 0; *getnames = 0; copynamesptr = copynames; getnamesptr = getnames; callout_count = 0; callout_fail_count = 999999; callout_fail_id = -1; if (extra != NULL) { extra->flags &= ~(PCRE_EXTRA_MATCH_LIMIT | PCRE_EXTRA_MATCH_LIMIT_RECURSION); } p = buffer; bptr = q = buffer; while ((c = *p++) != 0) { int i = 0; int n = 0; if (c == '\\') switch ((c = *p++)) { case 'a': c = 7; break; case 'b': c = '\b'; break; case 'e': c = 27; break; case 'f': c = '\f'; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'v': c = '\v'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': c -= '0'; while (i++ < 2 && isdigit(*p) && *p != '8' && *p != '9') { c = c * 8 + *p++ - '0'; } break; case 'x': /* Ordinary \x */ c = 0; while (i++ < 2 && isxdigit(*p)) { c = c * 16 + tolower(*p) - ((isdigit(*p)) ? '0' : 'W'); p++; } break; case 0: /* \ followed by EOF allows for an empty line */ p--; continue; case '>': while (isdigit(*p)) { start_offset = start_offset * 10 + *p++ - '0'; } continue; case 'A': /* Option setting */ options |= PCRE_ANCHORED; continue; case 'B': options |= PCRE_NOTBOL; continue; case 'C': if (isdigit(*p)) /* Set copy string */ { while (isdigit(*p)) { n = n * 10 + *p++ - '0'; } copystrings |= 1 << n; } else if (isalnum(*p)) { char *npp = copynamesptr; while (isalnum(*p)) { *npp++ = *p++; } *npp++ = 0; *npp = 0; pcre_get_stringnumber(re, (char *)copynamesptr); copynamesptr = npp; } else if (*p == '+') { p++; } else if (*p == '-') { p++; } else if (*p == '!') { callout_fail_id = 0; p++; while (isdigit(*p)) { callout_fail_id = callout_fail_id * 10 + *p++ - '0'; } callout_fail_count = 0; if (*p == '!') { p++; while (isdigit(*p)) { callout_fail_count = callout_fail_count * 10 + *p++ - '0'; } } } else if (*p == '*') { int sign = 1; callout_data = 0; if (*(++p) == '-') { sign = -1; p++; } while (isdigit(*p)) { callout_data = callout_data * 10 + *p++ - '0'; } callout_data *= sign; callout_data_set = 1; } continue; case 'G': if (isdigit(*p)) { while (isdigit(*p)) { n = n * 10 + *p++ - '0'; } getstrings |= 1 << n; } else if (isalnum(*p)) { char *npp = getnamesptr; while (isalnum(*p)) { *npp++ = *p++; } *npp++ = 0; *npp = 0; pcre_get_stringnumber(re, (char *)getnamesptr); getnamesptr = npp; } continue; case 'L': continue; case 'M': find_match_limit = 1; continue; case 'N': options |= PCRE_NOTEMPTY; continue; case 'O': while (isdigit(*p)) { n = n * 10 + *p++ - '0'; } if (n > size_offsets_max) { size_offsets_max = n; if (offsets) { FREE(offsets); } use_offsets = offsets = (int *)MALLOC(size_offsets_max * sizeof(int)); } use_size_offsets = n; if (n == 0) { use_offsets = NULL; /* Ensures it can't write to it */ } continue; case 'P': options |= PCRE_PARTIAL; continue; case 'Q': while (isdigit(*p)) { n = n * 10 + *p++ - '0'; } if (extra == NULL) { extra = (pcre_extra *)MALLOC(sizeof(pcre_extra)); extra->flags = 0; } extra->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION; extra->match_limit_recursion = n; continue; case 'q': while (isdigit(*p)) { n = n * 10 + *p++ - '0'; } if (extra == NULL) { extra = (pcre_extra *)MALLOC(sizeof(pcre_extra)); extra->flags = 0; } extra->flags |= PCRE_EXTRA_MATCH_LIMIT; extra->match_limit = n; continue; #if !defined NODFA case 'R': options |= PCRE_DFA_RESTART; continue; #endif case 'S': continue; case 'Z': options |= PCRE_NOTEOL; continue; case '?': options |= PCRE_NO_UTF8_CHECK; continue; case '<': { while (*p++ != '>') { ; } } continue; } *q++ = (char)c; } *q = 0; len = (int)(q - buffer); if ((all_use_dfa || use_dfa) && find_match_limit) { if (buffer) { FREE(buffer); buffer = NULL; } if (offsets) { FREE(offsets); offsets = NULL; } if (p) { FREE(p); p = NULL; } if (re) { (*pcre_free)(re); re = NULL; } if (tables) { (*pcre_free)((void*)tables); tables = NULL; } if (extra) { FREE(extra); extra = NULL; } return LIMIT_NOT_RELEVANT_FOR_DFA_MATCHING; } /* Handle matching via the POSIX interface, which does not support timing or playing with the match limit or callout data. */ for (;; gmatched++) /* Loop for /g or /G */ { /* If find_match_limit is set, we want to do repeated matches with varying limits in order to find the minimum value for the match limit and for the recursion limit. */ if (find_match_limit) { if (extra == NULL) { extra = (pcre_extra *)MALLOC(sizeof(pcre_extra)); extra->flags = 0; } (void)check_match_limit(re, extra, bptr, len, start_offset, options | g_notempty, use_offsets, use_size_offsets, PCRE_EXTRA_MATCH_LIMIT, &(extra->match_limit), PCRE_ERROR_MATCHLIMIT); count = check_match_limit(re, extra, bptr, len, start_offset, options | g_notempty, use_offsets, use_size_offsets, PCRE_EXTRA_MATCH_LIMIT_RECURSION, &(extra->match_limit_recursion), PCRE_ERROR_RECURSIONLIMIT); } /* If callout_data is set, use the interface with additional data */ else if (callout_data_set) { if (extra == NULL) { extra = (pcre_extra *)MALLOC(sizeof(pcre_extra)); extra->flags = 0; } extra->flags |= PCRE_EXTRA_CALLOUT_DATA; extra->callout_data = &callout_data; count = pcre_exec(re, extra, (char *)bptr, len, start_offset, options | g_notempty, use_offsets, use_size_offsets); extra->flags &= ~PCRE_EXTRA_CALLOUT_DATA; } /* The normal case is just to do the match once, with the default value of match_limit. */ else { count = pcre_exec(re, extra, (char *)bptr, len, start_offset, options | g_notempty, use_offsets, use_size_offsets); if (count == 0) { count = use_size_offsets / 3; } //to retrieve backref count and values if (count > 0 && _pstCapturedString != NULL && _piCapturedStringCount != NULL) { int i = 0; int iErr = 0; iErr = pcre_fullinfo(re, extra, PCRE_INFO_CAPTURECOUNT, _piCapturedStringCount); //sciprint("PCRE_INFO_CAPTURECOUNT %d\n", *_piCapturedStringCount); if (*_piCapturedStringCount > 0) { *_pstCapturedString = (char**)MALLOC(sizeof(char*) * *_piCapturedStringCount); for (i = 0 ; i < *_piCapturedStringCount ; i++) { char* pstSubstring = NULL; pcre_get_substring(bptr, use_offsets, count, i + 1, &pstSubstring); if (pstSubstring != NULL) { (*_pstCapturedString)[i] = strdup(pstSubstring); } pcre_free_substring(pstSubstring); } } } } /* Matched */ if (count >= 0) { int i, maxcount; maxcount = use_size_offsets / 3; /* This is a check against a lunatic return value. */ if (count > maxcount) { if (buffer) { FREE(buffer); buffer = NULL; } if (offsets) { FREE(offsets); offsets = NULL; } if (re) { (*pcre_free)(re); re = NULL; } if (tables) { (*pcre_free)((void*)tables); tables = NULL; } if (extra) { FREE(extra); extra = NULL; } if (back_p) { FREE(back_p); back_p = NULL; } return TOO_BIG_FOR_OFFSET_SIZE; } for (i = 0; i < count * 2; i += 2) { if (use_offsets[i] >= 0) { *Output_Start = use_offsets[i]; *Output_End = use_offsets[i + 1]; if (buffer) { FREE(buffer); } /* use_offsets = offsets no need to free use_offsets if we free offsets */ if (offsets) { FREE(offsets); } /* "re" allocated by pcre_compile (better to use free function associated)*/ if (re) { (*pcre_free)(re); } if (extra) { FREE(extra); } if (tables) { /* "tables" allocated by pcre_maketables (better to use free function associated to pcre)*/ (*pcre_free)((void *)tables); tables = NULL; setlocale(LC_CTYPE, "C"); } if (back_p) { FREE(back_p); back_p = NULL; } return PCRE_FINISHED_OK; } } for (copynamesptr = copynames; *copynamesptr != 0; copynamesptr += (int)strlen((char*)copynamesptr) + 1) { char copybuffer[256]; pcre_copy_named_substring(re, (char *)bptr, use_offsets, count, (char *)copynamesptr, copybuffer, sizeof(copybuffer)); } for (i = 0; i < 32; i++) { if ((getstrings & (1 << i)) != 0) { const char *substring; pcre_get_substring((char *)bptr, use_offsets, count, i, &substring); } } for (getnamesptr = getnames; *getnamesptr != 0; getnamesptr += (int)strlen((char*)getnamesptr) + 1) { const char *substring; pcre_get_named_substring(re, (char *)bptr, use_offsets, count, (char *)getnamesptr, &substring); } } /* Failed to match. If this is a /g or /G loop and we previously set g_notempty after a null match, this is not necessarily the end. We want to advance the start offset, and continue. We won't be at the end of the string - that was checked before setting g_notempty. Complication arises in the case when the newline option is "any" or "anycrlf". If the previous match was at the end of a line terminated by CRLF, an advance of one character just passes the \r, whereas we should prefer the longer newline sequence, as does the code in pcre_exec(). Fudge the offset value to achieve this. Otherwise, in the case of UTF-8 matching, the advance must be one character, not one byte. */ else { if (count == PCRE_ERROR_NOMATCH) { if (gmatched == 0) { if (tables) { (*pcre_free)((void *)tables); tables = NULL; } if (re) { (*pcre_free)((void *)re); re = NULL; } if (buffer) { FREE(buffer); buffer = NULL; } if (offsets) { FREE(offsets); } if (p) { FREE(back_p); back_p = NULL; } return NO_MATCH; } } if (count == PCRE_ERROR_MATCHLIMIT ) { if (tables) { (*pcre_free)((void *)tables); tables = NULL; } if (re) { (*pcre_free)((void *)re); re = NULL; } if (buffer) { FREE(buffer); buffer = NULL; } if (offsets) { FREE(offsets); offsets = NULL; } if (back_p) { FREE(back_p); back_p = NULL; } return MATCH_LIMIT; } break; /* Out of loop */ } /* If not /g or /G we are done */ if (!do_g && !do_G) { break; } /* If we have matched an empty string, first check to see if we are at the end of the subject. If so, the /g loop is over. Otherwise, mimic what Perl's /g options does. This turns out to be rather cunning. First we set PCRE_NOTEMPTY and PCRE_ANCHORED and try the match again at the same point. If this fails (picked up above) we advance to the next character. */ g_notempty = 0; if (use_offsets[0] == use_offsets[1]) { if (use_offsets[0] == len) { break; } g_notempty = PCRE_NOTEMPTY | PCRE_ANCHORED; } /* For /g, update the start offset, leaving the rest alone */ if (do_g) { start_offset = use_offsets[1]; } /* For /G, update the pointer and length */ else { bptr += use_offsets[1]; len -= use_offsets[1]; } } /* End of loop for /g and /G */ if (re) { (*pcre_free)(re); re = NULL; } if (extra) { FREE(extra); extra = NULL; } if (tables) { (*pcre_free)((void *)tables); tables = NULL; } FREE(back_p); back_p = NULL; continue; } /* End of loop for data lines */ } if (buffer) { FREE(buffer); buffer = NULL; } if (offsets) { FREE(offsets); offsets = NULL; } return PCRE_EXIT; }
__declspec(dllexport) void gen_doc_string(char *func_string,int indentation,char** out) { pcre *re; pcre *re2; const char *error; int erroffset; int ovector[OVECCOUNT]; int ovector2[OVECCOUNT]; int rc,rc1; std::string doc_string; std::string indent_spaces=get_spaces(indentation); char *regex="(?P<ret_type>\\w+)\\s+(?P<func_name>\\w+)\\s*\\((?P<func_args>.*)\\)(\\s+(?P<expts_block>throws\\s+(?P<exceptions>.*))|\\s*)"; re = pcre_compile( regex, /* the pattern */ NULL, /* default options */ &error, /* for error message */ &erroffset, /* for error offset */ NULL); /* use default character table */ rc=0; int offset=0; rc = pcre_exec( re, /* the compiled pattern */ NULL, /* no extra data - we didn't study the pattern */ func_string, /* the subject string */ strlen(func_string), /* the length of the subject */ offset, /* start at offset 0 in the subject */ 0, /* default options */ ovector, /* output vector for substring information */ OVECCOUNT); /* number of elements in the output vector */ if (rc < 0) { doc_string.append(indent_spaces); doc_string.append("/**\r\n"); doc_string.append(indent_spaces); doc_string.append(" *\r\n"); doc_string.append(indent_spaces); doc_string.append(" *\r\n"); doc_string.append(indent_spaces); doc_string.append(" *\r\n"); doc_string.append(indent_spaces); doc_string.append(" *\r\n"); doc_string.append(indent_spaces); doc_string.append(" *\r\n"); doc_string.append(indent_spaces); doc_string.append(" */\r\n"); *out=new char[doc_string.size()+1]; strncpy_s(*out,doc_string.size()+1,doc_string.c_str(),doc_string.size()+1); return; } const char *ret=NULL; doc_string.append(indent_spaces); doc_string.append("/**\r\n"); doc_string.append(indent_spaces); doc_string.append(" * \r\n"); doc_string.append(indent_spaces); doc_string.append(" * \r\n"); pcre_get_named_substring(re,func_string,ovector,OVECCOUNT,"func_args",&ret); //parse func_args and insert in each line char *regex2="(?P<arg_type>\\w+)\\s+(?P<arg_name>\\w+)"; re2 = pcre_compile( regex2, /* the pattern */ 0, /* default options */ &error, /* for error message */ &erroffset, /* for error offset */ NULL); /* use default character table */ rc1=0; int offset1=0; rc1 = pcre_exec( re2, /* the compiled pattern */ NULL, /* no extra data - we didn't study the pattern */ ret, /* the subject string */ strlen(ret), /* the length of the subject */ offset1, /* start at offset 0 in the subject */ 0, /* default options */ ovector2, /* output vector for substring information */ OVECCOUNT); /* number of elements in the output vector */ if(rc1>0){ while(rc1!=-1){ const char *ret1=NULL; pcre_get_named_substring(re2,ret,ovector2,OVECCOUNT,"arg_name",&ret1); doc_string.append(indent_spaces); doc_string.append(" * @param "); doc_string.append(ret1); doc_string.append(" \r\n"); pcre_free_substring(ret1); offset1=ovector2[1]; rc1 = pcre_exec( re2, /* the compiled pattern */ NULL, /* no extra data - we didn't study the pattern */ ret, /* the subject string */ strlen(ret), /* the length of the subject */ offset1, /* start at offset 0 in the subject */ 0, /* default options */ ovector2, /* output vector for substring information */ OVECCOUNT); /* number of elements in the output vector */ if (rc1 < 0 || rc < 3) { break; } } } pcre_free_substring(ret); //get return type pcre_get_named_substring(re,func_string,ovector,OVECCOUNT,"ret_type",&ret); if(strcmp(ret,"void")!=0) { doc_string.append(indent_spaces); doc_string.append(" * @return "); doc_string.append(ret); doc_string.append("\r\n"); } pcre_free_substring(ret); //process exceptions block pcre_get_named_substring(re,func_string,ovector,OVECCOUNT,"exceptions",&ret); if(strlen(ret)>0) { //function throws exceptions, include in doc string char *tmp=new char[strlen(ret)]; char *next_token; strcpy_s(tmp,strlen(ret),ret); char *exception_name=strtok_s(tmp,",",&next_token); while(exception_name!=NULL) { std::string s(exception_name); trim(&s); doc_string.append(indent_spaces); doc_string.append(" * @throws "); doc_string.append(s); doc_string.append("\r\n"); exception_name=strtok_s(NULL,",",&next_token); } } doc_string.append(indent_spaces); doc_string.append(" */\r\n"); pcre_free(re); pcre_free(re2); *out=new char[doc_string.size()+1]; strncpy_s(*out,doc_string.size()+1,doc_string.c_str(),doc_string.size()+1); return; }