| 6825 | |
| 6826 | |
| 6827 | UserFunc *Script::AddFunc(LPCTSTR aFuncName, size_t aFuncNameLength, Object *aClassObject) |
| 6828 | // Returns the address of the new function or NULL on failure. |
| 6829 | // The caller must already have verified that this isn't a duplicate function. |
| 6830 | { |
| 6831 | if (aFuncNameLength == -1) // Caller didn't specify, so use the entire string. |
| 6832 | aFuncNameLength = _tcslen(aFuncName); |
| 6833 | |
| 6834 | if (aFuncNameLength > MAX_VAR_NAME_LENGTH) // FindFunc(), BIF_OnMessage() and perhaps others rely on this limit being enforced. |
| 6835 | { |
| 6836 | ScriptError(_T("Function name too long."), aFuncName); |
| 6837 | return nullptr; |
| 6838 | } |
| 6839 | |
| 6840 | // ValidateName requires that the name be null-terminated, but it isn't in this case. |
| 6841 | // Doing this first saves doing tcslcpy() into a temporary buffer, and won't leak memory |
| 6842 | // since the script currently always exits if an error occurs anywhere below: |
| 6843 | LPTSTR new_name = SimpleHeap::Alloc(aFuncName, aFuncNameLength); |
| 6844 | |
| 6845 | if (!aClassObject && *new_name && !Var::ValidateName(new_name, DISPLAY_FUNC_ERROR)) // Variable and function names are both validated the same way. |
| 6846 | return nullptr; // Above already displayed the error for us. |
| 6847 | |
| 6848 | auto the_new_func = new UserFunc(new_name); |
| 6849 | if (!the_new_func) |
| 6850 | { |
| 6851 | ScriptError(ERR_OUTOFMEM); |
| 6852 | return nullptr; |
| 6853 | } |
| 6854 | |
| 6855 | if (aClassObject) |
| 6856 | { |
| 6857 | LPTSTR key = _tcsrchr(new_name, '.'); // DefineFunc() always passes "ClassName.MethodName". |
| 6858 | ++key; |
| 6859 | if (!Var::ValidateName(key, DISPLAY_METHOD_ERROR)) |
| 6860 | return nullptr; |
| 6861 | if (mClassProperty) |
| 6862 | { |
| 6863 | bool is_getter = ctoupper(*key) == 'G'; |
| 6864 | if (is_getter ? mClassProperty->Getter() : mClassProperty->Setter()) |
| 6865 | { |
| 6866 | ScriptError(ERR_DUPLICATE_DECLARATION, new_name); |
| 6867 | return nullptr; |
| 6868 | } |
| 6869 | if (is_getter) |
| 6870 | mClassProperty->SetGetter(the_new_func); |
| 6871 | else |
| 6872 | mClassProperty->SetSetter(the_new_func); |
| 6873 | } |
| 6874 | else |
| 6875 | { |
| 6876 | switch (aClassObject->GetOwnPropType(key)) |
| 6877 | { |
| 6878 | case Object::PropType::Object: |
| 6879 | case Object::PropType::DynamicMethod: // call |
| 6880 | case Object::PropType::DynamicMixed: // get/set and call |
| 6881 | ScriptError(ERR_DUPLICATE_DECLARATION, new_name); |
| 6882 | return nullptr; |
| 6883 | } |
| 6884 | if (!aClassObject->DefineMethod(key, the_new_func)) |
nothing calls this directly
no test coverage detected