| 11918 | }; |
| 11919 | |
| 11920 | int RegExCallout(pcret_callout_block *cb) |
| 11921 | { |
| 11922 | // It should be documented that (?C) is ignored if encountered by the hook thread, |
| 11923 | // which could happen if SetTitleMatchMode,Regex and "#HotIf Winactive/Exist" are used. |
| 11924 | // This would be a problem if the callout should affect the outcome of the match or |
| 11925 | // should be called even if #HotIf WinA/E. will ultimately prevent the hotkey from firing. |
| 11926 | // This is because: |
| 11927 | // - The callout cannot be called from the hook thread, and therefore cannot affect |
| 11928 | // the outcome of #HotIf WinA/E. when called by the hook thread. |
| 11929 | // - If #HotIf WinA/E does NOT prevent the hotkey from firing, it will be reevaluated from |
| 11930 | // the main thread before the hotkey is actually fired. This will allow any |
| 11931 | // callouts to occur on the main thread. |
| 11932 | // - By contrast, if #HotIf WinA/E DOES prevent the hotkey from firing, |
| 11933 | // #HotIf WinA/E will not be reevaluated from the main thread, |
| 11934 | // so callouts cannot occur. |
| 11935 | if (GetCurrentThreadId() != g_MainThreadID) |
| 11936 | return 0; |
| 11937 | |
| 11938 | if (!cb->callout_data) |
| 11939 | return 0; |
| 11940 | RegExCalloutData &cd = *(RegExCalloutData *)cb->callout_data; |
| 11941 | |
| 11942 | auto callout_func = (IObject *)cb->user_callout; |
| 11943 | if (!callout_func) |
| 11944 | { |
| 11945 | Var *pcre_callout_var = g_script.FindVar(_T("pcre_callout"), 12, FINDVAR_FOR_READ); // This may be a local of the UDF which called RegExMatch/Replace(). |
| 11946 | if (!pcre_callout_var) |
| 11947 | return 0; // Seems best to ignore the callout rather than aborting the match. |
| 11948 | callout_func = pcre_callout_var->ToObject(); |
| 11949 | if (!callout_func) |
| 11950 | { |
| 11951 | if (!pcre_callout_var->HasContents()) // Var exists but is empty. |
| 11952 | return 0; |
| 11953 | // Could be an invalid name, or the name of a built-in function. |
| 11954 | cd.result_token->Error(_T("Invalid pcre_callout")); |
| 11955 | return PCRE_ERROR_CALLOUT; |
| 11956 | } |
| 11957 | } |
| 11958 | |
| 11959 | // Adjust offset to account for options, which are excluded from the regex passed to PCRE. |
| 11960 | cb->pattern_position += cd.options_length; |
| 11961 | |
| 11962 | // Save EventInfo to be restored when we return. |
| 11963 | EventInfoType EventInfo_saved = g->EventInfo; |
| 11964 | |
| 11965 | g->EventInfo = (EventInfoType) cb; |
| 11966 | |
| 11967 | /* |
| 11968 | callout_number: should be available since callout number can be specified within (?C...). |
| 11969 | subject: useful when behaviour might depend on text surrounding a capture. |
| 11970 | start_match: as above. equivalent to return value of RegExMatch, so should be available somehow. |
| 11971 | |
| 11972 | pattern_position: useful to debug regexes when combined with auto-callouts. otherwise not useful. |
| 11973 | next_item_length: as above. combined 'next_item' instead of these two would be less useful as it cannot distinguish between multiple identical items, and would sometimes be empty. |
| 11974 | |
| 11975 | capture_top: not sure if useful? helps to distinguish between empty capture and non-capture. could maybe use callout number to determine this instead. |
| 11976 | capture_last: as above. |
| 11977 |
nothing calls this directly
no test coverage detected