comp.lang.ada
 help / color / mirror / Atom feed
* differences between Ada and C in gnat forcing me to use C instead of Ada
@ 2019-03-25  5:46 matthewbrentmccarty
  2019-03-25  5:58 ` Jere
                   ` (5 more replies)
  0 siblings, 6 replies; 14+ messages in thread
From: matthewbrentmccarty @ 2019-03-25  5:46 UTC (permalink / raw)


Hi all:

I really want to use Ada.  But gnat is forcing me to use C.  Basically, I wanted to interface with my scanner using SANE (Scanner Access Now Easy).  Using my "real" Debian machine since gnat doesn't work under Windows 10 (Debian subsystem for Linux), I created the ada specs from the C headers and the sizes in C and Ada are different.  For example:

In C, this code:
printf("sizeof(char *)=%d\n", sizeof(char *));

prints "sizeof(char *)=8"


and this code:
printf("sizeof(SANE_Device)=%d\n", sizeof(SANE_Device));

prints "sizeof(SANE_Device)=32".  In C, the header defines it this way:

typedef char SANE_Char;
typedef const SANE_Char *SANE_String_Const;

typedef struct
  {
    SANE_String_Const name;	/* unique device name */
    SANE_String_Const vendor;	/* device vendor string */
    SANE_String_Const model;	/* device model name */
    SANE_String_Const type;	/* device type (e.g., "flatbed scanner") */
  }
SANE_Device;

which makes sense to me since 8*4 = 32 (sizeof(char *) * 4 elements in the record.  But on the Ada side, I get the following code:

Text_Io.Put_Line ("sane_sane_h.SANE_Device'Size=>" & 
    Integer'Image (sane_sane_h.SANE_Device'Size));

to print "sane_sane_h.SANE_Device'Size=> 256"

And sure enough "Integer'Image (InterfaceS.C.Strings.chars_ptr'Size))" prints out 64.  Now, how can we interface to a C library passing around the 'Address of an array of pointers to records if the elements in the record are different sizes.  No wonder, I get back garbage when calling sane_get_devices. How is it that "sizeof(char *) is 8 in C and InterfaceS.C.Strings.chars_ptr'Size is 64 in Ada.  When I try to rep spec it, I get

   --size for "SANE_String_Const" too small, minimum allowed is 64
   --
   --for SANE_String_Const'Size use 8;

and

--for SANE_Device'Size use 32;                                     
-- causes compiler error "size for "SANE_Device" too small, minimum allowed is 256 
--       for SANE_Device use record
--          name at 0 range 0 .. 7;
--          vendor at 1 range 0 .. 7;
--          model at 2 range 0 .. 7;
--          c_type at 3 range 0 .. 7;
--       end record;

And sure enough Standard'Address_Size is  64.  Sorry to be so long winded. I guess I'll write C code.  Arggggh!

Regards,
Matthew McCarty

PS: Here are the steps.

So, I installed the development libraries using:

%apt-get install sane sane-utils libsane-extras xsane

which gave me

/usr/include/sane/sane.h


I then ran

%g++ -c -fdump-ada-spec -C /usr/include/sane/sane.h

which includes the following types and record:


with Interfaces.C; use Interfaces.C;
...
...
subtype SANE_Char is char;  -- /usr/include/sane/sane.h:46
...
type SANE_String is access all SANE_Char;  -- /usr/include/sane/sane.h:47
...
-- unique device name  
type SANE_Device is record
   name : SANE_String_Const;  -- /usr/include/sane/sane.h:104
   vendor : SANE_String_Const;  -- /usr/include/sane/sane.h:105
   model : SANE_String_Const;  -- /usr/include/sane/sane.h:106
   c_type : SANE_String_Const;  -- /usr/include/sane/sane.h:107
end record;
pragma Convention (C_Pass_By_Copy, SANE_Device);  -- /usr/include/sane/sane.h:109

function sane_get_devices (device_list : System.Address; local_only : SANE_Bool) return SANE_Status;  -- /usr/include/sane/sane.h:221
pragma Import (C, sane_get_devices, "sane_get_devices");

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: differences between Ada and C in gnat forcing me to use C instead of Ada
  2019-03-25  5:46 differences between Ada and C in gnat forcing me to use C instead of Ada matthewbrentmccarty
@ 2019-03-25  5:58 ` Jere
  2019-03-25  8:25 ` Dmitry A. Kazakov
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 14+ messages in thread
From: Jere @ 2019-03-25  5:58 UTC (permalink / raw)


