Ada Programming/Interfacing
Interfacing
[edit | edit source]Ada is one of the few languages where interfacing is part of the language standard. The programmer can interface with other programming languages, or with the hardware.
Other programming languages
[edit | edit source]The language standard defines the interfaces for C, Cobol and Fortran. Of course any implementation might define further interfaces — GNAT for example defines an interface to C++.
Interfacing with other languages is actually provided by pragma Export, Import and Convention.
Interfacing with C
[edit | edit source]The package Interfaces.C is used to define C types. C function wrappers should be used to encapsulate types and functions on the C side. This way the code is portable and forward-compatible. This is similar to the way of interfacing with C in Java's JNI. Wrappers should be used for:
- Translating typedefs defined in C includes to types defined in Interfaces.C;
- Using macros and exposing macro values to the Ada side;
- Using variable parameter list functions;
- Defining multiple function wrappers for a function that takes weakly typed parameters such as a function that takes a char_array or a null pointer;
- Using getters and setters for C structs that depend on operating system version or other compile-type aspect;
- Using pointer arithmetic;
- Keeping Ada source memory-safe.
Example
[edit | edit source]with
Interfaces.C;with
System;with
Ada.Text_IO;procedure
Mainis
procedure
W32_Open_File_Dialogis
package
Crenames
Interfaces.C;use
C;type
OPENFILENAMEis
new
System.Address;type
Window_Typeis
new
System.Address;function
GetOpenFileName (p : OPENFILENAME)return
C.int;pragma
Import (C, GetOpenFileName, "ada_getopenfilename");function
Allocatereturn
OPENFILENAMEwith
Import => True, Convention => C, External_Name => "ofn_allocate";procedure
Set_Struct_Size (X : OPENFILENAME)with
Import => True, Convention => C, External_Name => "ofn_set_struct_size";procedure
Set_Owner (X : OPENFILENAME; Owner : Window_Type)with
Import => True, Convention => C, External_Name => "ofn_set_owner";procedure
Set_File (X : OPENFILENAME; File : char_array; Length : C.int)with
Import => True, Convention => C, External_Name => "ofn_set_file";procedure
Set_Filter (X : OPENFILENAME; Filter : char_array);pragma
Import (C, Set_Filter, "ofn_set_filter");procedure
Set_Filter_Index (X : OPENFILENAME; N : C.int)with
Import => True, Convention => C, External_Name => "ofn_set_filter_index";function
Get_File (X : OPENFILENAME)return
System.Address;pragma
Import (C, Get_File, "ofn_get_file");function
Get_File_Length (X : OPENFILENAME)return
C.size_t;pragma
Import (C, Get_File_Length, "ofn_get_file_length");procedure
Free (X : OPENFILENAME)with
Import => True, Convention => C, External_Name => "ofn_free"; OFN : OPENFILENAME; Ret : C.int; File :aliased
C.char_array := "test.txt" & C.nul; Filter :aliased
C.char_array := "All" & C.nul & "*.*" & C.nul & C.nul & C.nul;begin
OFN := Allocate; Set_Struct_Size (OFN); Set_Owner (OFN, Window_Type (System.Null_Address)); Set_File (OFN, File, 256); Set_Filter (OFN, Filter); Set_Filter_Index (OFN, 0); Ret := GetOpenFileName (OFN);if
Ret = 0then
Free (OFN); Ada.Text_IO.Put_Line ("No file selected."); return;end
if
;declare
Selected_File_Address : System.Address := Get_File (OFN); Selected_File_Length : C.size_t := Get_File_Length (OFN); Selected_File : char_array (1 .. Selected_File_Length + 1);for
Selected_File'Addressuse
Selected_File_Address;begin
Ada.Text_IO.Put_Line (To_Ada (Selected_File, Trim_Nul => True));end
; Free (OFN);end
W32_Open_File_Dialog;begin
W32_Open_File_Dialog;end
Main;
#include <windows.h>
#include <stdlib.h>
OPENFILENAME *ofn_allocate()
{
OPENFILENAME *ofn;
ofn = (OPENFILENAME *) malloc(sizeof(OPENFILENAME));
if (ofn == NULL)
return NULL;
memset(ofn, 0, sizeof(OPENFILENAME));
return ofn;
}
void ofn_set_struct_size(OPENFILENAME *ofn)
{
ofn->lStructSize = sizeof(OPENFILENAME);
}
void ofn_set_owner(OPENFILENAME *ofn, void *owner)
{
ofn->hwndOwner = (HWND) owner;
}
void ofn_set_file(OPENFILENAME *ofn, char *file, int length)
{
if (ofn->lpstrFile)
free(ofn->lpstrFile);
ofn->lpstrFile = (char *)malloc (length);
if (ofn->lpstrFile == NULL) {
ofn->nMaxFile = 0;
return;
}
strncpy(ofn->lpstrFile, file, length);
ofn->nMaxFile = length;
}
void ofn_set_filter(OPENFILENAME *ofn, char *filter)
{
ofn->lpstrFilter = filter;
}
void ofn_set_filter_index(OPENFILENAME *ofn, int n)
{
ofn->nFilterIndex = n;
}
void ofn_free(OPENFILENAME *ofn)
{
if (ofn->lpstrFile)
free(ofn->lpstrFile);
free(ofn);
}
int ada_getopenfilename(OPENFILENAME *ofn)
{
return (int) GetOpenFileNameA(ofn);
}
char *ofn_get_file(OPENFILENAME *ofn)
{
return ofn->lpstrFile;
}
size_t ofn_get_file_length(OPENFILENAME *ofn)
{
return (size_t) lstrlen (ofn->lpstrFile);
}
The following project file (getopenfilename.gpr) shows how to link to comdlg32.dll:
project Getopenfilename is for Languages use ("Ada", "C"); for Source_Dirs use ("src"); for Object_Dir use "obj"; for Main use ("main.adb"); package Linker is for Default_Switches ("ada") use ("-lComdlg32"); end Linker; end Getopenfilename;
Hardware devices
[edit | edit source]Embedded programmers usually have to write device drivers. Ada provides extensive support for interfacing with hardware, like using representation clauses to specify the exact representation of types used by the hardware, or standard interrupt handling for writing Interrupt service routines.