/* * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im> * * All rights reserved. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3.0 only, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3.0 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3.0 along with this program. If not, see * <https://www.gnu.org/licenses/>. */ #include "config.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #import "ObjFWRT.h" #import "private.h" static struct objc_hashtable *categoriesMap = NULL; static void registerSelectors(struct objc_category *category) { struct objc_method_list *iter; unsigned int i; for (iter = category->instanceMethods; iter != NULL; iter = iter->next) for (i = 0; i < iter->count; i++) objc_registerSelector(&iter->methods[i].selector); for (iter = category->classMethods; iter != NULL; iter = iter->next) for (i = 0; i < iter->count; i++) objc_registerSelector(&iter->methods[i].selector); } static void registerCategory(struct objc_category *category) { struct objc_category **categories; Class class = objc_classnameToClass(category->className, false); if (categoriesMap == NULL) categoriesMap = objc_hashtable_new( objc_string_hash, objc_string_equal, 2); categories = (struct objc_category **)objc_hashtable_get( categoriesMap, category->className); if (categories != NULL) { struct objc_category **newCategories; size_t i; for (i = 0; categories[i] != NULL; i++); if ((newCategories = realloc(categories, (i + 2) * sizeof(*categories))) == NULL) OBJC_ERROR("Not enough memory for category %s of " "class %s!", category->categoryName, category->className); newCategories[i] = category; newCategories[i + 1] = NULL; objc_hashtable_set(categoriesMap, category->className, newCategories); if (class != Nil && class->info & OBJC_CLASS_INFO_SETUP) { objc_updateDTable(class); objc_updateDTable(class->isa); } return; } if ((categories = malloc(2 * sizeof(*categories))) == NULL) OBJC_ERROR("Not enough memory for category %s of class %s!\n", category->categoryName, category->className); categories[0] = category; categories[1] = NULL; objc_hashtable_set(categoriesMap, category->className, categories); if (class != Nil && class->info & OBJC_CLASS_INFO_SETUP) { objc_updateDTable(class); objc_updateDTable(class->isa); } } void objc_registerAllCategories(struct objc_symtab *symtab) { struct objc_category **categories = (struct objc_category **)symtab->defs + symtab->classDefsCount; for (size_t i = 0; i < symtab->categoryDefsCount; i++) { registerSelectors(categories[i]); registerCategory(categories[i]); } } struct objc_category ** objc_categoriesForClass(Class class) { if (categoriesMap == NULL) return NULL; return (struct objc_category **)objc_hashtable_get(categoriesMap, class->name); } void objc_unregisterAllCategories(void) { if (categoriesMap == NULL) return; for (uint32_t i = 0; i < categoriesMap->size; i++) if (categoriesMap->data[i] != NULL) free((void *)categoriesMap->data[i]->object); objc_hashtable_free(categoriesMap); categoriesMap = NULL; }