On Monday, March 25, 2019 at 1:46:07 AM UTC-4, matthewbr...@gmail.com wrote:
> Hi all:
> 
> I really want to use Ada.  But gnat is forcing me to use C.  Basically, I wanted to interface with my scanner using SANE (Scanner Access Now Easy).  Using my "real" Debian machine since gnat doesn't work under Windows 10 (Debian subsystem for Linux), I created the ada specs from the C headers and the sizes in C and Ada are different.  For example:
> 
> In C, this code:
> printf("sizeof(char *)=%d\n", sizeof(char *));
> 
> prints "sizeof(char *)=8"
> 
> 
> and this code:
> printf("sizeof(SANE_Device)=%d\n", sizeof(SANE_Device));
> 
> prints "sizeof(SANE_Device)=32".  In C, the header defines it this way:
> 
> typedef char SANE_Char;
> typedef const SANE_Char *SANE_String_Const;
> 
> typedef struct
>   {
>     SANE_String_Const name;	/* unique device name */
>     SANE_String_Const vendor;	/* device vendor string */
>     SANE_String_Const model;	/* device model name */
>     SANE_String_Const type;	/* device type (e.g., "flatbed scanner") */
>   }
> SANE_Device;
> 
> which makes sense to me since 8*4 = 32 (sizeof(char *) * 4 elements in the record.  But on the Ada side, I get the following code:
> 
> Text_Io.Put_Line ("sane_sane_h.SANE_Device'Size=>" & 
>     Integer'Image (sane_sane_h.SANE_Device'Size));
> 
> to print "sane_sane_h.SANE_Device'Size=> 256"
> 
> And sure enough "Integer'Image (InterfaceS.C.Strings.chars_ptr'Size))" prints out 64.  Now, how can we interface to a C library passing around the 'Address of an array of pointers to records if the elements in the record are different sizes.  No wonder, I get back garbage when calling sane_get_devices. How is it that "sizeof(char *) is 8 in C and InterfaceS.C.Strings.chars_ptr'Size is 64 in Ada.  When I try to rep spec it, I get

So when you do sizeof() in C it returns the number of bytes. When
you do 'Size in Ada, it gives the number of bits.  8bits * 8bytes
is 64 bits, so everything looks correct. They are returning the same
effective size in both C and Ada.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: differences between Ada and C in gnat forcing me to use C instead of Ada
  2019-03-25  5:46 differences between Ada and C in gnat forcing me to use C instead of Ada matthewbrentmccarty
  2019-03-25  5:58 ` Jere
@ 2019-03-25  8:25 ` Dmitry A. Kazakov
  2019-03-25 14:06   ` Florian Weimer
  2019-03-25 10:56 ` Philip Munts
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 14+ messages in thread
From: Dmitry A. Kazakov @ 2019-03-25  8:25 UTC (permalink / raw)


On 2019-03-25 06:46, matthewbrentmccarty@gmail.com wrote:

> Basically, I wanted to interface with my scanner using SANE (Scanner Access Now Easy).  Using my "real" Debian machine since gnat doesn't work under Windows 10 (Debian subsystem for Linux),

No idea what you mean under "subsystem", but GNAT works under Windows 
virtual machine.

> with Interfaces.C; use Interfaces.C;
> ...
> ...
> subtype SANE_Char is char;  -- /usr/include/sane/sane.h:46
> ...
> type SANE_String is access all SANE_Char;  -- /usr/include/sane/sane.h:47
> ...
> -- unique device name
> type SANE_Device is record
>     name : SANE_String_Const;  -- /usr/include/sane/sane.h:104
>     vendor : SANE_String_Const;  -- /usr/include/sane/sane.h:105
>     model : SANE_String_Const;  -- /usr/include/sane/sane.h:106
>     c_type : SANE_String_Const;  -- /usr/include/sane/sane.h:107
> end record;
> pragma Convention (C_Pass_By_Copy, SANE_Device);  -- /usr/include/sane/sane.h:109

    type SANE_Device is record
      name   : chars_ptr;
      vendor : chars_ptr;
      model  : chars_ptr;
      c_type : chars_ptr;
    end record;
    pragma Convention (C, SANE_Device);

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: differences between Ada and C in gnat forcing me to use C instead of Ada
  2019-03-25  5:46 differences between Ada and C in gnat forcing me to use C instead of Ada matthewbrentmccarty
  2019-03-25  5:58 ` Jere
  2019-03-25  8:25 ` Dmitry A. Kazakov
