class EL_DYNAMIC_MODULE_POINTERS

(source code)

description

Dynamic module API function pointers. This class automates the process of assigning shared object (DLL) API function pointers to pointer attributes.

instructions

To use this class, define a descendant and define a pointer attribute for each API function. The attibute must be named to match the API name with any common prefix stripped from the beginning. A common prefix is defined by creating a descendant of EL_DYNAMIC_MODULE and defining a value for name_prefix. The name of the C function will be automatically inferred from the attribute names

In the make routine these pointer attributes will be automatically initialized, by inferring the C function names from the attribute names using object reflection.

Reserved Words

If the C function name happens to coincide with an Eiffel reserved word, create for example, the attribute name can be tweaked with addition of an underscore, create_ in this example. This will resolve any compilation problems. The C function name will still be correctly inferred.

Upper case letters

Any C function names that happen to contain uppercase characters, must be explicitly listed by redefining the array function function_names_with_upper. This is because Eiffel identifers are case-insensitive and the object reflection always returns the name in lowercase.

note
	description: "[
		Dynamic module API function pointers.		
		This class automates the process of assigning shared object (DLL) API function pointers to
		pointer attributes.
	]"
	instructions: "[
		To use this class, define a descendant and define a pointer attribute for each API function.
		The attibute must be named to match the API name with any common prefix stripped from the beginning.
		A common prefix is defined by creating a descendant of ${EL_DYNAMIC_MODULE} and defining a value for
		`name_prefix'. The name of the C function will be automatically inferred from the attribute names
		
		In the `make' routine these pointer attributes will be automatically initialized, by inferring the
		C function names from the attribute names using object reflection.
		
		**Reserved Words**
		
		If the C function name happens to coincide with an Eiffel reserved word, `create' for example, the attribute
		name can be tweaked with addition of an underscore, `create_' in this example. This will resolve any compilation
		problems. The C function name will still be correctly inferred.
		
		**Upper case letters**
		
		Any C function names that happen to contain uppercase characters, must be explicitly listed by redefining
		the array function `function_names_with_upper'. This is because Eiffel identifers are case-insensitive and
		the object reflection always returns the name in lowercase.

	]"

	author: "Finnian Reilly"
	copyright: "Copyright (c) 2001-2022 Finnian Reilly"
	contact: "finnian at eiffel hyphen loop dot com"

	license: "MIT license (See: en.wikipedia.org/wiki/MIT_License)"
	date: "2024-01-20 19:18:25 GMT (Saturday 20th January 2024)"
	revision: "18"

class
	EL_DYNAMIC_MODULE_POINTERS

inherit
	EL_REFLECTIVELY_SETTABLE
		rename
			foreign_naming as eiffel_naming
		end

	EL_MODULE_EXCEPTION

create
	make

feature {NONE} -- Initialization

	make (module: EL_DYNAMIC_MODULE [EL_DYNAMIC_MODULE_POINTERS])
		-- Assumes that any pointer fields starting with "pointer_" correspond to an
		-- API function name and that the remainder of the field name is the same as the
		-- API name without the prefix defined by `name_prefix'

		-- since Eiffel identifiers are case insensitive, C API identifiers with upper case characters must be
		-- listed by overriding the function `function_names_with_upper'
		local
			names_with_upper: EL_HASH_TABLE [STRING, STRING]
			name: STRING; function: POINTER
		do
			make_default
			create names_with_upper.make_equal (11)
			across function_names_with_upper as upper_name loop
				names_with_upper [upper_name.item.as_lower] := upper_name.item
			end
			if attached field_table as table then
				from table.start until table.after loop
					name := table.key_for_iteration
					if names_with_upper.has_key (name) then
						name := names_with_upper.found_item
					end
					function := module.function_pointer (name)
					if function = Default_pointer then
						Exception.raise_developer (
							"API initialization error. No such C routine %"%S%S%" in class %S",
							[module.name_prefix, name, generator]
						)
					elseif attached {EL_REFLECTED_POINTER} table.item_for_iteration as pointer_field then
						pointer_field.set (Current, function)
					end
					table.forth
				end
			end
		end

feature {NONE} -- Implementation

	field_included (field: EL_FIELD_TYPE_PROPERTIES): BOOLEAN
		do
			Result := field.is_pointer
		end

	function_names_with_upper: ARRAY [STRING]
		-- List any C API names that contain uppercase characters in descendant
		-- but strip the names of the general prefix defined by `name_prefix'
		do
			create Result.make_empty
		end

end