Get a hash value using XS
This is an example of using Perl's XS extension "language" to make a simple extension to print out a hash value.
This is the Perl module, which is called GetHashValue.pm
:
package GetHashValue; require Exporter; @ISA = qw(Exporter); @EXPORT = 'get_hash_value'; require XSLoader; our $VERSION = '0.001'; XSLoader::load('GetHashValue', $VERSION); 1;
This is the XS part of the module, GetHashValue.xs
,
which goes in the top directory:
#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "get-hash-value.h" MODULE=GetHashValue PACKAGE=GetHashValue PROTOTYPES: ENABLE void get_hash_value (hash) HV * hash CODE: get_hash_value (hash);
This is a C file, get-hash-value.c
which contains the
working bits of our program. This is in its own file.
#include <stdio.h> #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "get-hash-value.h" void get_hash_value (HV * hash) { const char * key = "test-key"; SV * key_sv; key_sv = newSVpv (key, strlen (key)); if (hv_exists_ent (hash, key_sv, 0)) { HE * he; SV * val; char * val_pv; int val_length; int val_iv; printf ("The key for '%s' seems to exist.\n", key); he = hv_fetch_ent (hash, key_sv, 0, 0); val = HeVAL (he); val_pv = SvPV (val, val_length); printf ("As a string, its value is '%s' (length %d).\n", val_pv, val_length); if (SvIOK (val)) { val_iv = SvIV (val); printf ("As a number, its value is '%d'.\n", val_iv); } else { printf ("Perl doesn't think it's a number.\n"); } } else { printf ("The key for '%s' doesn't seem to exist.\n", key); } }
You also need a header file so the XS file knows what's in the C file. The following one is automatically generated by Cfunctions.
/* This is a Cfunctions (version 0.27) generated header file. Cfunctions is a free program for extracting headers from C files. Get Cfunctions from `http://cfunctions.sourceforge.net/'. */ /* This file was generated with: `cfunctions -i -c -n get-hash-value.c' */ #ifndef CFH_GET_HASH_VALUE_H #define CFH_GET_HASH_VALUE_H /* From `get-hash-value.c': */ #line 6 "get-hash-value.c" void get_hash_value (HV * hash ); #endif /* CFH_GET_HASH_VALUE_H */
You also need a file called Makefile.PL
in order to
compile this. As usual, you do
$ perl Makefile.PL $ make
With the test program as below you don't need to bother with "make install". There is no test so "make test" won't work!
use strict; use warnings; use ExtUtils::MakeMaker; WriteMakefile ( NAME => 'GetHashValue', VERSION => '0.001', OBJECT => 'GetHashValue.o get-hash-value.o', ); # Include the dependencies in the header file. sub MY::postamble { return <<EOF; GetHashValue.o: get-hash-value.h get-hash-value.o: get-hash-value.h EOF }
The following is a test program.
#!/home/ben/software/install/bin/perl use warnings; use strict; use lib 'blib/arch'; use lib 'blib/lib'; use GetHashValue; get_hash_value ({bonkers => 1}); get_hash_value ({bonkers => 1, 'test-key' => 1}); get_hash_value ({bonkers => 1, 'test-key' => "A million", x => 'y'}); get_hash_value ({});
The output should look something like this (hopefully):
The key for 'test-key' doesn't seem to exist. The key for 'test-key' seems to exist. As a string, its value is '1' (length 1). As a number, its value is '1'. The key for 'test-key' seems to exist. As a string, its value is 'A million' (length 9). Perl doesn't think it's a number. The key for 'test-key' doesn't seem to exist.