@ 2019-03-25 10:56 ` Philip Munts
  2019-03-25 11:54 ` Lucretia
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 14+ messages in thread
From: Philip Munts @ 2019-03-25 10:56 UTC (permalink / raw)


GNAT Community 2018 most certainly does work in Debian for Windows.  I use it almost every day.  What is difficult is *installing* it with the latest GUI installer.  I would up installing it one time on a real Linux machine and creating a Debian package file from said installation.  The package file is available at my custom Debian package repository http://repo.munts.com/debian9/.

The Debian native GNAT toolchain also works fine, as do cross-compilers for MuntsOS Embedded Linux (https://github.com/pmunts/muntsos).

I have a twisted mind:  I generally run Debian for Windows in a Windows 10 virtual machine running on either Debian Linux or MacOS.  It works amazingly well that way...

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: differences between Ada and C in gnat forcing me to use C instead of Ada
  2019-03-25  5:46 differences between Ada and C in gnat forcing me to use C instead of Ada matthewbrentmccarty
                   ` (2 preceding siblings ...)
  2019-03-25 10:56 ` Philip Munts
@ 2019-03-25 11:54 ` Lucretia
  2019-03-25 14:09 ` matthewbrentmccarty
  2019-03-25 16:42 ` matthewbrentmccarty
  5 siblings, 0 replies; 14+ messages in thread
From: Lucretia @ 2019-03-25 11:54 UTC (permalink / raw)


On Monday, 25 March 2019 05:46:07 UTC, matthewbr...@gmail.com  wrote:
> Hi all:
> 
> I really want to use Ada.  But gnat is forcing me to use C.  Basically, I 

Tried MingW64 under Windows?

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: differences between Ada and C in gnat forcing me to use C instead of Ada
  2019-03-25  8:25 ` Dmitry A. Kazakov
@ 2019-03-25 14:06   ` Florian Weimer
  0 siblings, 0 replies; 14+ messages in thread
From: Florian Weimer @ 2019-03-25 14:06 UTC (permalink / raw)


* Dmitry A. Kazakov:

> On 2019-03-25 06:46, matthewbrentmccarty@gmail.com wrote:
>
>> Basically, I wanted to interface with my scanner using SANE (Scanner
>> Access Now Easy).  Using my "real" Debian machine since gnat doesn't
>> work under Windows 10 (Debian subsystem for Linux),
>
> No idea what you mean under "subsystem", but GNAT works under Windows 
> virtual machine.

This probably refers to the Windows Subsystem for Linux, a fairly
rough approximation of the Linux kernel interface without a real Linux
kernel underneath.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: differences between Ada and C in gnat forcing me to use C instead of Ada
  2019-03-25  5:46 differences between Ada and C in gnat forcing me to use C instead of Ada matthewbrentmccarty
                   ` (3 preceding siblings ...)
  2019-03-25 11:54 ` Lucretia
@ 2019-03-25 14:09 ` matthewbrentmccarty
  2019-03-25 14:20   ` Dmitry A. Kazakov
  2019-03-25 17:38   ` Niklas Holsti
  2019-03-25 16:42 ` matthewbrentmccarty
  5 siblings, 2 replies; 14+ messages in thread
From: matthewbrentmccarty @ 2019-03-25 14:09 UTC (permalink / raw)


Hi all:
"gnat-gps" on my machine Windows 10 (debian subsystem for Linux) (see https://docs.microsoft.com/en-us/windows/wsl/install-win10 ) gives me "raised STORAGE_ERROR : s-intman.adb:139 explicit raise" yet the same software works fine on my "real" debian machine. The compiler works but gant-gps doesn't. 


For some reason when I call sane_get_devices as in:

      type Sane_Device_Ptr is access all sane_sane_h.SANE_Device;
      for Sane_Device_Ptr'Size use Standard'Address_Size;
      pragma Convention (C, Sane_Device_Ptr);

      type Device_Array is array (Integer range <>) of aliased Sane_Device_Ptr;
      pragma Convention (C, Device_Array);
      ...
      devices :  aliased  Device_Array (1..5);
      Status := sane_sane_h.sane_get_devices (devices(1)'Address, sane_sane_h.SANE_Bool(SANE_TRUE));

I get back garbage but in C, it works. Oh, now that makes sense about 'Size returning bits and sizeof in C returning bytes. 256 bits is indeed 32 bytes. I wonder why I'm getting back garbage. InterfaceS.C.Strings.chars_ptr'Size=64 and sizeof(char *)=8 are equivalent.

Thanks. I guess I got some more digging to do as to my garbage.

Regards,
Matthew McCarty


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: differences between Ada and C in gnat forcing me to use C instead of Ada
  2019-03-25 14:09 ` matthewbrentmccarty
@ 2019-03-25 14:20   ` Dmitry A. Kazakov
  2019-03-25 16:46     ` Jeffrey R. Carter
  2019-03-25 17:38   ` Niklas Holsti
  1 sibling, 1 reply; 14+ messages in thread
From: Dmitry A. Kazakov @ 2019-03-25 14:20 UTC (permalink / raw)


On 2019-03-25 15:09, matthewbrentmccarty@gmail.com wrote:

>        devices :  aliased  Device_Array (1..5);
>        Status := sane_sane_h.sane_get_devices (devices(1)'Address, sane_sane_h.SANE_Bool(SANE_TRUE));

How the callee should know the length of the output array?

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: differences between Ada and C in gnat forcing me to use C instead of Ada
  2019-03-25  5:46 differences between Ada and C in gnat forcing me to use C instead of Ada matthewbrentmccarty
                   ` (4 preceding siblings ...)
  2019-03-25 14:09 ` matthewbrentmccarty
@ 2019-03-25 16:42 ` matthewbrentmccarty
  2019-03-25 18:18   ` Dmitry A. Kazakov
  5 siblings, 1 reply; 14+ messages in thread
From: matthewbrentmccarty @ 2019-03-25 16:42 UTC (permalink / raw)


Hi all:

I don't know.  I chose 5 elements in the array since I only have 1 scanner attached to my system.  I wasn't sure how to make it null terminated. I tried:

nul_sane_device_ptr : constant Sane_Device_Ptr := null;
devices :  aliased  Device_Array (1..5) := (others => nul_sane_device_ptr );


In my C example which works, I have a header that says:

#define NELEMS(x)  (sizeof(x) / sizeof((x)[0]))
void sane_print_devices (const SANE_Device ** device_list);


and then C code which does the following:

const SANE_Device	**device_list;

status = sane_get_devices (&device_list, SANE_TRUE);
sane_print_devices (device_list);

I thought &device_list was the same as "devices(1)'Address" in Ada.

Regards,
Matthew McCarty

PS:

There's a html file at http://www.sane-project.org/html/doc012.html that says:

4.3.3 sane_get_devices

This function can be used to query the list of devices that are available. If the function executes successfully, it stores a pointer to a NULL terminated array of pointers to SANE_Device structures in *device_list. The returned list is guaranteed to remain unchanged and valid until (a) another call to this function is performed or (b) a call to sane_exit() is performed. This function can be called repeatedly to detect when new devices become available. If argument local_only is true, only local devices are returned (devices directly attached to the machine that SANE is running on). If it is false, the device list includes all remote devices that are accessible to the SANE library.

    SANE_Status sane_get_devices (const SANE_Device *** device_list,
                                  SANE_Bool local_only);

This function may fail with SANE_STATUS_NO_MEM if an insufficient amount of memory is available.

    Backend Implementation Note
    SANE does not require that this function is called before a sane_open() call is performed. A device name may be specified explicitly by a user which would make it unnecessary and undesirable to call this function first. 


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: differences between Ada and C in gnat forcing me to use C instead of Ada
  2019-03-25 14:20   ` Dmitry A. Kazakov
@ 2019-03-25 16:46     ` Jeffrey R. Carter
  2019-03-25 18:01       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 14+ messages in thread
From: Jeffrey R. Carter @ 2019-03-25 16:46 UTC (permalink / raw)


On 3/25/19 3:20 PM, Dmitry A. Kazakov wrote:
> On 2019-03-25 15:09, matthewbrentmccarty@gmail.com wrote:
> 
>>        devices :  aliased  Device_Array (1..5);
>>        Status := sane_sane_h.sane_get_devices (devices(1)'Address, 
>> sane_sane_h.SANE_Bool(SANE_TRUE));
> 
> How the callee should know the length of the output array?

The same strcpy does.

-- 
Jeff Carter
It's better to be root than to reboot.
119

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: differences between Ada and C in gnat forcing me to use C instead of Ada
  2019-03-25 14:09 ` matthewbrentmccarty
  2019-03-25 14:20   ` Dmitry A. Kazakov
@ 2019-03-25 17:38   ` Niklas Holsti
  1 sibling, 0 replies; 14+ messages in thread
From: Niklas Holsti @ 2019-03-25 17:38 UTC (permalink / raw)


On 19-03-25 16:09 , matthewbrentmccarty@gmail.com wrote:
> Hi all:
    ...
> For some reason when I call sane_get_devices as in:
>
>       type Sane_Device_Ptr is access all sane_sane_h.SANE_Device;
>       for Sane_Device_Ptr'Size use Standard'Address_Size;
>       pragma Convention (C, Sane_Device_Ptr);
>
>       type Device_Array is array (Integer range <>) of aliased Sane_Device_Ptr;
>       pragma Convention (C, Device_Array);
>       ...
>       devices :  aliased  Device_Array (1..5);
>       Status := sane_sane_h.sane_get_devices (devices(1)'Address, sane_sane_h.SANE_Bool(SANE_TRUE));

I think the Ada profile of sane_get_devices, above, is wrong. See below.

> I get back garbage but in C, it works.

Later, on 19-03-25 18:42 , matthewbrentmccarty@gmail.com wrote:
 > Hi all:
    ...
 > In my C example which works, I have a header that says:
 >
 > #define NELEMS(x)  (sizeof(x) / sizeof((x)[0]))
 > void sane_print_devices (const SANE_Device ** device_list);
 >
 >
 > and then C code which does the following:
 >
 > const SANE_Device	**device_list;
 >
 > status = sane_get_devices (&device_list, SANE_TRUE);

which agrees with the profile for sane_get_devices quoted later in that 
message:

 >     SANE_Status sane_get_devices (const SANE_Device *** device_list,
 >                                   SANE_Bool local_only);

In that profile, the device_list parameter is a pointer to a pointer to 
a pointer to a device_list (three *'s). The Ada code has only two 
pointer levels, so a conflict.

 From the description of sane_get_devices, also quoted in that message:

 > If the function executes successfully, it stores a pointer to
 > a NULL terminated array of pointers to SANE_Device structures
 > in *device_list.

This shows that the device_list is logically an "out" parameter, that 
the value returned is a pointer to an array of pointers to device 
records, and that the responsibility for allocating the array  of 
pointers to the device records (as well as the device records 
themselves) lies with the SANE library, not with the client.

This also answers Dmitry's question on how the client knows the number 
of devices returned: the array (to which a pointer is returned) has a 
null pointer at its end.

The Ada code should be something like this (not compiled nor tested, 
with representations omitted):

    type Sane_Device_Ptr is access all sane_sane_h.SANE_Device;

    type Device_Array is array (Integer range 1 .. 500)
       of aliased Sane_Device_Ptr;
    -- Constrained so as to avoid any problems with bounds dope.
    -- The actual array constructed in sane_get_devices may be shorter
    -- or longer.
    -- If there are less than 500 devices, the actual array ends with
    -- a null pointer at some index <= 500.
    -- If there are over 500 devices, the terminating null pointer will
    -- not be present.

    type Device_Array_Ptr is access all Device_Array;
    ...
    devices :  Device_Array_Ptr;

    Status := sane_sane_h.sane_get_devices (
       device_list => Device_Array_Ptr,
       local_only  => sane_sane_h.SANE_Bool(SANE_TRUE));

Here I have assumed that the device_list parameter is declared in the 
Ada profile of sane_get_devices as "out Device_Array_Ptr", which (with 
the C convention) provides pass by reference (and gives the third level 
of pointers).

HTH...

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
       .      @       .


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: differences between Ada and C in gnat forcing me to use C instead of Ada
  2019-03-25 16:46     ` Jeffrey R. Carter
@ 2019-03-25 18:01       ` Dmitry A. Kazakov
  0 siblings, 0 replies; 14+ messages in thread
From: Dmitry A. Kazakov @ 2019-03-25 18:01 UTC (permalink / raw)


On 2019-03-25 17:46, Jeffrey R. Carter wrote:
> On 3/25/19 3:20 PM, Dmitry A. Kazakov wrote:
>> On 2019-03-25 15:09, matthewbrentmccarty@gmail.com wrote:
>>
>>>        devices :  aliased  Device_Array (1..5);
>>>        Status := sane_sane_h.sane_get_devices (devices(1)'Address, 
>>> sane_sane_h.SANE_Bool(SANE_TRUE));
>>
>> How the callee should know the length of the output array?
> 
> The same strcpy does.

strcpy knows nothing about the output. That is why strncpy to be used 
instead.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: differences between Ada and C in gnat forcing me to use C instead of Ada
  2019-03-25 16:42 ` matthewbrentmccarty
@ 2019-03-25 18:18   ` Dmitry A. Kazakov
  2019-04-04  0:51     ` matthewbrentmccarty
  0 siblings, 1 reply; 14+ messages in thread
From: Dmitry A. Kazakov @ 2019-03-25 18:18 UTC (permalink / raw)


On 2019-03-25 17:42, matthewbrentmccarty@gmail.com wrote:

> This function can be used to query the list of devices that are available. If the function executes successfully, it stores a pointer to a NULL terminated array of pointers to SANE_Device structures in *device_list. The returned list is guaranteed to remain unchanged and valid until (a) another call to this function is performed or (b) a call to sane_exit() is performed. This function can be called repeatedly to detect when new devices become available. If argument local_only is true, only local devices are returned (devices directly attached to the machine that SANE is running on). If it is false, the device list includes all remote devices that are accessible to the SANE library.
> 
>      SANE_Status sane_get_devices (const SANE_Device *** device_list,
>                                    SANE_Bool local_only);
> 
> This function may fail with SANE_STATUS_NO_MEM if an insufficient amount of memory is available.
> 
>      Backend Implementation Note
>      SANE does not require that this function is called before a sane_open() call is performed. A device name may be specified explicitly by a user which would make it unnecessary and undesirable to call this function first.

    type SANE_Device is record
      name   : chars_ptr;
      vendor : chars_ptr;
      model  : chars_ptr;
      c_type : chars_ptr;
    end record;
    pragma Convention (C, SANE_Device);
    type SANE_Device_Ptr is access all SANE_Device;
    pragma Convention (C, SANE_Device_Ptr);

       -- Flat array of devices
    type SANE_Device_Array is array (size_t) of SANE_Device_Ptr;
    pragma Convention (C, SANE_Device_Array);
    type SANE_Device_Array_Ptr is access all SANE_Device_Array;
    pragma Convention (C, SANE_Device_Array_Ptr);

    function SANE_get_devices
             (  device_list : not null access SANE_Device_Array_Ptr;
                local_only  : SANE_Bool
             )  return SANE_Status;
    pragma Import (C, SANE_get_devices);
---------------------------------

    List_Ptr : SANE_Device_Array_Ptr;
begin
    SANE_get_devices (List, 0);
    declare
       List : SANE_Device_Array renames List.all;
    begin
       for Index in List'Range loop      -- "Infinite" loop
          exit when List (Index) = null; -- Null-terminated
          Put_Line ("Device: " Value (List (Index).name);
       end loop;
    end;
end;

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: differences between Ada and C in gnat forcing me to use C instead of Ada
  2019-03-25 18:18   ` Dmitry A. Kazakov
@ 2019-04-04  0:51     ` matthewbrentmccarty
  0 siblings, 0 replies; 14+ messages in thread
From: matthewbrentmccarty @ 2019-04-04  0:51 UTC (permalink / raw)


Hi all:

OK!  I was looking at this again with fresh eyes and with a little tweaking, I got Dmitry's example working with the following code:



with Text_Io; use Text_io;
with Interfaces.C; use Interfaces.C;
with Interfaces.C.Strings; use Interfaces.C.Strings;

procedure foo3 is

   subtype SANE_Word is int;  -- /usr/include/sane/sane.h:43
   subtype SANE_Bool is SANE_Word;  -- /usr/include/sane/sane.h:44

   type SANE_Status is
     (SANE_STATUS_GOOD,
      SANE_STATUS_UNSUPPORTED,
      SANE_STATUS_CANCELLED,
      SANE_STATUS_DEVICE_BUSY,
      SANE_STATUS_INVAL,
      SANE_STATUS_EOF,
      SANE_STATUS_JAMMED,
      SANE_STATUS_NO_DOCS,
      SANE_STATUS_COVER_OPEN,
      SANE_STATUS_IO_ERROR,
      SANE_STATUS_NO_MEM,
      SANE_STATUS_ACCESS_DENIED);
   pragma Convention (C, SANE_Status);  -- /usr/include/sane/sane.h:71

   subtype SANE_Char is char;  -- /usr/include/sane/sane.h:46
   subtype SANE_Int is SANE_Word;  -- /usr/include/sane/sane.h:45
   type SANE_String_Const is access all SANE_Char;  -- /usr/include/sane/sane.h:48

   type SANE_Auth_Callback is access procedure
        (arg1 : SANE_String_Const;
         arg2 : access SANE_Char;
         arg3 : access SANE_Char);
   pragma Convention (C, SANE_Auth_Callback);  -- /usr/include/sane/sane.h:214

    type SANE_Device is record
      name   : chars_ptr;
      vendor : chars_ptr;
      model  : chars_ptr;
      c_type : chars_ptr;
    end record;
    pragma Convention (C, SANE_Device);
    type SANE_Device_Ptr is access all SANE_Device;
    pragma Convention (C, SANE_Device_Ptr);

       -- Flat array of devices
    type SANE_Device_Array is array (size_t) of SANE_Device_Ptr;
    pragma Convention (C, SANE_Device_Array);
    type SANE_Device_Array_Ptr is access all SANE_Device_Array;
    pragma Convention (C, SANE_Device_Array_Ptr);

    function sane_get_devices
             (  device_list :  in out  SANE_Device_Array_Ptr;
                local_only  : SANE_Bool
             )  return SANE_Status;
   pragma Import (C, sane_get_devices, "sane_get_devices");

   function sane_init (version_code : access SANE_Int; authorize : SANE_Auth_Callback) return SANE_Status;  -- /usr/include/sane/sane.h:218
   pragma Import (C, sane_init, "sane_init");

   procedure sane_exit;  -- /usr/include/sane/sane.h:220
   pragma Import (C, sane_exit, "sane_exit");

---------------------------------

   List_Ptr : SANE_Device_Array_Ptr;
   stat : SANE_Status := SANE_STATUS_GOOD;
   version_code : access SANE_Int :=  new SANE_Int;


begin
    stat := sane_init(version_code, null);

    stat := sane_get_devices (List_Ptr, 0);
    declare
       List : SANE_Device_Array renames List_Ptr.all;
    begin
       for Index in List'Range loop      -- "Infinite" loop
          exit when List (Index) = null; -- Null-terminated
         Text_Io.Put_Line ("Name: " & Value (List (Index).name));
         Text_Io.Put_Line ("Vendor: " & Value (List (Index).vendor));
         Text_Io.Put_Line ("Model: " & Value (List (Index).model));
         Text_Io.Put_Line ("C_Type: " & Value (List (Index).c_type));
         
       end loop;
   end;

   sane_exit;
end Foo3;


Now, if I knew that it was possible to interface to C using "sane_get_devices" with a parameter of "device_list :  in out  SANE_Device_Array_Ptr;" instead of the generated "System.Address" parameter, then I would have been delighted to use that method instead of the generated version from "%g++ -c -fdump-ada-spec-slim".  For some reason, I thought the generated version was more accurate.  But I much rather use the SANE_Device_Array_Ptr version since it more accurately matches the documented API calls as explained in the manual.  I had to remove the "not null" on the parameter since it was causing "raised CONSTRAINT_ERROR : foo3.adb:74 access check failed" and it is null when you first call it.  And I still get garbage when passing the 'Address of the first element of my array in my version of the code.  Thanks for the assistance!

Regards,
Matthew McCarty

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2019-04-04  0:51 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-25  5:46 differences between Ada and C in gnat forcing me to use C instead of Ada matthewbrentmccarty
2019-03-25  5:58 ` Jere
2019-03-25  8:25 ` Dmitry A. Kazakov
2019-03-25 14:06   ` Florian Weimer
2019-03-25 10:56 ` Philip Munts
2019-03-25 11:54 ` Lucretia
2019-03-25 14:09 ` matthewbrentmccarty
2019-03-25 14:20   ` Dmitry A. Kazakov
2019-03-25 16:46     ` Jeffrey R. Carter
2019-03-25 18:01       ` Dmitry A. Kazakov
2019-03-25 17:38   ` Niklas Holsti
2019-03-25 16:42 ` matthewbrentmccarty
2019-03-25 18:18   ` Dmitry A. Kazakov
2019-04-04  0:51     ` matthewbrentmccarty

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox