/* * BRLTTY - A background process providing access to the console screen (when in * text mode) for a blind person using a refreshable braille display. * * Copyright (C) 1995-2021 by The BRLTTY Developers. * * BRLTTY comes with ABSOLUTELY NO WARRANTY. * * This is free software, placed under the terms of the * GNU Lesser General Public License, as published by the Free Software * Foundation; either version 2.1 of the License, or (at your option) any * later version. Please see the file LICENSE-LGPL for details. * * Web Page: http://brltty.app/ * * This software is maintained by Dave Mielke . */ #include "prologue.h" #include #include "log.h" #include "rgx.h" #include "rgx_internal.h" #include "strfmt.h" static int savedErrorCode = 0; static const char *savedErrorMessage = NULL; static void saveErrorMessage (int error, const char *message) { if (message && *message) { savedErrorCode = error; savedErrorMessage = message; } } static const char * getErrorMessage (int error) { if (error == savedErrorCode) return savedErrorMessage; return NULL; } RGX_CodeType * rgxCompilePattern ( const RGX_CharacterType *characters, size_t length, RGX_OptionsType options, RGX_OffsetType *offset, int *error ) { const char *message; RGX_CodeType *code = pcre32_compile2( characters, options, error, &message, offset, NULL ); if (!code) saveErrorMessage(*error, message); return code; } void rgxDeallocateCode (RGX_CodeType *code) { pcre32_free(code); } RGX_DataType * rgxAllocateData (RGX_CodeType *code) { RGX_DataType *data; size_t size = sizeof(*data); size_t matches = 10; size_t count = matches * 3; size += count * sizeof(data->offsets[0]); if (!(data = malloc(size))) return NULL; memset(data, 0, size); data->matches = matches; data->count = count; { const char *message = NULL; data->study = pcre32_study(code, 0, &message); if (message) { logMessage(LOG_WARNING, "pcre study error: %s", message); if (data->study) { pcre32_free_study(data->study); data->study = NULL; } } } return data; } void rgxDeallocateData (RGX_DataType *data) { if (data->study) pcre32_free_study(data->study); free(data); } int rgxMatchText ( const RGX_CharacterType *characters, size_t length, RGX_CodeType *code, RGX_DataType *data, RGX_OptionsType options, size_t *count, int *error ) { int result = pcre32_exec( code, data->study, characters, length, 0, options, data->offsets, data->count ); if (result < 0) { *error = result; return 0; } if (!result) result = data->matches; *count = result - 1; return 1; } int rgxNameNumber ( RGX_CodeType *code, const RGX_CharacterType *name, size_t *number, int *error ) { int result = pcre32_get_stringnumber(code, name); if (result > 0) { *number = result; return 1; } else { *error = result; return 0; } } int rgxCaptureBounds ( RGX_DataType *data, size_t number, size_t *from, size_t *to ) { const RGX_OffsetType *offsets = data->offsets; offsets += number * 2; if (offsets[0] == -1) return 0; if (offsets[1] == -1) return 0; *from = offsets[0]; *to = offsets[1]; return 1; } static const char *const rgxNegativeErrors[] = { [0] = "no error", [-PCRE_ERROR_NOMATCH] = "no match", [-PCRE_ERROR_NULL] = "required pointer argument is null", [-PCRE_ERROR_BADOPTION] = "unrecognized option", [-PCRE_ERROR_BADMAGIC] = "magic number not found", [-PCRE_ERROR_UNKNOWN_OPCODE] = "invalid item in compiled pattern", [-PCRE_ERROR_NOMEMORY] = "insufficient memory", [-PCRE_ERROR_NOSUBSTRING] = "no capture with specified number or name", [-PCRE_ERROR_MATCHLIMIT] = "match limit exceeded", [-PCRE_ERROR_CALLOUT] = "error in callout", [-PCRE_ERROR_BADUTF32] = "invalid UTF-32 character", [-PCRE_ERROR_BADUTF16_OFFSET] = "start offset is within a multibyte character", [-PCRE_ERROR_PARTIAL] = "partial match", [-PCRE_ERROR_BADPARTIAL] = "pattern contains item not supported for partial match", [-PCRE_ERROR_INTERNAL] = "internal error", [-PCRE_ERROR_BADCOUNT] = "size of offsets vector is negative", [-PCRE_ERROR_DFA_UITEM] = "pattern contains item not supported for DFA match", [-PCRE_ERROR_DFA_UCOND] = "DFA match uses back reference for condition or test for recursion in specific group", [-PCRE_ERROR_DFA_UMLIMIT] = "match or recursion limit specified for DFA match", [-PCRE_ERROR_DFA_WSSIZE] = "DFA workspace overflow", [-PCRE_ERROR_DFA_RECURSE] = "DFA recursion offsets vector too small", [-PCRE_ERROR_RECURSIONLIMIT] = "recursion limit exceeded", [-PCRE_ERROR_NULLWSLIMIT] = "", [-PCRE_ERROR_BADNEWLINE] = "invalid newline option combination", [-PCRE_ERROR_BADOFFSET] = "start offset out of bounds", [-PCRE_ERROR_SHORTUTF16] = "truncated multibyte character", [-PCRE_ERROR_RECURSELOOP] = "recursion loop detected", [-PCRE_ERROR_JIT_STACKLIMIT] = "JIT stack too small", [-PCRE_ERROR_BADMODE] = "pattern compiled for different character size", [-PCRE_ERROR_BADENDIANNESS] = "pattern compiled for different host endianness", [-PCRE_ERROR_DFA_BADRESTART] = "unable to resume partial DFA match", [-PCRE_ERROR_JIT_BADOPTION] = "invalid JIT option", [-PCRE_ERROR_BADLENGTH] = "text length is negative", [-PCRE_ERROR_UNSET] = "required value not set", }; STR_BEGIN_FORMATTER(rgxFormatErrorMessage, int error) const char *message = getErrorMessage(error); if (!message) { if (error <= 0) { if ((error = -error) < ARRAY_COUNT(rgxNegativeErrors)) { message = rgxNegativeErrors[error]; } } } if (message && *message) STR_PRINTF("%s", message); STR_END_FORMATTER RGX_BEGIN_OPTION_MAP(rgxCompileOptions) [RGX_COMPILE_ANCHOR_START] = PCRE_ANCHORED, [RGX_COMPILE_IGNORE_CASE] = PCRE_CASELESS, [RGX_COMPILE_UNICODE_PROPERTIES] = PCRE_UCP, RGX_END_OPTION_MAP(rgxCompileOptions) RGX_BEGIN_OPTION_MAP(rgxMatchOptions) [RGX_MATCH_ANCHOR_START] = PCRE_ANCHORED, RGX_END_OPTION_MAP(rgxMatchOptions)