Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Hexadecimal and stream element arrays

123 views
Skip to first unread message

tonyg

unread,
Apr 19, 2010, 11:44:31 AM4/19/10
to
I have some data coming in from a serial port which I want to convert
to hexadecimal and display on the screen. I was wondering if anyone
knows of a simple way to do this?

tonyg

unread,
Apr 19, 2010, 11:58:16 AM4/19/10
to

To make myself more clear I have already dealt with the serial comms
bit, I am looking to display the stream I have already captured

Ludovic Brenta

unread,
Apr 19, 2010, 12:24:26 PM4/19/10
to
tonyg wrote on comp.lang.ada:

You could use the predefined library to get a result using the Ada
"syntax for based literal" (ARM A.10.8(14)), e.g. 16#CE#.

package Stream_Element_IO is
new Ada.Text_IO.Modular_IO (Num => Ada.Streams.Stream_Element);

E : Ada.Streams.Stream_Element := ...
begin
Stream_Element_IO.Put (Item => E, Base => 16);

(There are variants of Put that send the output to a File_Type or to a
string).

If you want to avoid the 16## part, you can easily convert the
stream_elements to a string representation yourself like so:

function To_Hex (E : in Ada.Streams.Stream_Element) return String is
-- Warning: not compiled and not tested...
X : constant array (0 .. 15) of Character :=
('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
'D', 'E', 'F');
Result : String (1 .. Ada.Streams.Stream_Element'Size / 4); -- 1
hex digits = 4 bits
Working_Copy : Ada.Streams.Stream_Element := E;
use type Ada.Streams.Stream_Element;
First_Character : Natural := 0;
Base : constant := 16;
begin
for K in reverse Result'Length loop
Result (K) := X (Working_Copy mod Base);
Working_Copy := Working_Copy / Base;
if Working_Copy = 0 then
First_Character := K;
exit;
end if;
end loop;
return Result (First_Character .. Result'Last);
end To_Hex;

Hope this helps.

--
Ludovic Brenta.

tonyg

unread,
Apr 19, 2010, 12:27:13 PM4/19/10
to

Thanks Ludovic I'll try that.

tonyg

unread,
Apr 19, 2010, 1:02:12 PM4/19/10
to

I tried the first way and thought I would prefer the hex.
I got an error as the compiler is expecting a second value in the
range.
Second way is definetly the way forward I think , Thanks again for a
very detailed reply, its saved me loads of time :)

John B. Matthews

unread,
Apr 19, 2010, 1:20:44 PM4/19/10
to
In article
<f7e8f2a4-a989-4b74...@z11g2000yqz.googlegroups.com>,
tonyg <tonyt...@googlemail.com> wrote:

Here's one approach that's convenient for command line use:

<http://sites.google.com/site/drjohnbmatthews/hexdump>

--
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>

tonyg

unread,
Apr 19, 2010, 1:26:58 PM4/19/10
to

Changed the hex function to


function To_Hex (E : in Ada.Streams.Stream_Element) return String
is
-- Warning: not compiled and not tested...
X : constant array (0 .. 15) of Character :=
('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
'C', 'D', 'E', 'F');
Result : String (1 .. Ada.Streams.Stream_Element'Size / 4); -- 1
hex digits = 4 bits
Working_Copy : Ada.Streams.Stream_Element := E;
use type Ada.Streams.Stream_Element;
First_Character : Natural := 0;
Base : constant := 16;
begin

for K in reverse Result'First .. Result'Length loop
Result (K) := X (integer(Working_Copy) mod integer (Base) );


Working_Copy := Working_Copy / Base;
if Working_Copy = 0 then
First_Character := K;
exit;
end if;

end loop;
return Result (First_Character .. Result'Last);
end To_Hex;

It still seems to be dropping a few zeros though and I'm stumped where
its going wrong

Dmitry A. Kazakov

unread,
Apr 19, 2010, 1:27:00 PM4/19/10
to

The following is based on:

http://www.dmitry-kazakov.de/ada/strings_edit.htm

with Ada.Streams; use Ada.Streams;
with Strings_Edit; use Strings_Edit;
with Strings_Edit.Integers; use Strings_Edit.Integers;

function Image (Data : Stream_Element_Array) return String is
begin
if Data'Length = 0 then
return "";
end if;
declare
Text : String (1..Data'Length * 3);
Pointer : Integer := 1;
begin
for I in Data'Range loop
Put
( Text, Pointer, Stream_Element'Pos (Data (I)),
Field=>2, Fill=>'0', Justify=>Right, Base=>16
);
Put (Text, Pointer, ' ');
end loop;
return Text (1..Text'Last - 1);
end;
end Image;

An individual item is output

Put
( Text, Pointer, Stream_Element'Pos (Item),
Field=>2, Fill=>'0', Justify=>Right, Base=>16
);

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

tonyg

unread,
Apr 19, 2010, 1:55:56 PM4/19/10
to
On Apr 19, 6:27 pm, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

Thanks Guys, I forgot how helpful these forums were and how many
people out there used Ada, you reminded me, and I got some working
code \o/

Warren

unread,
Apr 19, 2010, 2:05:01 PM4/19/10
to
Ludovic Brenta expounded in
news:2f4313a5-bb3d-4f7f...@k41g2000yqf.googlegroups.com:

..


> You could use the predefined library to get a result using the Ada
> "syntax for based literal" (ARM A.10.8(14)), e.g. 16#CE#.
>
> package Stream_Element_IO is
> new Ada.Text_IO.Modular_IO (Num => Ada.Streams.Stream_Element);
>
> E : Ada.Streams.Stream_Element := ...
> begin
> Stream_Element_IO.Put (Item => E, Base => 16);
>
> (There are variants of Put that send the output to a File_Type or to a

> string)..
> Ludovic Brenta.

I've been interested in finding these ways to "Put" (Hex) to
a string, instead of a File_Type.

But what I've seen is that "Put" always involves a
File_Type (or implies one).

So what have I missed?

Warren

Jeffrey R. Carter

unread,
Apr 19, 2010, 3:21:16 PM4/19/10
to
On Apr 19, 11:05 am, Warren <ve3...@gmail.com> wrote:
>
> I've been interested in finding these ways to "Put" (Hex) to
> a string, instead of a File_Type.
>
> But what I've seen is that "Put" always involves a
> File_Type (or implies one).
>
> So what have I missed?  

From A.10.8 (Input-Output for Integer Types):

15
procedure Get(From : in String; Item : out Num; Last : out Positive);
16
Reads an integer value from the beginning of the given string,
following the same rules as the Get procedure that reads an integer
value from a file, but treating the end of the string as a file
terminator. Returns, in the parameter Item, the value of type Num that
corresponds to the sequence input. Returns in Last the index value
such that From(Last) is the last character read.
17
The exception Data_Error is propagated if the sequence input does not
have the required syntax or if the value obtained is not of the
subtype Num.
18
procedure Put(To : out String;
Item : in Num;
Base : in Number_Base := Default_Base);
19
Outputs the value of the parameter Item to the given string, following
the same rule as for output to a file, using the length of the given
string as the value for Width.

Warren

unread,
Apr 19, 2010, 3:28:12 PM4/19/10
to
Jeffrey R. Carter expounded in news:e5748cb1-0e95-49ff-8616-
6709c6...@q15g2000yqj.googlegroups.com:

> On Apr 19, 11:05�am, Warren <ve3...@gmail.com> wrote:
>>
>> I've been interested in finding these ways to "Put" (Hex) to
>> a string, instead of a File_Type.
>>
>> But what I've seen is that "Put" always involves a
>> File_Type (or implies one).
>>
>> So what have I missed? �
>
> From A.10.8 (Input-Output for Integer Types):

...


> procedure Put(To : out String;
> Item : in Num;
> Base : in Number_Base := Default_Base);
> 19
> Outputs the value of the parameter Item to the given string, following
> the same rule as for output to a file, using the length of the given
> string as the value for Width.

My apologies-- I see it now. I hate these dos names
that gnat uses for the spec file names. I see the
api now.

Now if only I could find where the mayonnaise in the
fridge is..

Warren

Jeffrey R. Carter

unread,
Apr 19, 2010, 3:17:17 PM4/19/10
to
On Apr 19, 9:24 am, Ludovic Brenta <ludo...@ludovic-brenta.org> wrote:
>
> If you want to avoid the 16## part, you can easily convert the
> stream_elements to a string representation yourself like so:
>
> function To_Hex (E : in Ada.Streams.Stream_Element) return String is

This seems unnecessarily complex to me. Using the standard library to
put an element to a String in base 16, then stripping the "16#" from
the front and '#' from the end seems simpler, clearer, and less error
prone.

The PragmAda Reusable Components include Image functions with optional
Width, Zero_Filled, and Base parameters that do not include any base
indicator in the image. See PragmARC.Images and PragmARC.Images.Image.

http://pragmada.x10hosting.com/

Ludovic Brenta

unread,
Apr 19, 2010, 4:50:35 PM4/19/10
to
tonyg writes on comp.lang.ada:

> Changed the hex function to
> function To_Hex (E : in Ada.Streams.Stream_Element) return String
> is
> -- Warning: not compiled and not tested...
> X : constant array (0 .. 15) of Character :=

(1) I should have written:

X : constant array (Ada.Streams.Stream_Element range 0 .. 15) of Character :=

> ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
> 'C', 'D', 'E', 'F');
> Result : String (1 .. Ada.Streams.Stream_Element'Size / 4); -- 1 hex digits = 4 bits
> Working_Copy : Ada.Streams.Stream_Element := E;
> use type Ada.Streams.Stream_Element;
> First_Character : Natural := 0;
> Base : constant := 16;
> begin
> for K in reverse Result'First .. Result'Length loop

(2) and this should be:

for K in reverse Result'Range loop

> Result (K) := X (integer(Working_Copy) mod integer (Base) );

(3) and thanks to (1), this can come back to the simpler:

Result (K) := X (Working_Copy mod Base);

> Working_Copy := Working_Copy / Base;
> if Working_Copy = 0 then
> First_Character := K;
> exit;
> end if;
> end loop;
> return Result (First_Character .. Result'Last);
> end To_Hex;
>

> It still seems to be dropping a few zeros though and I'm stumped where
> its going wrong

I tested it with 42 and 0 and correctly got 2A and 0, so I don't know
what you mean by that.

Maybe the fact that the result has a variable width is a problem? If
so, here is a fixed-width variant which is actually a bit simpler:

function To_Hex (E : in Ada.Streams.Stream_Element) return String is

X : constant array (Ada.Streams.Stream_Element range 0 .. 15)


of Character :=
('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
'D', 'E', 'F');
Result : String
(1 .. Ada.Streams.Stream_Element'Size / 4) -- 1 hex digits = 4 bits

:= (others => '0');


Working_Copy : Ada.Streams.Stream_Element := E;
use type Ada.Streams.Stream_Element;

Base : constant := 16;
begin

for K in reverse Result'Range loop


Result (K) := X (Working_Copy mod Base);
Working_Copy := Working_Copy / Base;

end loop;
return Result;
end To_Hex;

and this yields 2A and 00 for my "test vector".

--
Ludovic Brenta.

Ludovic Brenta

unread,
Apr 19, 2010, 4:52:42 PM4/19/10
to
"Jeffrey R. Carter" <gg...@pragmada.x10hosting.com> writes:

> On Apr 19, 9:24 am, Ludovic Brenta <ludo...@ludovic-brenta.org> wrote:
>>
>> If you want to avoid the 16## part, you can easily convert the
>> stream_elements to a string representation yourself like so:
>>
>> function To_Hex (E : in Ada.Streams.Stream_Element) return String is
>
> This seems unnecessarily complex to me. Using the standard library to
> put an element to a String in base 16, then stripping the "16#" from
> the front and '#' from the end seems simpler, clearer, and less error
> prone.

I find it funny you should say that because I thought exactly the
opposite: letting Ada.Text_IO (which is notoriously slow) do the
conversion to string and then doing string manipulation is less clear
and more error-prone, IMHO (a proper implementation would use a simple,
but full-fledged, finite state machine). But your approach is certainly
valid and correct nevertheless.

--
Ludovic Brenta.

John B. Matthews

unread,
Apr 19, 2010, 7:21:13 PM4/19/10
to
In article <Xns9D5F9D5EB3703W...@81.169.183.62>,
Warren <ve3...@gmail.com> wrote:

> I hate these dos names that gnat uses for the spec file names.

Same here. Using GNAT, `gnatkr` can be used to find a file from a name
in the API. Say you are reading "A.10.1 The Package Text_IO", you can
pull up the specification with a command such as this:

$ more $ADA_INC/$(gnatkr Ada.Text_IO.ads)

where $ADA_INC point to the run-time library include files.

<http://gcc.gnu.org/onlinedocs/gcc-4.5.0/gnat_ugn_unw/File-Name-Krunching-Using-gnatkr.html>

Adam Beneschan

unread,
Apr 19, 2010, 7:22:39 PM4/19/10
to
On Apr 19, 12:28 pm, Warren <ve3...@gmail.com> wrote:
> Jeffrey R. Carter expounded in news:e5748cb1-0e95-49ff-8616-
> 6709c6dd7...@q15g2000yqj.googlegroups.com:

It got shoved in the back, behind that leftover chicken casserole
that's been there way too long and needs to be thrown out.

Hope this helps,

-- Adam

Jeffrey R. Carter

unread,
Apr 19, 2010, 7:34:32 PM4/19/10
to
On Apr 19, 1:52 pm, Ludovic Brenta <ludo...@ludovic-brenta.org> wrote:
>
> I find it funny you should say that because I thought exactly the
> opposite: letting Ada.Text_IO (which is notoriously slow) do the
> conversion to string and then doing string manipulation is less clear
> and more error-prone, IMHO (a proper implementation would use a simple,
> but full-fledged, finite state machine).  But your approach is certainly
> valid and correct nevertheless.

Funny you should say that ...

Considering that I can write

function Hex_Image (Number : Ada.Streams.Stream_Element) return String
is
Result : String (1 .. 10);
Start : Natural;

package Stream_Element_IO is new Ada.Text_IO.Modular_IO (Num =>
Ada.Streams.Stream_Element);

begin -- Hex_Image
Stream_Element_IO.Put (To => Result, Item => Number, Base => 16);
Start := Ada.Strings.Fixed.Index (Result, "#") + 1;

return Result (Start .. Result'Last - 1);
end Hex_Image;

and get it right 1st time, compared to the issues you encountered
duplicating (some of) the functionality of Put, seems to me evidence
that this approach is less error prone. I certainly find it simpler
and clearer, too.

Getting this to return a zero-filled String of the correct number of
digits is slightly more complex:

Num_Chars : constant := Ada.Streams.Stream_Element'Size / 4;

Result : String (1 .. Num_Chars + 10);

...

return String'(1 .. Num_Chars - (Result'Last - Start) => '0') & Result
(Start .. Result'Last - 1);

Stephen Leake

unread,
Apr 20, 2010, 3:25:41 AM4/20/10
to
tonyg <tonyt...@googlemail.com> writes:

Just to chime in with my generic solution to this (from SAL
http://www.stephe-leake.org/ada/sal.html) :

pragma License (Modified_GPL);

generic
Width : Natural;
type Number_Type is mod <>;
function SAL.Generic_Hex_Image (Item : in Number_Type) return String;
-- Return a hexadecimal image of Item, padded with leading zeros to
-- Width. If Width is too small for Item, leading digits are silently
-- truncated.
pragma Pure (SAL.Generic_Hex_Image);

function SAL.Generic_Hex_Image (Item : in Number_Type) return String
is
Temp : Number_Type := Item;
Nibble : Number_Type;
Image : String (1 .. Width);
begin
for I in reverse Image'Range loop
Nibble := Temp mod 16;
Temp := Temp / 16;
if Nibble > 9 then
Image (I) := Character'Val (Character'Pos ('A') + Integer (Nibble) - 10);
else
Image (I) := Character'Val (Character'Pos ('0') + Integer (Nibble));
end if;
end loop;
return Image;
end SAL.Generic_Hex_Image;

--
-- Stephe

tonyg

unread,
Apr 20, 2010, 5:00:37 AM4/20/10
to

Its the variable width I think.

Peter Hermann

unread,
Apr 20, 2010, 5:25:52 AM4/20/10
to
tonyg <tonyt...@googlemail.com> wrote:
> Its the variable width I think.

http://en.wikipedia.org/wiki/Netiquette
and
http://tools.ietf.org/html/rfc1855
for postings, look for:
But do not include the entire original!

alternative: many CTRL-K

Warren

unread,
Apr 20, 2010, 10:04:26 AM4/20/10
to
Adam Beneschan expounded in news:32ac71bf-cd1e-4068-a0a6-
9491b4...@y38g2000prb.googlegroups.com:

..


>> Now if only I could find where the mayonnaise in the
>> fridge is..
>
> It got shoved in the back, behind that leftover chicken casserole
> that's been there way too long and needs to be thrown out.
>
> Hope this helps,
>
> -- Adam

Ew!

I guess it helps not to have preconceptions when looking
for stuff. I looked for a "white" jar of mayonnaise and of
course couldn't find it. This was because my wife bought
mayonnaise in a yellow plastic jar (recently), which I
mistook for mustard. She of course, had no trouble at
all finding it.

Warren

J-P. Rosen

unread,
Apr 20, 2010, 10:46:22 AM4/20/10
to
Warren a écrit :

> I guess it helps not to have preconceptions when looking
> for stuff. I looked for a "white" jar of mayonnaise and of
> course couldn't find it. This was because my wife bought
> mayonnaise in a yellow plastic jar (recently), which I
> mistook for mustard. She of course, had no trouble at
> all finding it.
>

Now, you understand the importance of having unambiguous specifications
that match the implementation (back on topic) ;-)

--
---------------------------------------------------------
J-P. Rosen (ro...@adalog.fr)
Visit Adalog's web site at http://www.adalog.fr

Warren

unread,
Apr 20, 2010, 11:52:34 AM4/20/10
to
J-P. Rosen expounded in news:hqkeo7$p8r$1...@news.eternal-september.org:

> Warren a écrit :
>
>> I guess it helps not to have preconceptions when looking
>> for stuff. I looked for a "white" jar of mayonnaise and of
>> course couldn't find it. This was because my wife bought
>> mayonnaise in a yellow plastic jar (recently), which I
>> mistook for mustard. She of course, had no trouble at
>> all finding it.
>>
> Now, you understand the importance of having unambiguous specifications
> that match the implementation (back on topic) ;-)

Indeed!

with Fridge.Mayonnaise;

Warren

Jeffrey R. Carter

unread,
Apr 20, 2010, 6:21:22 PM4/20/10
to
On Apr 20, 12:25 am, Stephen Leake <stephen_le...@stephe-leake.org>
wrote:

>
> generic
>    Width : Natural;
>    type Number_Type is mod <>;
> function SAL.Generic_Hex_Image (Item : in Number_Type) return String;
> --  Return a hexadecimal image of Item, padded with leading zeros to
> --  Width. If Width is too small for Item, leading digits are silently
> --  truncated.

So if I sometimes want different widths for the same type, I have to
have multiple instantiations? That doesn't seem very friendly to me. I
don't see why Width couldn't be a parameter of the function, probably
defaulted to Number_Type'Width.

What do I do for signed integer images, for bases other than 16, and
for signed integer images for bases other than 16? Do I have to roll
my own for these cases?

In Ada.Text_IO, a Width of zero implies the minimum width needed to
represent the value; here it's an expensive way to get a null String.
I'd prefer consistency with the standard.

I haven't used SAL, but these are the kind of comments you'd probably
get from me if I did use this function. HTH.

Stephen Leake

unread,
Apr 21, 2010, 8:38:35 AM4/21/10
to
"Jeffrey R. Carter" <gg...@pragmada.x10hosting.com> writes:

> On Apr 20, 12:25 am, Stephen Leake <stephen_le...@stephe-leake.org>
> wrote:
>>
>> generic
>>    Width : Natural;
>>    type Number_Type is mod <>;
>> function SAL.Generic_Hex_Image (Item : in Number_Type) return String;
>> --  Return a hexadecimal image of Item, padded with leading zeros to
>> --  Width. If Width is too small for Item, leading digits are silently
>> --  truncated.
>
> So if I sometimes want different widths for the same type, I have to
> have multiple instantiations?

Yes. But in practice, the width you want is Number_Type'Width (but
assuming hexadecimal), so it's not a problem.

The only problem I've encountered is the "silently truncated" part. We
changed a number type to have more bits, but forgot to change the Width
parameter here.

There are times, such as building formatted dates, when I need a
specific number of characters, and want an exception if the actual value
can't be represented in that number. Then this function is not
appropriate.

> That doesn't seem very friendly to me. I don't see why Width couldn't
> be a parameter of the function,

It could; in the body, it is only used as the size of the result image
string. It's just historical accident that it is a generic parameter
instead.

> probably defaulted to Number_Type'Width.

That assumes base 10, so it would be wrong. If I made a change like
this, I'd keep the generic parameter as the default width, or add a
function that computes a default width assuming base 16, and use that as
the default.

> What do I do for signed integer images,

I never need to image signed integers in hex; that's confusing.

> for bases other than 16,

sal-generic_binary_image.ads
sal-generic_decimal_image.ads

are the only ones I've ever needed. The binary image includes '_' every
four digits.

> and for signed integer images for bases other than 16?

Never needed them.

> Do I have to roll my own for these cases?

Yes.

It is far easier to test a small, focused routine than a large, general
purpose one.

> In Ada.Text_IO, a Width of zero implies the minimum width needed to
> represent the value; here it's an expensive way to get a null String.
> I'd prefer consistency with the standard.

If this function were proposed as part of the Ada standard, that would
make sense. However, it is part of SAL, which often has a different
philosophy.

> I haven't used SAL, but these are the kind of comments you'd probably
> get from me if I did use this function. HTH.

Thanks for your comments.

--
-- Stephe

0 new messages