AI-FANN
view release on metacpan or search on metacpan
Revision history for Perl extension AI::FANN.
0.10 Mar 10, 2009
- syntax error in Makefile.PL (bug report by Michael Stevens)
- backport OpenBSD patch for Makefile.PL
0.09 Oct 16, 2008
- AI::FANN::TrainData->new_from_file was nos working (bug reported
by Renata Camargo)
- constructors were not reporting errors via exceptions as
documented
- compiler warnings cleaned
0.08 Jul 5, 2007
- use doubles instead of floats on accessors
- MSE is a float (bug and patch by Alex Lang)
- add support for FANN_SIN_SYMMETRIC, FANN_COS_SYMMETRIC,
FANN_SIN and FANN_COS constants.
0.07 Nov 22, 2006
- move to FANN 2.1
0.06 Sep 18, 2006
- add support for FANN_LIB and FANN_INCLUDE to MAkefile.PL
0.05 May 4, 2006
- ppport.h regenerated with latest version of Devel::PPPort to
make it work on perls older than 5.8.8 (bug reported by bodyn).
0.04 May 1, 2006
- corrected bug on accessor generators with indexes
- better accessor generation using default arguments XS feature
0.03 Apr 14, 2006
- improved docs.
0.02 Apr 14, 2006
- improved docs.
0.01 Apr 7, 2006
- original version; created by h2xs 1.23 with options
-An AI::FANN /usr/local/include/fann.h
#include "constants.h"
#define WANT_MORTAL 1
typedef fann_type *fta; /* fta: fann_type array */
typedef fta fta_input;
typedef fta fta_output;
static SV *
_obj2sv(pTHX_ void *ptr, SV * klass, char * ctype) {
if (ptr) {
SV *rv;
SV *sv = newSVpvf("%s(0x%p)", ctype, ptr);
SV *mgobj = sv_2mortal(newSViv(PTR2IV(ptr)));
SvREADONLY_on(mgobj);
sv_magic(sv, mgobj, '~', ctype, 0);
/* SvREADONLY_on(sv); */
rv = newRV_noinc(sv);
if (SvOK(klass)) {
HV *stash;
if (SvROK(klass))
stash = SvSTASH(klass);
else
stash = gv_stashsv(klass, 1);
sv_bless(rv, stash);
}
return rv;
}
return &PL_sv_undef;
}
static void *
_sv2obj(pTHX_ SV* self, char * ctype, int required) {
SV *sv = SvRV(self);
if (sv) {
if (SvTYPE(sv) == SVt_PVMG) {
MAGIC *mg = mg_find(sv, '~');
if (mg) {
if (strcmp(ctype, mg->mg_ptr) == 0 && mg->mg_obj) {
return INT2PTR(void *, SvIV(mg->mg_obj));
}
}
}
}
if (required) {
Perl_croak(aTHX_ "object of class %s expected", ctype);
}
return NULL;
}
static SV *
_fta2sv(pTHX_ fann_type *fta, unsigned int len) {
unsigned int i;
AV *av = newAV();
av_extend(av, len - 1);
for (i = 0; i < len; i++) {
SV *sv = newSVnv(fta[i]);
av_store(av, i, sv);
}
return newRV_noinc((SV*)av);
}
static AV*
_srv2av(pTHX_ SV* sv, unsigned int len, char * const name) {
if (SvROK(sv)) {
AV *av = (AV*)SvRV(sv);
if (SvTYPE((SV*)av)==SVt_PVAV) {
if (av_len(av)+1 == len) {
return av;
}
else {
Perl_croak(aTHX_ "wrong number of elements in %s array, %d found when %d were required",
name, (unsigned int)(av_len(av)+1), len);
}
}
}
Perl_croak(aTHX_ "wrong type for %s argument, array reference expected", name);
}
static fann_type*
_sv2fta(pTHX_ SV *sv, unsigned int len, int flags, char * const name) {
unsigned int i;
fann_type *fta;
AV *av = _srv2av(aTHX_ sv, len, name);
Newx(fta, len, fann_type);
if (flags & WANT_MORTAL) SAVEFREEPV(fta);
for (i = 0; i < len; i++) {
SV ** svp = av_fetch(av, i, 0);
fta[i] = SvNV(svp ? *svp : &PL_sv_undef);
}
return fta;
}
static void
_check_error(pTHX_ struct fann_error *self) {
if (self) {
if (fann_get_errno(self) != FANN_E_NO_ERROR) {
ERRSV = newSVpv(self->errstr, strlen(self->errstr) - 2);
fann_get_errstr(self);
Perl_croak(aTHX_ Nullch);
}
}
else {
Perl_croak(aTHX_ "Constructor failed");
}
}
static unsigned int
_sv2enum(pTHX_ SV *sv, unsigned int top, char * const name) {
unsigned int value = SvUV(sv);
if (value > top) {
Perl_croak(aTHX_ "value %d is out of range for %s", value, name);
}
return value;
}
static SV *
_enum2sv(pTHX_ unsigned int value, char const * const * const names, unsigned int top, char const * const name) {
SV *sv;
if (value > top) {
Perl_croak(aTHX_ "internal error: value %d out of range for %s", value, name);
}
sv = newSVpv(names[value], 0);
SvUPGRADE(sv, SVt_PVIV);
SvUV_set(sv, value);
SvIOK_on(sv);
SvIsUV_on(sv);
return sv;
}
#define _sv2fann_train_enum(sv) _sv2enum(aTHX_ sv, FANN_TRAIN_QUICKPROP, "fann_train_enum")
#define _sv2fann_activationfunc_enum(sv) _sv2enum(aTHX_ sv, FANN_LINEAR_PIECE_SYMMETRIC, "fann_activationfunc_enum")
#define _sv2fann_errorfunc_enum(sv) _sv2enum(aTHX_ sv, FANN_ERRORFUNC_TANH, "fann_errorfunc_enum")
#define _sv2fann_stopfunc_enum(sv) _sv2enum(aTHX_ sv, FANN_STOPFUNC_BIT, "fann_stopfunc_enum")
#define _fann_train_enum2sv(sv) _enum2sv(aTHX_ sv, FANN_TRAIN_NAMES, FANN_TRAIN_QUICKPROP, "fann_train_enum")
#define _fann_activationfunc_enum2sv(sv) _enum2sv(aTHX_ sv, FANN_ACTIVATIONFUNC_NAMES, FANN_LINEAR_PIECE_SYMMETRIC, "fann_activationfunc_enum")
#define _fann_errorfunc_enum2sv(sv) _enum2sv(aTHX_ sv, FANN_ERRORFUNC_NAMES, FANN_ERRORFUNC_TANH, "fann_errorfunc_enum")
#define fann_train_data_length fann_length_train_data
#define fann_train_data_num_input fann_num_input_train_data
#define fann_train_data_num_output fann_num_output_train_data
#define fann_train_data_save fann_save_train
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = fann_
PROTOTYPES: DISABLE
BOOT:
fann_set_error_log(0, 0);
void
_constants()
PREINIT:
unsigned int i;
PPCODE:
for (i = 0; my_constant_names[i]; i++) {
SV *sv = sv_2mortal(newSVpv(my_constant_names[i], 0));
SvUPGRADE(sv, SVt_PVIV);
SvUV_set(sv, my_constant_values[i]);
SvIOK_on(sv);
SvIsUV_on(sv);
XPUSHs(sv);
}
XSRETURN(i);
struct fann *
fann_new_standard(klass, ...)
SV *klass;
PREINIT:
unsigned int *layers;
unsigned int i;
unsigned int num_layers;
CODE:
num_layers = items - 1;
Newx(layers, num_layers, unsigned int);
SAVEFREEPV(layers);
for (i = 0; i < num_layers; i++) {
layers[i] = SvIV(ST(i+1));
}
RETVAL = fann_create_standard_array(num_layers, layers);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)RETVAL);
struct fann *
fann_new_sparse(klass, connection_rate, ...)
SV *klass;
double connection_rate;
PREINIT:
unsigned int *layers;
unsigned int i;
unsigned int num_layers;
CODE:
num_layers = items - 2;
Newx(layers, num_layers, unsigned int);
SAVEFREEPV(layers);
for (i = 0; i < num_layers; i++) {
layers[i] = SvIV(ST(i+2));
}
RETVAL = fann_create_sparse_array(connection_rate, num_layers, layers);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)RETVAL);
struct fann *
fann_new_shortcut(klass, ...)
SV *klass;
PREINIT:
unsigned int *layers;
unsigned int i;
unsigned int num_layers;
CODE:
num_layers = items - 1;
Newx(layers, num_layers, unsigned int);
SAVEFREEPV(layers);
for (i = 0; i < num_layers; i++) {
layers[i] = SvIV(ST(i+1));
}
RETVAL = fann_create_shortcut_array(num_layers, layers);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)RETVAL);
struct fann *
fann_new_from_file(klass, filename)
SV *klass;
char *filename;
CODE:
RETVAL = fann_create_from_file(filename);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)RETVAL);
void
fann_DESTROY(self)
struct fann * self;
CODE:
fann_destroy(self);
sv_unmagic(SvRV(ST(0)), '~');
int
fann_save(self, filename)
struct fann *self;
char * filename;
CODE:
RETVAL = !fann_save(self, filename);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
fta_output
fann_run(self, input)
struct fann *self;
fta_input input;
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
void
fann_randomize_weights(self, min_weight, max_weight)
struct fann *self;
fann_type min_weight;
fann_type max_weight;
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
void
fann_train(self, input, desired_output)
struct fann *self;
fta_input input;
fta_output desired_output;
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
fta_output
fann_test(self, input, desired_output)
struct fann *self;
fta_input input;
fta_output desired_output;
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
void
fann_reset_MSE(self)
struct fann * self;
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
void
fann_train_on_file(self, filename, max_epochs, epochs_between_reports, desired_error)
struct fann *self;
const char *filename;
unsigned int max_epochs;
unsigned int epochs_between_reports;
double desired_error;
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
void
fann_train_on_data(self, data, max_epochs, epochs_between_reports, desired_error)
struct fann *self;
struct fann_train_data *data;
unsigned int max_epochs;
unsigned int epochs_between_reports;
double desired_error;
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
_check_error(aTHX_ (struct fann_error *)data);
void
fann_cascadetrain_on_file(self, filename, max_neurons, neurons_between_reports, desired_error)
struct fann *self;
const char *filename;
unsigned int max_neurons;
unsigned int neurons_between_reports;
double desired_error;
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
void
fann_cascadetrain_on_data(self, data, max_neurons, neurons_between_reports, desired_error)
struct fann *self;
struct fann_train_data *data;
unsigned int max_neurons;
unsigned int neurons_between_reports;
double desired_error;
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
_check_error(aTHX_ (struct fann_error *)data);
double
fann_train_epoch(self, data)
struct fann *self;
struct fann_train_data *data;
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
_check_error(aTHX_ (struct fann_error *)data);
void
fann_print_connections(self)
struct fann * self;
void
fann_print_parameters(self)
struct fann * self;
void
fann_cascade_activation_functions(self, ...)
struct fann *self;
PREINIT:
unsigned int count;
PPCODE:
if (items > 1) {
unsigned int i;
enum fann_activationfunc_enum * funcs;
count = items - 1;
Newx(funcs, items - 1, enum fann_activationfunc_enum);
SAVEFREEPV(funcs);
for (i = 0; i < count; i++) {
funcs[i] = _sv2fann_activationfunc_enum(ST(i+1));
}
fann_set_cascade_activation_functions(self, funcs, count);
}
count = fann_get_cascade_activation_functions_count(self);
if (GIMME_V == G_ARRAY) {
unsigned int i;
enum fann_activationfunc_enum * funcs = fann_get_cascade_activation_functions(self);
EXTEND(SP, count);
for (i = 0; i < count; i++) {
ST(i) = sv_2mortal(_fann_activationfunc_enum2sv(funcs[i]));
}
XSRETURN(count);
}
else {
ST(0) = sv_2mortal(newSVuv(count));
XSRETURN(1);
}
void
fann_cascade_activation_steepnesses(self, ...)
struct fann *self;
PREINIT:
unsigned int count;
PPCODE:
if (items > 1) {
unsigned int i;
fann_type * steepnesses;
count = items - 1;
Newx(steepnesses, items - 1, fann_type);
SAVEFREEPV(steepnesses);
for (i = 0; i < count; i++) {
steepnesses[i] = SvNV(ST(i+1));
}
fann_set_cascade_activation_steepnesses(self, steepnesses, count);
}
count = fann_get_cascade_activation_steepnesses_count(self);
if (GIMME_V == G_ARRAY) {
unsigned int i;
fann_type * steepnesses = fann_get_cascade_activation_steepnesses(self);
EXTEND(SP, count);
for (i = 0; i < count; i++) {
ST(i) = sv_2mortal(newSVuv(steepnesses[i]));
}
XSRETURN(count);
}
else {
ST(0) = sv_2mortal(newSVuv(count));
XSRETURN(1);
}
MODULE = AI::FANN PACKAGE = AI::FANN::TrainData PREFIX = fann_train_data_
struct fann_train_data *
fann_train_data_new_from_file(klass, filename)
SV *klass;
const char *filename;
CODE:
RETVAL = fann_train_data_create_from_file(filename);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)RETVAL);
struct fann_train_data *
fann_train_data_new_empty(klass, num_data, num_input, num_output)
SV *klass;
unsigned int num_data;
unsigned int num_input;
unsigned int num_output;
CODE:
RETVAL = fann_train_data_create(num_data, num_input, num_output);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)RETVAL);
void
fann_train_data_data(self, index, ...)
struct fann_train_data *self;
unsigned int index;
PREINIT:
AV *input;
AV *output;
unsigned int i;
PPCODE:
if (index >= self->num_data)
Perl_croak(aTHX_"index %d is out of range", index);
switch (items) {
case 4:
input = _srv2av(aTHX_ ST(2), self->num_input, "input");
for (i = 0; i < self->num_input; i++) {
SV **svp = av_fetch(input, i, 0);
self->input[index][i] = SvNV(svp ? *svp : &PL_sv_undef);
}
output = _srv2av(aTHX_ ST(3), self->num_output, "output");
for (i = 0; i < self->num_output; i++) {
SV **svp = av_fetch(output, i, 0);
self->output[index][i] = SvNV(svp ? *svp : &PL_sv_undef);
}
case 2:
if (GIMME_V == G_ARRAY) {
input = newAV();
output = newAV();
av_extend(input, self->num_input - 1);
av_extend(output, self->num_output - 1);
for (i = 0; i < self->num_input; i++) {
SV *sv = newSVnv(self->input[index][i]);
av_store(input, i, sv);
}
for (i = 0; i < self->num_output; i++) {
SV *sv = newSVnv(self->output[index][i]);
av_store(output, i, sv);
}
ST(0) = sv_2mortal(newRV_inc((SV*)input));
ST(1) = sv_2mortal(newRV_inc((SV*)output));
XSRETURN(2);
}
else {
ST(0) = &PL_sv_yes;
XSRETURN(1);
}
break;
default:
Perl_croak(aTHX_ "Usage: AI::FANN::TrainData::data(self, index [, input, output])");
}
struct fann_train_data *
fann_train_data_new(klass, input, output, ...)
SV *klass;
AV *input;
AV *output;
PREINIT:
unsigned int num_data;
unsigned int num_input;
unsigned int num_output;
unsigned int i;
CODE:
if (!(items & 1)) {
Perl_croak(aTHX_ "wrong number of arguments in constructor");
}
num_data = items >> 1;
num_input = av_len(input) + 1;
if (!num_input)
Perl_croak(aTHX_ "input array is empty");
num_output = av_len(output) + 1;
if (!num_output)
Perl_croak(aTHX_ "output array is empty");
RETVAL = fann_train_data_create(num_data, num_input, num_output);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)RETVAL);
/* we do that at cleanup to ensure that the just created object is
* freed if we croak */
if (RETVAL) {
for (i = 0; i < num_data; i++) {
unsigned int j;
input = _srv2av(aTHX_ ST(1 + i * 2), num_input, "input");
for (j = 0; j < num_input; j++) {
SV **svp = av_fetch(input, j, 0);
RETVAL->input[i][j] = SvNV(svp ? *svp : &PL_sv_undef);
}
output = _srv2av(aTHX_ ST(2 + i * 2), num_output, "output");
for (j = 0; j < num_output; j++) {
SV **svp = av_fetch(output, j, 0);
RETVAL->output[i][j] = SvNV(svp ? *svp : &PL_sv_undef);
}
}
}
void
fann_train_data_DESTROY(self)
struct fann_train_data * self;
CODE:
fann_destroy_train(self);
sv_unmagic(SvRV(ST(0)), '~');
void
fann_train_data_shuffle(self)
struct fann_train_data *self;
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
void
fann_train_data_scale_input(self, new_min, new_max)
struct fann_train_data *self;
fann_type new_min;
fann_type new_max;
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
void
fann_train_data_scale_output(self, new_min, new_max)
struct fann_train_data *self;
fann_type new_min;
fann_type new_max;
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
void
fann_train_data_scale(self, new_min, new_max)
struct fann_train_data *self;
fann_type new_min;
fann_type new_max;
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
struct fann_train_data*
fann_train_data_subset(self, pos, length)
struct fann_train_data *self;
unsigned int pos;
unsigned int length;
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
_check_error(aTHX_ (struct fann_error *)RETVAL);
INCLUDE: accessors.xsh
--- #YAML:1.0
name: AI-FANN
version: 0.10
abstract: Perl wrapper for the Fast Artificial Neural Network library
license: ~
author:
- Salvador Fandiño <sfandino@yahoo.com>
generated_by: ExtUtils::MakeMaker version 6.42
distribution_type: module
requires:
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.3.html
version: 1.3
Makefile.PL view on Meta::CPAN
use ExtUtils::MakeMaker;
use strict;
use warnings;
my $fann_lib = '';
my $fann_inc = '';
my $prefix;
@ARGV = map {
if (/^FANN_LIB=(.*)/) {
$fann_lib = "-L$1 ";
()
}
elsif (/^FANN_INCLUDE=(.*)/) {
$fann_inc = "-I$1 ";
()
}
else {
$prefix = $1 if /^PREFIX=(.*)/;
$_
}
} @ARGV;
if (defined $prefix) {
$fann_lib = "-L$prefix/lib " unless length $fann_lib;
$fann_inc = "-I$prefix/include " unless length $fann_inc;
}
WriteMakefile( NAME => 'AI::FANN',
VERSION_FROM => 'lib/AI/FANN.pm',
PREREQ_PM => {},
ABSTRACT_FROM => 'lib/AI/FANN.pm',
AUTHOR => 'Salvador Fandiño <sfandino@yahoo.com>',
LIBS => ["${fann_lib}-ldoublefann"],
DEFINE => '',
INC => "${fann_inc}-I.",
OBJECT => '$(BASEEXT)$(OBJ_EXT) morefann$(OBJ_EXT)',
#OPTIMIZE => '-g -O0',
depend => { '$(BASEEXT).c' => 'constants.h accessors.xsh' }
);
sub MY::postamble {
return <<MAKE_FRAG
constants.h: genconstants
\t\$(PERL) genconstants > constants.h
accessors.xsh: genaccessors
\t\$(PERL) genaccessors > accessors.xsh
MAKE_FRAG
}
This module requires the FANN library version 2.1.0beta or later
compiled to use doubles internally.
The module Test::More is also required for testing.
INSTALLATION
To install this module type the following:
perl Makefile.PL
make
make test
make install
You may need to add two extra parameters to the Makefile.PL script to
indicate where to find the FANN library and include files if they are
not installed on some standard locations. For instance:
perl Makefile.PL \
FANN_LIB=/usr/local/fann/lib \
FANN_INCLUDE=/usr/local/fann/include
COPYRIGHT AND LICENCE
Copyright (C) 2006 by Salvador Fandino (sfandino@yahoo.com).
This Perl module is free software; you can redistribute it and/or
modify it under the same terms as Perl itself, either Perl version
5.8.8 or, at your option, any later version of Perl 5 you may have
available.
accessors.xsh view on Meta::CPAN
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
enum fann_train_enum
accessor_training_algorithm(self, value = NO_INIT)
struct fann * self;
enum fann_train_enum value
CODE:
if (items > 1) {
fann_set_training_algorithm(self, value);
}
RETVAL = fann_get_training_algorithm(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
enum fann_errorfunc_enum
accessor_train_error_function(self, value = NO_INIT)
struct fann * self;
enum fann_errorfunc_enum value
CODE:
if (items > 1) {
fann_set_train_error_function(self, value);
}
RETVAL = fann_get_train_error_function(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
enum fann_stopfunc_enum
accessor_train_stop_function(self, value = NO_INIT)
struct fann * self;
enum fann_stopfunc_enum value
CODE:
if (items > 1) {
fann_set_train_stop_function(self, value);
}
RETVAL = fann_get_train_stop_function(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
double
accessor_learning_rate(self, value = NO_INIT)
struct fann * self;
double value
CODE:
if (items > 1) {
fann_set_learning_rate(self, value);
}
RETVAL = fann_get_learning_rate(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
double
accessor_learning_momentum(self, value = NO_INIT)
struct fann * self;
double value
CODE:
if (items > 1) {
fann_set_learning_momentum(self, value);
}
RETVAL = fann_get_learning_momentum(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
fann_type
accessor_bit_fail_limit(self, value = NO_INIT)
struct fann * self;
fann_type value
CODE:
if (items > 1) {
fann_set_bit_fail_limit(self, value);
}
RETVAL = fann_get_bit_fail_limit(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
double
accessor_quickprop_decay(self, value = NO_INIT)
struct fann * self;
double value
CODE:
if (items > 1) {
fann_set_quickprop_decay(self, value);
}
RETVAL = fann_get_quickprop_decay(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
double
accessor_quickprop_mu(self, value = NO_INIT)
struct fann * self;
double value
CODE:
if (items > 1) {
fann_set_quickprop_mu(self, value);
}
RETVAL = fann_get_quickprop_mu(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
double
accessor_rprop_increase_factor(self, value = NO_INIT)
struct fann * self;
double value
CODE:
if (items > 1) {
fann_set_rprop_increase_factor(self, value);
}
RETVAL = fann_get_rprop_increase_factor(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
double
accessor_rprop_decrease_factor(self, value = NO_INIT)
struct fann * self;
double value
CODE:
if (items > 1) {
fann_set_rprop_decrease_factor(self, value);
}
RETVAL = fann_get_rprop_decrease_factor(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
double
accessor_rprop_delta_min(self, value = NO_INIT)
struct fann * self;
double value
CODE:
if (items > 1) {
fann_set_rprop_delta_min(self, value);
}
RETVAL = fann_get_rprop_delta_min(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
double
accessor_rprop_delta_max(self, value = NO_INIT)
struct fann * self;
double value
CODE:
if (items > 1) {
fann_set_rprop_delta_max(self, value);
}
RETVAL = fann_get_rprop_delta_max(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
unsigned int
accessor_num_inputs(self)
struct fann * self;
CODE:
RETVAL = fann_get_num_input(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
unsigned int
accessor_num_outputs(self)
struct fann * self;
CODE:
RETVAL = fann_get_num_output(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
unsigned int
accessor_total_neurons(self)
struct fann * self;
CODE:
RETVAL = fann_get_total_neurons(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
unsigned int
accessor_total_connections(self)
struct fann * self;
CODE:
RETVAL = fann_get_total_connections(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
double
accessor_connection_rate(self)
struct fann * self;
CODE:
RETVAL = fann_get_connection_rate(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
double
accessor_MSE(self)
struct fann * self;
CODE:
RETVAL = fann_get_MSE(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
unsigned int
accessor_bit_fail(self)
struct fann * self;
CODE:
RETVAL = fann_get_bit_fail(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
double
accessor_cascade_output_change_fraction(self, value = NO_INIT)
struct fann * self;
double value
CODE:
if (items > 1) {
fann_set_cascade_output_change_fraction(self, value);
}
RETVAL = fann_get_cascade_output_change_fraction(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
double
accessor_cascade_output_stagnation_epochs(self, value = NO_INIT)
struct fann * self;
double value
CODE:
if (items > 1) {
fann_set_cascade_output_stagnation_epochs(self, value);
}
RETVAL = fann_get_cascade_output_stagnation_epochs(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
double
accessor_cascade_candidate_change_fraction(self, value = NO_INIT)
struct fann * self;
double value
CODE:
if (items > 1) {
fann_set_cascade_candidate_change_fraction(self, value);
}
RETVAL = fann_get_cascade_candidate_change_fraction(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
unsigned int
accessor_cascade_candidate_stagnation_epochs(self, value = NO_INIT)
struct fann * self;
unsigned int value
CODE:
if (items > 1) {
fann_set_cascade_candidate_stagnation_epochs(self, value);
}
RETVAL = fann_get_cascade_candidate_stagnation_epochs(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
fann_type
accessor_cascade_weight_multiplier(self, value = NO_INIT)
struct fann * self;
fann_type value
CODE:
if (items > 1) {
fann_set_cascade_weight_multiplier(self, value);
}
RETVAL = fann_get_cascade_weight_multiplier(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
fann_type
accessor_cascade_candidate_limit(self, value = NO_INIT)
struct fann * self;
fann_type value
CODE:
if (items > 1) {
fann_set_cascade_candidate_limit(self, value);
}
RETVAL = fann_get_cascade_candidate_limit(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
unsigned int
accessor_cascade_max_out_epochs(self, value = NO_INIT)
struct fann * self;
unsigned int value
CODE:
if (items > 1) {
fann_set_cascade_max_out_epochs(self, value);
}
RETVAL = fann_get_cascade_max_out_epochs(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
unsigned int
accessor_cascade_max_cand_epochs(self, value = NO_INIT)
struct fann * self;
unsigned int value
CODE:
if (items > 1) {
fann_set_cascade_max_cand_epochs(self, value);
}
RETVAL = fann_get_cascade_max_cand_epochs(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
unsigned int
accessor_cascade_num_candidates(self)
struct fann * self;
CODE:
RETVAL = fann_get_cascade_num_candidates(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
unsigned int
accessor_cascade_num_candidate_groups(self, value = NO_INIT)
struct fann * self;
unsigned int value
CODE:
if (items > 1) {
fann_set_cascade_num_candidate_groups(self, value);
}
RETVAL = fann_get_cascade_num_candidate_groups(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
enum fann_activationfunc_enum
accessor_neuron_activation_function(self, layer, neuron_index, value = NO_INIT)
struct fann * self;
unsigned int layer;
unsigned int neuron_index;
enum fann_activationfunc_enum value
CODE:
if (items > 3) {
fann_set_activation_function(self, value, layer, neuron_index);
}
RETVAL = fann_get_activation_function(self, layer, neuron_index);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
void
accessor_layer_activation_function(self, layer, value)
struct fann * self;
unsigned int layer;
enum fann_activationfunc_enum value;
CODE:
fann_set_activation_function_layer(self, value, layer);
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
void
accessor_hidden_activation_function(self, value)
struct fann * self;
enum fann_activationfunc_enum value;
CODE:
fann_set_activation_function_hidden(self, value);
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
void
accessor_output_activation_function(self, value)
struct fann * self;
enum fann_activationfunc_enum value;
CODE:
fann_set_activation_function_output(self, value);
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
fann_type
accessor_neuron_activation_steepness(self, layer, neuron, value = NO_INIT)
struct fann * self;
unsigned int layer;
unsigned int neuron;
fann_type value
CODE:
if (items > 3) {
fann_set_activation_steepness(self, value, layer, neuron);
}
RETVAL = fann_get_activation_steepness(self, layer, neuron);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
void
accessor_layer_activation_steepness(self, layer, value)
struct fann * self;
unsigned int layer;
fann_type value;
CODE:
fann_set_activation_steepness_layer(self, value, layer);
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
void
accessor_hidden_activation_steepness(self, value)
struct fann * self;
fann_type value;
CODE:
fann_set_activation_steepness_hidden(self, value);
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
void
accessor_output_activation_steepness(self, value)
struct fann * self;
fann_type value;
CODE:
fann_set_activation_steepness_output(self, value);
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
unsigned int
accessor_layer_num_neurons(self, layer)
struct fann * self;
unsigned int layer;
CODE:
RETVAL = fann_get_num_neurons(self, layer);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN PREFIX = accessor_
unsigned int
accessor_num_layers(self)
struct fann * self;
CODE:
RETVAL = fann_get_num_layers(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN::TrainData PREFIX = accessor_
unsigned int
accessor_num_inputs(self)
struct fann_train_data * self;
CODE:
RETVAL = fann_train_data_num_input(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN::TrainData PREFIX = accessor_
unsigned int
accessor_num_outputs(self)
struct fann_train_data * self;
CODE:
RETVAL = fann_train_data_num_output(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
MODULE = AI::FANN PACKAGE = AI::FANN::TrainData PREFIX = accessor_
unsigned int
accessor_length(self)
struct fann_train_data * self;
CODE:
RETVAL = fann_train_data_length(self);
OUTPUT:
RETVAL
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
constants.h view on Meta::CPAN
static char * const my_constant_names[] = {
"FANN_TRAIN_INCREMENTAL",
"FANN_TRAIN_BATCH",
"FANN_TRAIN_RPROP",
"FANN_TRAIN_QUICKPROP",
"FANN_LINEAR",
"FANN_THRESHOLD",
"FANN_THRESHOLD_SYMMETRIC",
"FANN_SIGMOID",
"FANN_SIGMOID_STEPWISE",
"FANN_SIGMOID_SYMMETRIC",
"FANN_SIGMOID_SYMMETRIC_STEPWISE",
"FANN_GAUSSIAN",
"FANN_GAUSSIAN_SYMMETRIC",
"FANN_GAUSSIAN_STEPWISE",
"FANN_ELLIOT",
"FANN_ELLIOT_SYMMETRIC",
"FANN_LINEAR_PIECE",
"FANN_LINEAR_PIECE_SYMMETRIC",
"FANN_SIN_SYMMETRIC",
"FANN_COS_SYMMETRIC",
"FANN_SIN",
"FANN_COS",
"FANN_ERRORFUNC_LINEAR",
"FANN_ERRORFUNC_TANH",
"FANN_STOPFUNC_MSE",
"FANN_STOPFUNC_BIT",
0,
};
static const unsigned int my_constant_values[] = {
FANN_TRAIN_INCREMENTAL,
FANN_TRAIN_BATCH,
FANN_TRAIN_RPROP,
FANN_TRAIN_QUICKPROP,
FANN_LINEAR,
FANN_THRESHOLD,
FANN_THRESHOLD_SYMMETRIC,
FANN_SIGMOID,
FANN_SIGMOID_STEPWISE,
FANN_SIGMOID_SYMMETRIC,
FANN_SIGMOID_SYMMETRIC_STEPWISE,
FANN_GAUSSIAN,
FANN_GAUSSIAN_SYMMETRIC,
FANN_GAUSSIAN_STEPWISE,
FANN_ELLIOT,
FANN_ELLIOT_SYMMETRIC,
FANN_LINEAR_PIECE,
FANN_LINEAR_PIECE_SYMMETRIC,
FANN_SIN_SYMMETRIC,
FANN_COS_SYMMETRIC,
FANN_SIN,
FANN_COS,
FANN_ERRORFUNC_LINEAR,
FANN_ERRORFUNC_TANH,
FANN_STOPFUNC_MSE,
FANN_STOPFUNC_BIT,
};
genaccessors view on Meta::CPAN
#!/usr/bin/perl
use strict;
use warnings;
$| = 1;
my %struct = ( 'AI::FANN' => 'struct fann *',
'AI::FANN::TrainData' => 'struct fann_train_data *' );
sub accessor {
my ($name, $type, $getter, $setter, @ixs) = @_;
my ($package, $method) = $name =~ /^(?:(.*)::)?(.*)$/
or die "wrong accessor name $name";
$package = $package ? "AI::FANN::$package" : 'AI::FANN';
my $struct = $struct{$package}
or die "wrong package name $package";
push @ixs, 'value' unless grep /^value$/, @ixs;
my @ixs1 = grep !/^value$/, @ixs;
my $nixs = @ixs;
my $types = join("\n ", "$struct self;", map "unsigned int $_;", @ixs1);
my $args = join(', ', 'self', @ixs1);
my $setargs = join(', ', 'self', @ixs);
if ($getter) {
if ($getter =~ /^->/) {
$getter = "self->$getter"
}
else {
$getter = "$getter($args)"
}
}
if ($setter) {
if ($setter =~ /^->/) {
$setter = "self->$setter = value"
}
else {
$setter = "$setter($setargs)"
}
}
print <<HEAD;
MODULE = AI::FANN PACKAGE = $package PREFIX = accessor_
HEAD
if ($setter and $getter) {
print <<EOA
$type
accessor_$method($args, value = NO_INIT)
$types
$type value
CODE:
if (items > $nixs) {
$setter;
}
RETVAL = $getter;
OUTPUT:
RETVAL
EOA
}
elsif ($getter) {
print <<EOA;
$type
accessor_$method($args)
$types
CODE:
RETVAL = $getter;
OUTPUT:
RETVAL
EOA
}
elsif ($setter) {
print <<EOA;
void
accessor_$method($args, value)
$types
$type value;
CODE:
$setter;
EOA
}
else {
die "both setter and getter are null"
}
print <<EOA;
CLEANUP:
_check_error(aTHX_ (struct fann_error *)self);
EOA
}
while(<DATA>) {
chomp;
next if /^\s*(?:#.*)?$/;
my (@args) = split /\s*,\s*/;
@args > 2 or die "wrong number of arguments: $_";
accessor(@args);
}
__DATA__
training_algorithm, enum fann_train_enum, fann_get_training_algorithm, fann_set_training_algorithm
train_error_function, enum fann_errorfunc_enum, fann_get_train_error_function, fann_set_train_error_function
train_stop_function, enum fann_stopfunc_enum, fann_get_train_stop_function, fann_set_train_stop_function
learning_rate, double, fann_get_learning_rate, fann_set_learning_rate
learning_momentum, double, fann_get_learning_momentum, fann_set_learning_momentum
bit_fail_limit, fann_type, fann_get_bit_fail_limit, fann_set_bit_fail_limit
genconstants view on Meta::CPAN
#!/usr/bin/perl
my @names;
while(<DATA>) {
chomp;
next if /^\s*(?:#.*)?$/;
push @names, $_
}
my $n = @names;
my $n2 = $n*2;
print "static char * const my_constant_names[] = {\n";
for (@names) {
print qq( "$_",\n)
}
print qq( 0,\n);
print "};\n";
print "static const unsigned int my_constant_values[] = {\n";
for (@names) {
print qq( $_,\n)
}
print "};\n";
__DATA__
# enum fann_train_enum:
FANN_TRAIN_INCREMENTAL
FANN_TRAIN_BATCH
FANN_TRAIN_RPROP
FANN_TRAIN_QUICKPROP
lib/AI/FANN.pm view on Meta::CPAN
use strict;
use warnings;
use Carp;
require XSLoader;
XSLoader::load('AI::FANN', $VERSION);
use Exporter qw(import);
{
my @constants = _constants();
our %EXPORT_TAGS = ( 'all' => [ @constants ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
require constant;
for my $constant (@constants) {
constant->import($constant, $constant);
}
}
sub num_neurons {
@_ == 1 or croak "Usage: AI::FANN::get_neurons(self)";
my $self = shift;
if (wantarray) {
map { $self->layer_num_neurons($_) } (0 .. $self->num_layers - 1);
}
else {
$self->total_neurons;
}
}
1;
__END__
=head1 NAME
AI::FANN - Perl wrapper for the Fast Artificial Neural Network library
=head1 SYNOPSIS
Train...
use AI::FANN qw(:all);
# create an ANN with 2 inputs, a hidden layer with 3 neurons and an
# output layer with 1 neuron:
my $ann = AI::FANN->new_standard(2, 3, 1);
$ann->hidden_activation_function(FANN_SIGMOID_SYMMETRIC);
$ann->output_activation_function(FANN_SIGMOID_SYMMETRIC);
# create the training data for a XOR operator:
my $xor_train = AI::FANN::TrainData->new( [-1, -1], [-1],
[-1, 1], [1],
[1, -1], [1],
[1, 1], [-1] );
$ann->train_on_data($xor_train, 500000, 1000, 0.001);
$ann->save("xor.ann");
Run...
use AI::FANN;
my $ann = AI::FANN->new_from_file("xor.ann");
for my $a (-1, 1) {
for my $b (-1, 1) {
my $out = $ann->run([$a, $b]);
printf "xor(%f, %f) = %f\n", $a, $b, $out->[0];
}
}
=head1 DESCRIPTION
WARNING: THIS IS A VERY EARLY RELEASE,
MAY CONTAIN CRITICAL BUGS!!!
AI::FANN is a Perl wrapper for the Fast Artificial Neural Network
(FANN) Library available from L<http://fann.sourceforge.net>:
Fast Artificial Neural Network Library is a free open source neural
network library, which implements multilayer artificial neural
networks in C with support for both fully connected and sparsely
connected networks. Cross-platform execution in both fixed and
floating point are supported. It includes a framework for easy
handling of training data sets. It is easy to use, versatile, well
documented, and fast. PHP, C++, .NET, Python, Delphi, Octave, Ruby,
Pure Data and Mathematica bindings are available. A reference manual
accompanies the library with examples and recommendations on how to
use the library. A graphical user interface is also available for
the library.
AI::FANN object oriented interface provides an almost direct map to
the C library API. Some differences have been introduced to make it
more perlish:
=over 4
=item *
Two classes are used: C<AI::FANN> that wraps the C C<struct fann> type
and C<AI::FANN::TrainData> that wraps C<struct fann_train_data>.
=item *
Prefixes and common parts on the C function names referring to those
structures have been removed. For instance C
C<fann_train_data_shuffle> becomes C<AI::FANN::TrainData::shuffle> that
will be usually called as...
$train_data->shuffle;
=item *
Pairs of C get/set functions are wrapped in Perl with dual accessor
methods named as the attribute (and without any C<set_>/C<get_>
prefix). For instance:
$ann->bit_fail_limit($limit); # sets the bit_fail_limit
$bfl = $ann->bit_fail_limit; # gets the bit_fail_limit
Pairs of get/set functions requiring additional indexing arguments are
also wrapped inside dual accessors:
# sets:
$ann->neuron_activation_function($layer_ix, $neuron_ix, $actfunc);
# gets:
$af = $ann->neuron_activation_function($layer_ix, $neuron_ix);
Important: note that on the Perl version, the optional value argument
is moved to the last position (on the C version of the C<set_> method
it is usually the second argument).
=item *
Some functions have been renamed to make the naming more consistent
and to follow Perl conventions:
C Perl
-----------------------------------------------------------
fann_create_from_file => new_from_file
fann_create_standard => new_standard
fann_get_num_input => num_inputs
fann_get_activation_function => neuron_activation_function
fann_set_activation_function => ^^^
fann_set_activation_function_layer => layer_activation_function
fann_set_activation_function_hidden => hidden_activation_function
fann_set_activation_function_output => output_activation_function
=item *
Boolean methods return true on success and undef on failure.
=item *
Any error reported from the C side is automaticaly converter to a Perl
exception. No manual error checking is required after calling FANN
functions.
lib/AI/FANN.pm view on Meta::CPAN
Doubles are used for computations (using floats or fixed
point types is not supported).
=back
=head1 CONSTANTS
All the constants defined in the C documentation are exported from the module:
# import all...
use AI::FANN ':all';
# or individual constants...
use AI::FANN qw(FANN_TRAIN_INCREMENTAL FANN_GAUSSIAN);
The values returned from this constant subs yield the integer value on
numerical context and the constant name when used as strings.
The constants available are:
# enum fann_train_enum:
FANN_TRAIN_INCREMENTAL
FANN_TRAIN_BATCH
FANN_TRAIN_RPROP
FANN_TRAIN_QUICKPROP
# enum fann_activationfunc_enum:
FANN_LINEAR
FANN_THRESHOLD
FANN_THRESHOLD_SYMMETRIC
FANN_SIGMOID
FANN_SIGMOID_STEPWISE
FANN_SIGMOID_SYMMETRIC
FANN_SIGMOID_SYMMETRIC_STEPWISE
FANN_GAUSSIAN
FANN_GAUSSIAN_SYMMETRIC
FANN_GAUSSIAN_STEPWISE
FANN_ELLIOT
FANN_ELLIOT_SYMMETRIC
FANN_LINEAR_PIECE
FANN_LINEAR_PIECE_SYMMETRIC
FANN_SIN_SYMMETRIC
FANN_COS_SYMMETRIC
FANN_SIN
FANN_COS
# enum fann_errorfunc_enum:
FANN_ERRORFUNC_LINEAR
FANN_ERRORFUNC_TANH
# enum fann_stopfunc_enum:
FANN_STOPFUNC_MSE
FANN_STOPFUNC_BIT
=head1 CLASSES
The classes defined by this package are:
=head2 AI::FANN
Wraps C C<struct fann> types and provides the following methods
(consult the C documentation for a full description of their usage):
lib/AI/FANN.pm view on Meta::CPAN
=item $ann->save($filename)
-
=item $ann->run($input)
C<input> is an array with the input values.
returns an array with the values on the output layer.
$out = $ann->run([1, 0.6]);
print "@$out\n";
=item $ann->randomize_weights($min_weight, $max_weight)
=item $ann->train($input, $desired_output)
C<$input> and C<$desired_output> are arrays.
=item $ann->test($input, $desired_output)
C<$input> and C<$desired_output> are arrays.
#include "morefann.h"
#include <string.h>
static fann_type **allocvv(unsigned int n1, unsigned int n2) {
fann_type **ptr = (fann_type **)malloc(n1 * sizeof(fann_type *));
fann_type *v = (fann_type *)malloc(n1 * n2 * sizeof(fann_type));
if (ptr && v) {
unsigned int i;
for (i = 0; i < n1; i++) {
ptr[i] = v + i * n2;
}
return ptr;
}
return 0;
}
struct fann_train_data *
fann_train_data_create(unsigned int num_data, unsigned int num_input, unsigned int num_output) {
struct fann_train_data *data = (struct fann_train_data *)calloc(1, sizeof(*data));
if (data) {
fann_init_error_data((struct fann_error *)data);
data->input = allocvv(num_data, num_input);
data->output = allocvv(num_data, num_output);
if (data->input && data->output) {
data->num_data = num_data;
data->num_input = num_input;
data->num_output = num_output;
return data;
}
}
return 0;
}
void
fann_train_data_set(struct fann_train_data *data, unsigned int ix,
fann_type *input, fann_type *output ) {
if (ix < data->num_data) {
memcpy(data->input[ix], input, data->num_input * sizeof(fann_type));
memcpy(data->output[ix], output, data->num_output * sizeof(fann_type));
}
else {
fann_error((struct fann_error *)data, FANN_E_INDEX_OUT_OF_BOUND, ix);
}
}
/*
enum fann_activationfunc_enum
fann_get_activation_function(struct fann *ann, unsigned int layer, int neuron_index) {
struct fann_neuron *neuron = fann_get_neuron(ann, layer, neuron_index);
if (neuron) {
return neuron->activation_function;
}
return 0;
}
*/
/*
fann_type
fann_get_activation_steepness(struct fann *ann, unsigned int layer, int neuron_index) {
struct fann_neuron *neuron = fann_get_neuron(ann, layer, neuron_index);
if (neuron) {
return neuron->activation_steepness;
}
return 0;
}
*/
/*
unsigned int
fann_get_num_layers(struct fann *ann) {
return ann->last_layer - ann->first_layer;
}
*/
unsigned int
fann_get_num_neurons(struct fann *ann, unsigned int layer_index) {
struct fann_layer * layer = fann_get_layer(ann, layer_index);
if (layer) {
return layer->last_neuron - layer->first_neuron;
}
return 0;
}
#include <doublefann.h>
void
fann_train_data_set(struct fann_train_data *data, unsigned int ix,
fann_type *input, fann_type *output );
struct fann_train_data *
fann_train_data_create(unsigned int num_data,
unsigned int num_input, unsigned int num_output);
struct fann_layer*
fann_get_layer(struct fann *ann, int layer);
struct fann_neuron*
fann_get_neuron_layer(struct fann *ann, struct fann_layer* layer, int neuron);
struct fann_neuron*
fann_get_neuron(struct fann *ann, unsigned int layer, int neuron);
#if 0
<<'SKIP';
#endif
/*
----------------------------------------------------------------------
ppport.h -- Perl/Pollution/Portability Version 3.13
Automatically created by Devel::PPPort running under perl 5.010000.
Do NOT edit this file directly! -- Edit PPPort_pm.PL and the
includes in parts/inc/ instead.
Use 'perldoc ppport.h' to view the documentation below.
----------------------------------------------------------------------
SKIP
=pod
=head1 NAME
ppport.h - Perl/Pollution/Portability version 3.13
=head1 SYNOPSIS
perl ppport.h [options] [source files]
Searches current directory for files if no [source files] are given
--help show short help
--version show version
--patch=file write one patch file with changes
--copy=suffix write changed copies with suffix
--diff=program use diff program and options
--compat-version=version provide compatibility with Perl version
--cplusplus accept C++ comments
--quiet don't output anything except fatal errors
--nodiag don't show diagnostics
--nohints don't show hints
--nochanges don't suggest changes
--nofilter don't filter input files
--strip strip all script and doc functionality from
ppport.h
--list-provided list provided API
--list-unsupported list unsupported API
--api-info=name show Perl API portability information
=head1 COMPATIBILITY
This version of F<ppport.h> is designed to support operation with Perl
installations back to 5.003, and has been tested up to 5.10.0.
=head1 OPTIONS
=head2 --help
across differing versions of Perl itself, certain steps need to be taken.
=over 4
=item *
Including this header is the first major one. This alone will give you
access to a large part of the Perl API that hasn't been available in
earlier Perl releases. Use
perl ppport.h --list-provided
to see which API elements are provided by ppport.h.
=item *
You should avoid using deprecated parts of the API. For example, using
global Perl variables without the C<PL_> prefix is deprecated. Also,
some API functions used to have a C<perl_> prefix. Using this form is
also deprecated. You can safely use the supported API, as F<ppport.h>
will provide wrappers for older Perl versions.
These functions or variables will be marked C<explicit> in the list shown
by C<--list-provided>.
Depending on whether you module has a single or multiple files that
use such functions or variables, you want either C<static> or global
variants.
For a C<static> function or variable (used only in a single source
file), use:
#define NEED_function
#define NEED_variable
For a global function or variable (used in multiple source files),
use:
#define NEED_function_GLOBAL
#define NEED_variable_GLOBAL
Note that you mustn't have more than one global request for the
same function or variable in your project.
Function / Variable Static Request Global Request
-----------------------------------------------------------------------------------------
PL_signals NEED_PL_signals NEED_PL_signals_GLOBAL
eval_pv() NEED_eval_pv NEED_eval_pv_GLOBAL
grok_bin() NEED_grok_bin NEED_grok_bin_GLOBAL
grok_hex() NEED_grok_hex NEED_grok_hex_GLOBAL
grok_number() NEED_grok_number NEED_grok_number_GLOBAL
grok_numeric_radix() NEED_grok_numeric_radix NEED_grok_numeric_radix_GLOBAL
grok_oct() NEED_grok_oct NEED_grok_oct_GLOBAL
load_module() NEED_load_module NEED_load_module_GLOBAL
my_snprintf() NEED_my_snprintf NEED_my_snprintf_GLOBAL
my_strlcat() NEED_my_strlcat NEED_my_strlcat_GLOBAL
my_strlcpy() NEED_my_strlcpy NEED_my_strlcpy_GLOBAL
newCONSTSUB() NEED_newCONSTSUB NEED_newCONSTSUB_GLOBAL
newRV_noinc() NEED_newRV_noinc NEED_newRV_noinc_GLOBAL
newSVpvn_share() NEED_newSVpvn_share NEED_newSVpvn_share_GLOBAL
sv_2pv_flags() NEED_sv_2pv_flags NEED_sv_2pv_flags_GLOBAL
sv_2pvbyte() NEED_sv_2pvbyte NEED_sv_2pvbyte_GLOBAL
sv_catpvf_mg() NEED_sv_catpvf_mg NEED_sv_catpvf_mg_GLOBAL
sv_catpvf_mg_nocontext() NEED_sv_catpvf_mg_nocontext NEED_sv_catpvf_mg_nocontext_GLOBAL
sv_pvn_force_flags() NEED_sv_pvn_force_flags NEED_sv_pvn_force_flags_GLOBAL
sv_setpvf_mg() NEED_sv_setpvf_mg NEED_sv_setpvf_mg_GLOBAL
sv_setpvf_mg_nocontext() NEED_sv_setpvf_mg_nocontext NEED_sv_setpvf_mg_nocontext_GLOBAL
vload_module() NEED_vload_module NEED_vload_module_GLOBAL
vnewSVpvf() NEED_vnewSVpvf NEED_vnewSVpvf_GLOBAL
warner() NEED_warner NEED_warner_GLOBAL
To avoid namespace conflicts, you can change the namespace of the
explicitly exported functions / variables using the C<DPPP_NAMESPACE>
macro. Just C<#define> the macro before including C<ppport.h>:
#define DPPP_NAMESPACE MyOwnNamespace_
#include "ppport.h"
The default namespace is C<DPPP_>.
=back
The good thing is that most of the above can be checked by running
F<ppport.h> on your source code. See the next section for
details.
=head1 EXAMPLES
To verify whether F<ppport.h> is needed for your module, whether you
should make any changes to your code, and whether any special defines
should be used, F<ppport.h> can be run as a Perl script to check your
source code. Simply say:
perl ppport.h
The result will usually be a list of patches suggesting changes
that should at least be acceptable, if not necessarily the most
efficient solution, or a fix for all possible problems.
If you know that your XS module uses features only available in
newer Perl releases, if you're aware that it uses C++ comments,
and if you want all suggestions as a single patch file, you could
use something like this:
perl ppport.h --compat-version=5.6.0 --cplusplus --patch=test.diff
If you only want your code to be scanned without any suggestions
for changes, use:
perl ppport.h --nochanges
You can specify a different C<diff> program or options, using
the C<--diff> option:
perl ppport.h --diff='diff -C 10'
This would output context diffs with 10 lines of context.
If you want to create patched copies of your files instead, use:
perl ppport.h --copy=.new
To display portability information for the C<newSVpvn> function,
use:
perl ppport.h --api-info=newSVpvn
Since the argument to C<--api-info> can be a regular expression,
you can use
perl ppport.h --api-info=/_nomg$/
to display portability information for all C<_nomg> functions or
perl ppport.h --api-info=/./
to display information for all known API elements.
=head1 BUGS
If this version of F<ppport.h> is causing failure during
the compilation of this module, please check if newer versions
of either this module or C<Devel::PPPort> are available on CPAN
before sending a bug report.
=cut
use strict;
# Disable broken TRIE-optimization
BEGIN { eval '${^RE_TRIE_MAXBUF} = -1' if $] >= 5.009004 && $] <= 5.009005 }
my $VERSION = 3.13;
my %opt = (
quiet => 0,
diag => 1,
hints => 1,
changes => 1,
cplusplus => 0,
filter => 1,
strip => 0,
version => 0,
);
my($ppport) = $0 =~ /([\w.]+)$/;
my $LF = '(?:\r\n|[\r\n])'; # line feed
my $HS = "[ \t]"; # horizontal whitespace
# Never use C comments in this file!
my $ccs = '/'.'*';
my $cce = '*'.'/';
my $rccs = quotemeta $ccs;
my $rcce = quotemeta $cce;
eval {
require Getopt::Long;
Getopt::Long::GetOptions(\%opt, qw(
help quiet diag! filter! hints! changes! cplusplus strip version
patch=s copy=s diff=s compat-version=s
list-provided list-unsupported api-info=s
)) or usage();
};
if ($@ and grep /^-/, @ARGV) {
usage() if "@ARGV" =~ /^--?h(?:elp)?$/;
die "Getopt::Long not found. Please don't use any options.\n";
}
if ($opt{version}) {
print "This is $0 $VERSION.\n";
exit 0;
}
usage() if $opt{help};
strip() if $opt{strip};
if (exists $opt{'compat-version'}) {
my($r,$v,$s) = eval { parse_version($opt{'compat-version'}) };
if ($@) {
die "Invalid version number format: '$opt{'compat-version'}'\n";
}
die "Only Perl 5 is supported\n" if $r != 5;
die "Invalid version number: $opt{'compat-version'}\n" if $v >= 1000 || $s >= 1000;
$opt{'compat-version'} = sprintf "%d.%03d%03d", $r, $v, $s;
}
else {
$opt{'compat-version'} = 5;
}
my %API = map { /^(\w+)\|([^|]*)\|([^|]*)\|(\w*)$/
? ( $1 => {
($2 ? ( base => $2 ) : ()),
($3 ? ( todo => $3 ) : ()),
(index($4, 'v') >= 0 ? ( varargs => 1 ) : ()),
(index($4, 'p') >= 0 ? ( provided => 1 ) : ()),
(index($4, 'n') >= 0 ? ( nothxarg => 1 ) : ()),
} )
: die "invalid spec: $_" } qw(
AvFILLp|5.004050||p
AvFILL|||
CLASS|||n
CX_CURPAD_SAVE|||
CX_CURPAD_SV|||
CopFILEAV|5.006000||p
CopFILEGV_set|5.006000||p
CopFILEGV|5.006000||p
CopFILESV|5.006000||p
CopFILE_set|5.006000||p
xmldump_packsubs|||
xmldump_sub|||
xmldump_vindent|||
yyerror|||
yylex|||
yyparse|||
yywarn|||
);
if (exists $opt{'list-unsupported'}) {
my $f;
for $f (sort { lc $a cmp lc $b } keys %API) {
next unless $API{$f}{todo};
print "$f ", '.'x(40-length($f)), " ", format_version($API{$f}{todo}), "\n";
}
exit 0;
}
# Scan for possible replacement candidates
my(%replace, %need, %hints, %warnings, %depends);
my $replace = 0;
my($hint, $define, $function);
sub find_api
{
my $code = shift;
$code =~ s{
/ (?: \*[^*]*\*+(?:[^$ccs][^*]*\*+)* / | /[^\r\n]*)
| "[^"\\]*(?:\\.[^"\\]*)*"
| '[^'\\]*(?:\\.[^'\\]*)*' }{}egsx;
grep { exists $API{$_} } $code =~ /(\w+)/mg;
}
while (<DATA>) {
if ($hint) {
my $h = $hint->[0] eq 'Hint' ? \%hints : \%warnings;
if (m{^\s*\*\s(.*?)\s*$}) {
for (@{$hint->[1]}) {
$h->{$_} ||= ''; # suppress warning with older perls
$h->{$_} .= "$1\n";
}
}
else { undef $hint }
}
$hint = [$1, [split /,?\s+/, $2]]
if m{^\s*$rccs\s+(Hint|Warning):\s+(\w+(?:,?\s+\w+)*)\s*$};
if ($define) {
if ($define->[1] =~ /\\$/) {
$define->[1] .= $_;
}
else {
if (exists $API{$define->[0]} && $define->[1] !~ /^DPPP_\(/) {
my @n = find_api($define->[1]);
push @{$depends{$define->[0]}}, @n if @n
}
undef $define;
}
}
$define = [$1, $2] if m{^\s*#\s*define\s+(\w+)(?:\([^)]*\))?\s+(.*)};
if ($function) {
if (/^}/) {
if (exists $API{$function->[0]}) {
my @n = find_api($function->[1]);
push @{$depends{$function->[0]}}, @n if @n
}
undef $define;
}
else {
$function->[1] .= $_;
}
}
$function = [$1, ''] if m{^DPPP_\(my_(\w+)\)};
$replace = $1 if m{^\s*$rccs\s+Replace:\s+(\d+)\s+$rcce\s*$};
$replace{$2} = $1 if $replace and m{^\s*#\s*define\s+(\w+)(?:\([^)]*\))?\s+(\w+)};
$replace{$2} = $1 if m{^\s*#\s*define\s+(\w+)(?:\([^)]*\))?\s+(\w+).*$rccs\s+Replace\s+$rcce};
$replace{$1} = $2 if m{^\s*$rccs\s+Replace (\w+) with (\w+)\s+$rcce\s*$};
if (m{^\s*$rccs\s+(\w+)\s+depends\s+on\s+(\w+(\s*,\s*\w+)*)\s+$rcce\s*$}) {
push @{$depends{$1}}, map { s/\s+//g; $_ } split /,/, $2;
}
$need{$1} = 1 if m{^#if\s+defined\(NEED_(\w+)(?:_GLOBAL)?\)};
}
for (values %depends) {
my %s;
$_ = [sort grep !$s{$_}++, @$_];
}
if (exists $opt{'api-info'}) {
my $f;
my $count = 0;
my $match = $opt{'api-info'} =~ m!^/(.*)/$! ? $1 : "^\Q$opt{'api-info'}\E\$";
for $f (sort { lc $a cmp lc $b } keys %API) {
next unless $f =~ /$match/;
print "\n=== $f ===\n\n";
my $info = 0;
if ($API{$f}{base} || $API{$f}{todo}) {
my $base = format_version($API{$f}{base} || $API{$f}{todo});
print "Supported at least starting from perl-$base.\n";
$info++;
}
if ($API{$f}{provided}) {
my $todo = $API{$f}{todo} ? format_version($API{$f}{todo}) : "5.003";
print "Support by $ppport provided back to perl-$todo.\n";
print "Support needs to be explicitly requested by NEED_$f.\n" if exists $need{$f};
print "Depends on: ", join(', ', @{$depends{$f}}), ".\n" if exists $depends{$f};
print "\n$hints{$f}" if exists $hints{$f};
print "\nWARNING:\n$warnings{$f}" if exists $warnings{$f};
$info++;
}
print "No portability information available.\n" unless $info;
$count++;
}
$count or print "Found no API matching '$opt{'api-info'}'.";
print "\n";
exit 0;
}
if (exists $opt{'list-provided'}) {
my $f;
for $f (sort { lc $a cmp lc $b } keys %API) {
next unless $API{$f}{provided};
my @flags;
push @flags, 'explicit' if exists $need{$f};
push @flags, 'depend' if exists $depends{$f};
push @flags, 'hint' if exists $hints{$f};
push @flags, 'warning' if exists $warnings{$f};
my $flags = @flags ? ' ['.join(', ', @flags).']' : '';
print "$f$flags\n";
}
exit 0;
}
my @files;
my @srcext = qw( .xs .c .h .cc .cpp -c.inc -xs.inc );
my $srcext = join '|', map { quotemeta $_ } @srcext;
if (@ARGV) {
my %seen;
for (@ARGV) {
if (-e) {
if (-f) {
push @files, $_ unless $seen{$_}++;
}
else { warn "'$_' is not a file.\n" }
}
else {
my @new = grep { -f } glob $_
or warn "'$_' does not exist.\n";
push @files, grep { !$seen{$_}++ } @new;
}
}
}
else {
eval {
require File::Find;
File::Find::find(sub {
$File::Find::name =~ /($srcext)$/i
and push @files, $File::Find::name;
}, '.');
};
if ($@) {
@files = map { glob "*$_" } @srcext;
}
}
if (!@ARGV || $opt{filter}) {
my(@in, @out);
my %xsc = map { /(.*)\.xs$/ ? ("$1.c" => 1, "$1.cc" => 1) : () } @files;
for (@files) {
my $out = exists $xsc{$_} || /\b\Q$ppport\E$/i || !/($srcext)$/i;
push @{ $out ? \@out : \@in }, $_;
}
if (@ARGV && @out) {
warning("Skipping the following files (use --nofilter to avoid this):\n| ", join "\n| ", @out);
}
@files = @in;
}
die "No input files given!\n" unless @files;
my(%files, %global, %revreplace);
%revreplace = reverse %replace;
my $filename;
my $patch_opened = 0;
for $filename (@files) {
unless (open IN, "<$filename") {
warn "Unable to read from $filename: $!\n";
next;
}
info("Scanning $filename ...");
my $c = do { local $/; <IN> };
close IN;
my %file = (orig => $c, changes => 0);
# Temporarily remove C/XS comments and strings from the code
my @ccom;
$c =~ s{
( ^$HS*\#$HS*include\b[^\r\n]+\b(?:\Q$ppport\E|XSUB\.h)\b[^\r\n]*
| ^$HS*\#$HS*(?:define|elif|if(?:def)?)\b[^\r\n]* )
| ( ^$HS*\#[^\r\n]*
| "[^"\\]*(?:\\.[^"\\]*)*"
| '[^'\\]*(?:\\.[^'\\]*)*'
| / (?: \*[^*]*\*+(?:[^$ccs][^*]*\*+)* / | /[^\r\n]* ) )
}{ defined $2 and push @ccom, $2;
defined $1 ? $1 : "$ccs$#ccom$cce" }mgsex;
$file{ccom} = \@ccom;
$file{code} = $c;
$file{has_inc_ppport} = $c =~ /^$HS*#$HS*include[^\r\n]+\b\Q$ppport\E\b/m;
my $func;
for $func (keys %API) {
my $match = $func;
$match .= "|$revreplace{$func}" if exists $revreplace{$func};
if ($c =~ /\b(?:Perl_)?($match)\b/) {
$file{uses_replace}{$1}++ if exists $revreplace{$func} && $1 eq $revreplace{$func};
$file{uses_Perl}{$func}++ if $c =~ /\bPerl_$func\b/;
if (exists $API{$func}{provided}) {
$file{uses_provided}{$func}++;
if (!exists $API{$func}{base} || $API{$func}{base} > $opt{'compat-version'}) {
$file{uses}{$func}++;
my @deps = rec_depend($func);
if (@deps) {
$file{uses_deps}{$func} = \@deps;
for (@deps) {
$file{uses}{$_} = 0 unless exists $file{uses}{$_};
}
}
for ($func, @deps) {
$file{needs}{$_} = 'static' if exists $need{$_};
}
}
}
if (exists $API{$func}{todo} && $API{$func}{todo} > $opt{'compat-version'}) {
if ($c =~ /\b$func\b/) {
$file{uses_todo}{$func}++;
}
}
}
}
while ($c =~ /^$HS*#$HS*define$HS+(NEED_(\w+?)(_GLOBAL)?)\b/mg) {
if (exists $need{$2}) {
$file{defined $3 ? 'needed_global' : 'needed_static'}{$2}++;
}
else { warning("Possibly wrong #define $1 in $filename") }
}
for (qw(uses needs uses_todo needed_global needed_static)) {
for $func (keys %{$file{$_}}) {
push @{$global{$_}{$func}}, $filename;
}
}
$files{$filename} = \%file;
}
# Globally resolve NEED_'s
my $need;
for $need (keys %{$global{needs}}) {
if (@{$global{needs}{$need}} > 1) {
my @targets = @{$global{needs}{$need}};
my @t = grep $files{$_}{needed_global}{$need}, @targets;
@targets = @t if @t;
@t = grep /\.xs$/i, @targets;
@targets = @t if @t;
my $target = shift @targets;
$files{$target}{needs}{$need} = 'global';
for (@{$global{needs}{$need}}) {
$files{$_}{needs}{$need} = 'extern' if $_ ne $target;
}
}
}
for $filename (@files) {
exists $files{$filename} or next;
info("=== Analyzing $filename ===");
my %file = %{$files{$filename}};
my $func;
my $c = $file{code};
my $warnings = 0;
for $func (sort keys %{$file{uses_Perl}}) {
if ($API{$func}{varargs}) {
unless ($API{$func}{nothxarg}) {
my $changes = ($c =~ s{\b(Perl_$func\s*\(\s*)(?!aTHX_?)(\)|[^\s)]*\))}
{ $1 . ($2 eq ')' ? 'aTHX' : 'aTHX_ ') . $2 }ge);
if ($changes) {
warning("Doesn't pass interpreter argument aTHX to Perl_$func");
$file{changes} += $changes;
}
}
}
else {
warning("Uses Perl_$func instead of $func");
$file{changes} += ($c =~ s{\bPerl_$func(\s*)\((\s*aTHX_?)?\s*}
{$func$1(}g);
}
}
for $func (sort keys %{$file{uses_replace}}) {
warning("Uses $func instead of $replace{$func}");
$file{changes} += ($c =~ s/\b$func\b/$replace{$func}/g);
}
for $func (sort keys %{$file{uses_provided}}) {
if ($file{uses}{$func}) {
if (exists $file{uses_deps}{$func}) {
diag("Uses $func, which depends on ", join(', ', @{$file{uses_deps}{$func}}));
}
else {
diag("Uses $func");
}
}
$warnings += hint($func);
}
unless ($opt{quiet}) {
for $func (sort keys %{$file{uses_todo}}) {
print "*** WARNING: Uses $func, which may not be portable below perl ",
format_version($API{$func}{todo}), ", even with '$ppport'\n";
$warnings++;
}
}
for $func (sort keys %{$file{needed_static}}) {
my $message = '';
if (not exists $file{uses}{$func}) {
$message = "No need to define NEED_$func if $func is never used";
}
elsif (exists $file{needs}{$func} && $file{needs}{$func} ne 'static') {
$message = "No need to define NEED_$func when already needed globally";
}
if ($message) {
diag($message);
$file{changes} += ($c =~ s/^$HS*#$HS*define$HS+NEED_$func\b.*$LF//mg);
}
}
for $func (sort keys %{$file{needed_global}}) {
my $message = '';
if (not exists $global{uses}{$func}) {
$message = "No need to define NEED_${func}_GLOBAL if $func is never used";
}
elsif (exists $file{needs}{$func}) {
if ($file{needs}{$func} eq 'extern') {
$message = "No need to define NEED_${func}_GLOBAL when already needed globally";
}
elsif ($file{needs}{$func} eq 'static') {
$message = "No need to define NEED_${func}_GLOBAL when only used in this file";
}
}
if ($message) {
diag($message);
$file{changes} += ($c =~ s/^$HS*#$HS*define$HS+NEED_${func}_GLOBAL\b.*$LF//mg);
}
}
$file{needs_inc_ppport} = keys %{$file{uses}};
if ($file{needs_inc_ppport}) {
my $pp = '';
for $func (sort keys %{$file{needs}}) {
my $type = $file{needs}{$func};
next if $type eq 'extern';
my $suffix = $type eq 'global' ? '_GLOBAL' : '';
unless (exists $file{"needed_$type"}{$func}) {
if ($type eq 'global') {
diag("Files [@{$global{needs}{$func}}] need $func, adding global request");
}
else {
diag("File needs $func, adding static request");
}
$pp .= "#define NEED_$func$suffix\n";
}
}
if ($pp && ($c =~ s/^(?=$HS*#$HS*define$HS+NEED_\w+)/$pp/m)) {
$pp = '';
$file{changes}++;
}
unless ($file{has_inc_ppport}) {
diag("Needs to include '$ppport'");
$pp .= qq(#include "$ppport"\n)
}
if ($pp) {
$file{changes} += ($c =~ s/^($HS*#$HS*define$HS+NEED_\w+.*?)^/$1$pp/ms)
|| ($c =~ s/^(?=$HS*#$HS*include.*\Q$ppport\E)/$pp/m)
|| ($c =~ s/^($HS*#$HS*include.*XSUB.*\s*?)^/$1$pp/m)
|| ($c =~ s/^/$pp/);
}
}
else {
if ($file{has_inc_ppport}) {
diag("No need to include '$ppport'");
$file{changes} += ($c =~ s/^$HS*?#$HS*include.*\Q$ppport\E.*?$LF//m);
}
}
# put back in our C comments
my $ix;
my $cppc = 0;
my @ccom = @{$file{ccom}};
for $ix (0 .. $#ccom) {
if (!$opt{cplusplus} && $ccom[$ix] =~ s!^//!!) {
$cppc++;
$file{changes} += $c =~ s/$rccs$ix$rcce/$ccs$ccom[$ix] $cce/;
}
else {
$c =~ s/$rccs$ix$rcce/$ccom[$ix]/;
}
}
if ($cppc) {
my $s = $cppc != 1 ? 's' : '';
warning("Uses $cppc C++ style comment$s, which is not portable");
}
my $s = $warnings != 1 ? 's' : '';
my $warn = $warnings ? " ($warnings warning$s)" : '';
info("Analysis completed$warn");
if ($file{changes}) {
if (exists $opt{copy}) {
my $newfile = "$filename$opt{copy}";
if (-e $newfile) {
error("'$newfile' already exists, refusing to write copy of '$filename'");
}
else {
local *F;
if (open F, ">$newfile") {
info("Writing copy of '$filename' with changes to '$newfile'");
print F $c;
close F;
}
else {
error("Cannot open '$newfile' for writing: $!");
}
}
}
elsif (exists $opt{patch} || $opt{changes}) {
if (exists $opt{patch}) {
unless ($patch_opened) {
if (open PATCH, ">$opt{patch}") {
$patch_opened = 1;
}
else {
error("Cannot open '$opt{patch}' for writing: $!");
delete $opt{patch};
$opt{changes} = 1;
goto fallback;
}
}
mydiff(\*PATCH, $filename, $c);
}
else {
fallback:
info("Suggested changes:");
mydiff(\*STDOUT, $filename, $c);
}
}
else {
my $s = $file{changes} == 1 ? '' : 's';
info("$file{changes} potentially required change$s detected");
}
}
else {
info("Looks good");
}
}
close PATCH if $patch_opened;
exit 0;
sub try_use { eval "use @_;"; return $@ eq '' }
sub mydiff
{
local *F = shift;
my($file, $str) = @_;
my $diff;
if (exists $opt{diff}) {
$diff = run_diff($opt{diff}, $file, $str);
}
if (!defined $diff and try_use('Text::Diff')) {
$diff = Text::Diff::diff($file, \$str, { STYLE => 'Unified' });
$diff = <<HEADER . $diff;
--- $file
+++ $file.patched
HEADER
}
if (!defined $diff) {
$diff = run_diff('diff -u', $file, $str);
}
if (!defined $diff) {
$diff = run_diff('diff', $file, $str);
}
if (!defined $diff) {
error("Cannot generate a diff. Please install Text::Diff or use --copy.");
return;
}
print F $diff;
}
sub run_diff
{
my($prog, $file, $str) = @_;
my $tmp = 'dppptemp';
my $suf = 'aaa';
my $diff = '';
local *F;
while (-e "$tmp.$suf") { $suf++ }
$tmp = "$tmp.$suf";
if (open F, ">$tmp") {
print F $str;
close F;
if (open F, "$prog $file $tmp |") {
while (<F>) {
s/\Q$tmp\E/$file.patched/;
$diff .= $_;
}
close F;
unlink $tmp;
return $diff;
}
unlink $tmp;
}
else {
error("Cannot open '$tmp' for writing: $!");
}
return undef;
}
sub rec_depend
{
my($func, $seen) = @_;
return () unless exists $depends{$func};
$seen = {%{$seen||{}}};
return () if $seen->{$func}++;
my %s;
grep !$s{$_}++, map { ($_, rec_depend($_, $seen)) } @{$depends{$func}};
}
sub parse_version
{
my $ver = shift;
if ($ver =~ /^(\d+)\.(\d+)\.(\d+)$/) {
return ($1, $2, $3);
}
elsif ($ver !~ /^\d+\.[\d_]+$/) {
die "cannot parse version '$ver'\n";
}
$ver =~ s/_//g;
$ver =~ s/$/000000/;
my($r,$v,$s) = $ver =~ /(\d+)\.(\d{3})(\d{3})/;
$v = int $v;
$s = int $s;
if ($r < 5 || ($r == 5 && $v < 6)) {
if ($s % 10) {
die "cannot parse version '$ver'\n";
}
}
return ($r, $v, $s);
}
sub format_version
{
my $ver = shift;
$ver =~ s/$/000000/;
my($r,$v,$s) = $ver =~ /(\d+)\.(\d{3})(\d{3})/;
$v = int $v;
$s = int $s;
if ($r < 5 || ($r == 5 && $v < 6)) {
if ($s % 10) {
die "invalid version '$ver'\n";
}
$s /= 10;
$ver = sprintf "%d.%03d", $r, $v;
$s > 0 and $ver .= sprintf "_%02d", $s;
return $ver;
}
return sprintf "%d.%d.%d", $r, $v, $s;
}
sub info
{
$opt{quiet} and return;
print @_, "\n";
}
sub diag
{
$opt{quiet} and return;
$opt{diag} and print @_, "\n";
}
sub warning
{
$opt{quiet} and return;
print "*** ", @_, "\n";
}
sub error
{
print "*** ERROR: ", @_, "\n";
}
my %given_hints;
my %given_warnings;
sub hint
{
$opt{quiet} and return;
my $func = shift;
my $rv = 0;
if (exists $warnings{$func} && !$given_warnings{$func}++) {
my $warn = $warnings{$func};
$warn =~ s!^!*** !mg;
print "*** WARNING: $func\n", $warn;
$rv++;
}
if ($opt{hints} && exists $hints{$func} && !$given_hints{$func}++) {
my $hint = $hints{$func};
$hint =~ s/^/ /mg;
print " --- hint for $func ---\n", $hint;
}
$rv;
}
sub usage
{
my($usage) = do { local(@ARGV,$/)=($0); <> } =~ /^=head\d$HS+SYNOPSIS\s*^(.*?)\s*^=/ms;
my %M = ( 'I' => '*' );
$usage =~ s/^\s*perl\s+\S+/$^X $0/;
$usage =~ s/([A-Z])<([^>]+)>/$M{$1}$2$M{$1}/g;
print <<ENDUSAGE;
Usage: $usage
See perldoc $0 for details.
ENDUSAGE
exit 2;
}
sub strip
{
my $self = do { local(@ARGV,$/)=($0); <> };
my($copy) = $self =~ /^=head\d\s+COPYRIGHT\s*^(.*?)^=\w+/ms;
$copy =~ s/^(?=\S+)/ /gms;
$self =~ s/^$HS+Do NOT edit.*?(?=^-)/$copy/ms;
$self =~ s/^SKIP.*(?=^__DATA__)/SKIP
if (\@ARGV && \$ARGV[0] eq '--unstrip') {
eval { require Devel::PPPort };
\$@ and die "Cannot require Devel::PPPort, please install.\\n";
if (\$Devel::PPPort::VERSION < $VERSION) {
die "$0 was originally generated with Devel::PPPort $VERSION.\\n"
. "Your Devel::PPPort is only version \$Devel::PPPort::VERSION.\\n"
. "Please install a newer version, or --unstrip will not work.\\n";
}
Devel::PPPort::WriteFile(\$0);
exit 0;
}
print <<END;
Sorry, but this is a stripped version of \$0.
To be able to use its original script and doc functionality,
please try to regenerate this file using:
\$^X \$0 --unstrip
END
/ms;
my($pl, $c) = $self =~ /(.*^__DATA__)(.*)/ms;
$c =~ s{
/ (?: \*[^*]*\*+(?:[^$ccs][^*]*\*+)* / | /[^\r\n]*)
| ( "[^"\\]*(?:\\.[^"\\]*)*"
| '[^'\\]*(?:\\.[^'\\]*)*' )
| ($HS+) }{ defined $2 ? ' ' : ($1 || '') }gsex;
$c =~ s!\s+$!!mg;
$c =~ s!^$LF!!mg;
$c =~ s!^\s*#\s*!#!mg;
$c =~ s!^\s+!!mg;
open OUT, ">$0" or die "cannot strip $0: $!\n";
print OUT "$pl$c\n";
exit 0;
}
__DATA__
*/
#ifndef _P_P_PORTABILITY_H_
#define _P_P_PORTABILITY_H_
#ifndef DPPP_NAMESPACE
# define DPPP_NAMESPACE DPPP_
#ifndef PERL_REVISION
# if !defined(__PATCHLEVEL_H_INCLUDED__) && !(defined(PATCHLEVEL) && defined(SUBVERSION))
# define PERL_PATCHLEVEL_H_IMPLICIT
# include <patchlevel.h>
# endif
# if !(defined(PERL_VERSION) || (defined(SUBVERSION) && defined(PATCHLEVEL)))
# include <could_not_find_Perl_patchlevel.h>
# endif
# ifndef PERL_REVISION
# define PERL_REVISION (5)
/* Replace: 1 */
# define PERL_VERSION PATCHLEVEL
# define PERL_SUBVERSION SUBVERSION
/* Replace PERL_PATCHLEVEL with PERL_VERSION */
/* Replace: 0 */
# endif
#endif
#define _dpppDEC2BCD(dec) ((((dec)/100)<<8)|((((dec)%100)/10)<<4)|((dec)%10))
#define PERL_BCDVERSION ((_dpppDEC2BCD(PERL_REVISION)<<24)|(_dpppDEC2BCD(PERL_VERSION)<<12)|_dpppDEC2BCD(PERL_SUBVERSION))
/* It is very unlikely that anyone will try to use this with Perl 6
(or greater), but who knows.
*/
#if PERL_REVISION != 5
# error ppport.h only works with Perl version 5
#endif /* PERL_REVISION != 5 */
#ifdef I_LIMITS
# include <limits.h>
#endif
#ifndef PERL_UCHAR_MIN
# define PERL_UCHAR_MIN ((unsigned char)0)
#endif
#ifndef UVTYPE
# define UVTYPE unsigned IVTYPE
#endif
#ifndef UVSIZE
# define UVSIZE IVSIZE
#endif
#ifndef sv_setuv
# define sv_setuv(sv, uv) \
STMT_START { \
UV TeMpUv = uv; \
if (TeMpUv <= IV_MAX) \
sv_setiv(sv, TeMpUv); \
else \
sv_setnv(sv, (double)TeMpUv); \
} STMT_END
#endif
#ifndef newSVuv
# define newSVuv(uv) ((uv) <= IV_MAX ? newSViv((IV)uv) : newSVnv((NV)uv))
#endif
#ifndef sv_2uv
# define sv_2uv(sv) ((PL_Sv = (sv)), (UV) (SvNOK(PL_Sv) ? SvNV(PL_Sv) : sv_2nv(PL_Sv)))
#endif
#ifndef SvUVX
# define SvUVX(sv) ((UV)SvIVX(sv))
#ifndef SvUV
# define SvUV(sv) (SvIOK(sv) ? SvUVX(sv) : sv_2uv(sv))
#endif
#ifndef SvUVx
# define SvUVx(sv) ((PL_Sv = (sv)), SvUV(PL_Sv))
#endif
/* Hint: sv_uv
* Always use the SvUVx() macro instead of sv_uv().
*/
#ifndef sv_uv
# define sv_uv(sv) SvUVx(sv)
#endif
#if !defined(SvUOK) && defined(SvIOK_UV)
# define SvUOK(sv) SvIOK_UV(sv)
#endif
#ifndef XST_mUV
# define XST_mUV(i,v) (ST(i) = sv_2mortal(newSVuv(v)) )
#endif
/* Older perls (<=5.003) lack AvFILLp */
#ifndef AvFILLp
# define AvFILLp AvFILL
#endif
#ifndef ERRSV
# define ERRSV get_sv("@",FALSE)
#endif
#ifndef newSVpvn
# define newSVpvn(data,len) ((data) \
? ((len) ? newSVpv((data), (len)) : newSVpv("", 0)) \
: newSV(0))
#endif
/* Hint: gv_stashpvn
* This function's backport doesn't support the length parameter, but
* rather ignores it. Portability can only be ensured if the length
* parameter is used for speed reasons, but the length can always be
* correctly computed from the string argument.
*/
#ifndef gv_stashpvn
# define gv_stashpvn(str,len,create) gv_stashpv(str,create)
#endif
/* Replace: 1 */
#ifndef get_cv
# define get_cv perl_get_cv
#endif
#ifndef get_sv
#endif
#ifndef dITEMS
# define dITEMS I32 items = SP - MARK
#endif
#ifndef dXSTARG
# define dXSTARG SV * targ = sv_newmortal()
#endif
#ifndef dAXMARK
# define dAXMARK I32 ax = POPMARK; \
register SV ** const mark = PL_stack_base + ax++
#endif
#ifndef XSprePUSH
# define XSprePUSH (sp = PL_stack_base + ax - 1)
#endif
#if (PERL_BCDVERSION < 0x5005000)
# undef XSRETURN
# define XSRETURN(off) \
STMT_START { \
PL_stack_sp = PL_stack_base + ax + ((off) - 1); \
return; \
} STMT_END
#endif
#ifndef PERL_ABS
# define PERL_ABS(x) ((x) < 0 ? -(x) : (x))
#endif
#ifndef dVAR
# define dVAR dNOOP
#endif
#ifndef SVf
# define SVf "_"
#endif
#ifndef UTF8_MAXBYTES
# define UTF8_MAXBYTES UTF8_MAXLEN
#endif
#ifndef PERL_HASH
# define PERL_HASH(hash,str,len) \
STMT_START { \
const char *s_PeRlHaSh = str; \
I32 i_PeRlHaSh = len; \
U32 hash_PeRlHaSh = 0; \
while (i_PeRlHaSh--) \
hash_PeRlHaSh = hash_PeRlHaSh * 33 + *s_PeRlHaSh++; \
(hash) = hash_PeRlHaSh; \
} STMT_END
#endif
#ifndef PERL_SIGNALS_UNSAFE_FLAG
#define PERL_SIGNALS_UNSAFE_FLAG 0x0001
#if (PERL_BCDVERSION < 0x5008000)
# define D_PPP_PERL_SIGNALS_INIT PERL_SIGNALS_UNSAFE_FLAG
#else
# define D_PPP_PERL_SIGNALS_INIT 0
#elif defined(NEED_PL_signals_GLOBAL)
U32 DPPP_(my_PL_signals) = D_PPP_PERL_SIGNALS_INIT;
#else
extern U32 DPPP_(my_PL_signals);
#endif
#define PL_signals DPPP_(my_PL_signals)
#endif
/* Hint: PL_ppaddr
* Calling an op via PL_ppaddr requires passing a context argument
* for threaded builds. Since the context argument is different for
* 5.005 perls, you can use aTHXR (supplied by ppport.h), which will
* automatically be defined as the correct argument.
*/
#if (PERL_BCDVERSION <= 0x5005005)
/* Replace: 1 */
# define PL_ppaddr ppaddr
# define PL_no_modify no_modify
/* Replace: 0 */
#endif
#if (PERL_BCDVERSION <= 0x5004005)
/* Replace: 1 */
# define PL_sv_arenaroot sv_arenaroot
# define PL_sv_no sv_no
# define PL_sv_undef sv_undef
# define PL_sv_yes sv_yes
# define PL_tainted tainted
# define PL_tainting tainting
/* Replace: 0 */
#endif
/* Warning: PL_expect, PL_copline, PL_rsfp, PL_rsfp_filters
* Do not use this variable. It is internal to the perl parser
* and may change or even be removed in the future. Note that
* as of perl 5.9.5 you cannot assign to this variable anymore.
*/
/* TODO: cannot assign to these vars; is it worth fixing? */
#if (PERL_BCDVERSION >= 0x5009005)
# define PL_expect (PL_parser ? PL_parser->expect : 0)
# define PL_copline (PL_parser ? PL_parser->copline : 0)
# define PL_rsfp (PL_parser ? PL_parser->rsfp : (PerlIO *) 0)
# define PL_rsfp_filters (PL_parser ? PL_parser->rsfp_filters : (AV *) 0)
#endif
#ifndef dTHR
# define dTHR dNOOP
# undef eval_pv
#endif
#define eval_pv(a,b) DPPP_(my_eval_pv)(aTHX_ a,b)
#define Perl_eval_pv DPPP_(my_eval_pv)
#if defined(NEED_eval_pv) || defined(NEED_eval_pv_GLOBAL)
SV*
DPPP_(my_eval_pv)(char *p, I32 croak_on_error)
{
dSP;
SV* sv = newSVpv(p, 0);
PUSHMARK(sp);
eval_sv(sv, G_SCALAR);
SvREFCNT_dec(sv);
SPAGAIN;
sv = POPs;
PUTBACK;
if (croak_on_error && SvTRUE(GvSV(errgv)))
croak(SvPVx(GvSV(errgv), na));
return sv;
}
#endif
#endif
#ifndef vload_module
#if defined(NEED_vload_module)
static void DPPP_(my_vload_module)(U32 flags, SV *name, SV *ver, va_list *args);
static
#else
# undef vload_module
#endif
#define vload_module(a,b,c,d) DPPP_(my_vload_module)(aTHX_ a,b,c,d)
#define Perl_vload_module DPPP_(my_vload_module)
#if defined(NEED_vload_module) || defined(NEED_vload_module_GLOBAL)
void
DPPP_(my_vload_module)(U32 flags, SV *name, SV *ver, va_list *args)
{
dTHR;
dVAR;
OP *veop, *imop;
OP * const modname = newSVOP(OP_CONST, 0, name);
/* 5.005 has a somewhat hacky force_normal that doesn't croak on
SvREADONLY() if PL_compling is true. Current perls take care in
ck_require() to correctly turn off SvREADONLY before calling
force_normal_flags(). This seems a better fix than fudging PL_compling
*/
SvREADONLY_off(((SVOP*)modname)->op_sv);
modname->op_private |= OPpCONST_BARE;
if (ver) {
veop = newSVOP(OP_CONST, 0, ver);
}
else
veop = NULL;
if (flags & PERL_LOADMOD_NOIMPORT) {
imop = sawparens(newNULLLIST());
}
else if (flags & PERL_LOADMOD_IMPORT_OPS) {
imop = va_arg(*args, OP*);
}
else {
SV *sv;
imop = NULL;
sv = va_arg(*args, SV*);
while (sv) {
imop = append_elem(OP_LIST, imop, newSVOP(OP_CONST, 0, sv));
sv = va_arg(*args, SV*);
}
}
{
const line_t ocopline = PL_copline;
COP * const ocurcop = PL_curcop;
const int oexpect = PL_expect;
#if (PERL_BCDVERSION >= 0x5004000)
utilize(!(flags & PERL_LOADMOD_DENY), start_subparse(FALSE, 0),
veop, modname, imop);
#else
utilize(!(flags & PERL_LOADMOD_DENY), start_subparse(),
modname, imop);
#endif
PL_expect = oexpect;
PL_copline = ocopline;
PL_curcop = ocurcop;
}
}
#endif
#endif
#ifndef load_module
#if defined(NEED_load_module)
static void DPPP_(my_load_module)(U32 flags, SV *name, SV *ver, ...);
static
#else
# undef load_module
#endif
#define load_module DPPP_(my_load_module)
#define Perl_load_module DPPP_(my_load_module)
#if defined(NEED_load_module) || defined(NEED_load_module_GLOBAL)
void
DPPP_(my_load_module)(U32 flags, SV *name, SV *ver, ...)
{
va_list args;
va_start(args, ver);
vload_module(flags, name, ver, &args);
va_end(args);
}
#endif
#endif
#ifndef newRV_inc
# define newRV_inc(sv) newRV(sv) /* Replace */
#endif
#ifndef newRV_noinc
#if defined(NEED_newRV_noinc)
#ifdef newRV_noinc
# undef newRV_noinc
#endif
#define newRV_noinc(a) DPPP_(my_newRV_noinc)(aTHX_ a)
#define Perl_newRV_noinc DPPP_(my_newRV_noinc)
#if defined(NEED_newRV_noinc) || defined(NEED_newRV_noinc_GLOBAL)
SV *
DPPP_(my_newRV_noinc)(SV *sv)
{
SV *rv = (SV *)newRV(sv);
SvREFCNT_dec(sv);
return rv;
}
#endif
#endif
/* Hint: newCONSTSUB
* Returns a CV* as of perl-5.7.1. This return value is not supported
* by Devel::PPPort.
*/
/* newCONSTSUB from IO.xs is in the core starting with 5.004_63 */
#if (PERL_BCDVERSION < 0x5004063) && (PERL_BCDVERSION != 0x5004005)
#if defined(NEED_newCONSTSUB)
static void DPPP_(my_newCONSTSUB)(HV *stash, const char *name, SV *sv);
static
#else
extern void DPPP_(my_newCONSTSUB)(HV *stash, const char *name, SV *sv);
#endif
# undef newCONSTSUB
#endif
#define newCONSTSUB(a,b,c) DPPP_(my_newCONSTSUB)(aTHX_ a,b,c)
#define Perl_newCONSTSUB DPPP_(my_newCONSTSUB)
#if defined(NEED_newCONSTSUB) || defined(NEED_newCONSTSUB_GLOBAL)
void
DPPP_(my_newCONSTSUB)(HV *stash, const char *name, SV *sv)
{
U32 oldhints = PL_hints;
HV *old_cop_stash = PL_curcop->cop_stash;
HV *old_curstash = PL_curstash;
line_t oldline = PL_curcop->cop_line;
PL_curcop->cop_line = PL_copline;
PL_hints &= ~HINT_BLOCK_SCOPE;
if (stash)
PL_curstash = PL_curcop->cop_stash = stash;
newSUB(
#if (PERL_BCDVERSION < 0x5003022)
start_subparse(),
#elif (PERL_BCDVERSION == 0x5003022)
start_subparse(0),
#else /* 5.003_23 onwards */
start_subparse(FALSE, 0),
#endif
newSVOP(OP_CONST, 0, newSVpv((char *) name, 0)),
newSVOP(OP_CONST, 0, &PL_sv_no), /* SvPV(&PL_sv_no) == "" -- GMB */
newSTATEOP(0, Nullch, newSVOP(OP_CONST, 0, sv))
);
PL_hints = oldhints;
PL_curcop->cop_stash = old_cop_stash;
PL_curstash = old_curstash;
PL_curcop->cop_line = oldline;
}
#endif
#endif
/*
* Boilerplate macros for initializing and accessing interpreter-local
* data from C. All statics in extensions should be reworked to use
* this, if you want to make the extension thread-safe. See ext/re/re.xs
* for an example of the use of these macros.
*
* Code that uses these macros is responsible for the following:
* 1. #define MY_CXT_KEY to a unique string, e.g. "DynaLoader_guts"
* 2. Declare a typedef named my_cxt_t that is a structure that contains
* all the data that needs to be interpreter-local.
* 3. Use the START_MY_CXT macro after the declaration of my_cxt_t.
* 4. Use the MY_CXT_INIT macro such that it is called exactly once
* (typically put in the BOOT: section).
* 5. Use the members of the my_cxt_t structure everywhere as
* MY_CXT.member.
* 6. Use the dMY_CXT macro (a declaration) in all the functions that
* access MY_CXT.
*/
#if defined(MULTIPLICITY) || defined(PERL_OBJECT) || \
defined(PERL_CAPI) || defined(PERL_IMPLICIT_CONTEXT)
#ifndef START_MY_CXT
/* This must appear in all extensions that define a my_cxt_t structure,
* right after the definition (i.e. at file scope). The non-threads
* case below uses it to declare the data as static. */
#define START_MY_CXT
#if (PERL_BCDVERSION < 0x5004068)
/* Fetches the SV that keeps the per-interpreter data. */
#define dMY_CXT_SV \
SV *my_cxt_sv = get_sv(MY_CXT_KEY, FALSE)
#else /* >= perl5.004_68 */
#define dMY_CXT_SV \
SV *my_cxt_sv = *hv_fetch(PL_modglobal, MY_CXT_KEY, \
sizeof(MY_CXT_KEY)-1, TRUE)
#endif /* < perl5.004_68 */
/* This declaration should be used within all functions that use the
* interpreter-local data. */
#define dMY_CXT \
dMY_CXT_SV; \
my_cxt_t *my_cxtp = INT2PTR(my_cxt_t*,SvUV(my_cxt_sv))
/* Creates and zeroes the per-interpreter data.
* (We allocate my_cxtp in a Perl SV so that it will be released when
* the interpreter goes away.) */
#define MY_CXT_INIT \
dMY_CXT_SV; \
/* newSV() allocates one more than needed */ \
my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\
Zero(my_cxtp, 1, my_cxt_t); \
sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
/* This macro must be used to access members of the my_cxt_t structure.
* e.g. MYCXT.some_data */
#define MY_CXT (*my_cxtp)
/* Judicious use of these macros can reduce the number of times dMY_CXT
* is used. Use is similar to pTHX, aTHX etc. */
#define pMY_CXT my_cxt_t *my_cxtp
#define pMY_CXT_ pMY_CXT,
#define _pMY_CXT ,pMY_CXT
#define aMY_CXT my_cxtp
#define aMY_CXT_ aMY_CXT,
#define _aMY_CXT ,aMY_CXT
#endif /* START_MY_CXT */
#ifndef MY_CXT_CLONE
/* Clones the per-interpreter data. */
#define MY_CXT_CLONE \
dMY_CXT_SV; \
my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\
Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t);\
sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
#endif
#else /* single interpreter */
#ifndef START_MY_CXT
#define START_MY_CXT static my_cxt_t my_cxt;
#define dMY_CXT_SV dNOOP
#define dMY_CXT dNOOP
#define MY_CXT_INIT NOOP
# define UVuf "u"
# define UVof "o"
# define UVxf "x"
# define UVXf "X"
# endif
# endif
#endif
#ifndef NVef
# if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE) && \
defined(PERL_PRIfldbl) /* Not very likely, but let's try anyway. */
# define NVef PERL_PRIeldbl
# define NVff PERL_PRIfldbl
# define NVgf PERL_PRIgldbl
# else
# define NVef "e"
# define NVff "f"
# define NVgf "g"
# endif
#endif
#ifndef SvREFCNT_inc
# ifdef PERL_USE_GCC_BRACE_GROUPS
# define SvREFCNT_inc(sv) \
({ \
SV * const _sv = (SV*)(sv); \
if (_sv) \
(SvREFCNT(_sv))++; \
_sv; \
})
# else
# define SvREFCNT_inc(sv) \
((PL_Sv=(SV*)(sv)) ? (++(SvREFCNT(PL_Sv)),PL_Sv) : NULL)
# endif
#endif
#ifndef SvREFCNT_inc_simple
# ifdef PERL_USE_GCC_BRACE_GROUPS
# define SvREFCNT_inc_simple(sv) \
({ \
if (sv) \
(SvREFCNT(sv))++; \
(SV *)(sv); \
})
# else
# define SvREFCNT_inc_simple(sv) \
((sv) ? (SvREFCNT(sv)++,(SV*)(sv)) : NULL)
# endif
#endif
#ifndef SvREFCNT_inc_NN
# ifdef PERL_USE_GCC_BRACE_GROUPS
# define SvREFCNT_inc_NN(sv) \
({ \
SV * const _sv = (SV*)(sv); \
SvREFCNT(_sv)++; \
_sv; \
})
# else
# define SvREFCNT_inc_NN(sv) \
(PL_Sv=(SV*)(sv),++(SvREFCNT(PL_Sv)),PL_Sv)
# endif
#endif
#ifndef SvREFCNT_inc_void
# ifdef PERL_USE_GCC_BRACE_GROUPS
# define SvREFCNT_inc_void(sv) \
({ \
SV * const _sv = (SV*)(sv); \
if (_sv) \
(void)(SvREFCNT(_sv)++); \
})
# else
# define SvREFCNT_inc_void(sv) \
(void)((PL_Sv=(SV*)(sv)) ? ++(SvREFCNT(PL_Sv)) : 0)
# endif
#endif
#ifndef SvREFCNT_inc_simple_void
# define SvREFCNT_inc_simple_void(sv) STMT_START { if (sv) SvREFCNT(sv)++; } STMT_END
#endif
#ifndef SvREFCNT_inc_simple_NN
# define SvREFCNT_inc_simple_NN(sv) (++SvREFCNT(sv), (SV*)(sv))
#endif
/* Backwards compatibility stuff... :-( */
#if !defined(NEED_sv_2pv_flags) && defined(NEED_sv_2pv_nolen)
# define NEED_sv_2pv_flags
#endif
#if !defined(NEED_sv_2pv_flags_GLOBAL) && defined(NEED_sv_2pv_nolen_GLOBAL)
# define NEED_sv_2pv_flags_GLOBAL
#endif
/* Hint: sv_2pv_nolen
* Use the SvPV_nolen() or SvPV_nolen_const() macros instead of sv_2pv_nolen().
*/
#ifndef sv_2pv_nolen
# define sv_2pv_nolen(sv) SvPV_nolen(sv)
#endif
#ifdef SvPVbyte
/* Hint: SvPVbyte
* Does not work in perl-5.6.1, ppport.h implements a version
* borrowed from perl-5.7.3.
*/
#if (PERL_BCDVERSION < 0x5007000)
#if defined(NEED_sv_2pvbyte)
static char * DPPP_(my_sv_2pvbyte)(pTHX_ SV * sv, STRLEN * lp);
static
#else
extern char * DPPP_(my_sv_2pvbyte)(pTHX_ SV * sv, STRLEN * lp);
#endif
# undef sv_2pvbyte
#endif
#define sv_2pvbyte(a,b) DPPP_(my_sv_2pvbyte)(aTHX_ a,b)
#define Perl_sv_2pvbyte DPPP_(my_sv_2pvbyte)
#if defined(NEED_sv_2pvbyte) || defined(NEED_sv_2pvbyte_GLOBAL)
char *
DPPP_(my_sv_2pvbyte)(pTHX_ SV *sv, STRLEN *lp)
{
sv_utf8_downgrade(sv,0);
return SvPV(sv,*lp);
}
#endif
/* Hint: sv_2pvbyte
* Use the SvPVbyte() macro instead of sv_2pvbyte().
*/
#undef SvPVbyte
#define SvPVbyte(sv, lp) \
((SvFLAGS(sv) & (SVf_POK|SVf_UTF8)) == (SVf_POK) \
? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_2pvbyte(sv, &lp))
#endif
#else
# define SvPVbyte SvPV
# define sv_2pvbyte sv_2pv
#endif
#ifndef sv_2pvbyte_nolen
# define sv_2pvbyte_nolen(sv) sv_2pv_nolen(sv)
#endif
/* Hint: sv_pvn
* Always use the SvPV() macro instead of sv_pvn().
*/
/* Hint: sv_pvn_force
* Always use the SvPV_force() macro instead of sv_pvn_force().
*/
/* If these are undefined, they're not handled by the core anyway */
#ifndef SV_IMMEDIATE_UNREF
# define SV_IMMEDIATE_UNREF 0
#endif
#ifndef SV_GMAGIC
# define SV_GMAGIC 0
#endif
# undef sv_2pv_flags
#endif
#define sv_2pv_flags(a,b,c) DPPP_(my_sv_2pv_flags)(aTHX_ a,b,c)
#define Perl_sv_2pv_flags DPPP_(my_sv_2pv_flags)
#if defined(NEED_sv_2pv_flags) || defined(NEED_sv_2pv_flags_GLOBAL)
char *
DPPP_(my_sv_2pv_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags)
{
STRLEN n_a = (STRLEN) flags;
return sv_2pv(sv, lp ? lp : &n_a);
}
#endif
#if defined(NEED_sv_pvn_force_flags)
static char * DPPP_(my_sv_pvn_force_flags)(pTHX_ SV * sv, STRLEN * lp, I32 flags);
static
#else
extern char * DPPP_(my_sv_pvn_force_flags)(pTHX_ SV * sv, STRLEN * lp, I32 flags);
#endif
# undef sv_pvn_force_flags
#endif
#define sv_pvn_force_flags(a,b,c) DPPP_(my_sv_pvn_force_flags)(aTHX_ a,b,c)
#define Perl_sv_pvn_force_flags DPPP_(my_sv_pvn_force_flags)
#if defined(NEED_sv_pvn_force_flags) || defined(NEED_sv_pvn_force_flags_GLOBAL)
char *
DPPP_(my_sv_pvn_force_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags)
{
STRLEN n_a = (STRLEN) flags;
return sv_pvn_force(sv, lp ? lp : &n_a);
}
#endif
#endif
#ifndef SvPV_const
# define SvPV_const(sv, lp) SvPV_flags_const(sv, lp, SV_GMAGIC)
#endif
#ifndef SvPV_mutable
# define SvPV_mutable(sv, lp) SvPV_flags_mutable(sv, lp, SV_GMAGIC)
#endif
#ifndef SvPV_flags
# define SvPV_flags(sv, lp, flags) \
((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \
? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_2pv_flags(sv, &lp, flags))
#endif
#ifndef SvPV_flags_const
# define SvPV_flags_const(sv, lp, flags) \
((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \
? ((lp = SvCUR(sv)), SvPVX_const(sv)) : \
(const char*) sv_2pv_flags(sv, &lp, flags|SV_CONST_RETURN))
#endif
#ifndef SvPV_flags_const_nolen
# define SvPV_flags_const_nolen(sv, flags) \
((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \
? SvPVX_const(sv) : \
(const char*) sv_2pv_flags(sv, 0, flags|SV_CONST_RETURN))
#endif
#ifndef SvPV_flags_mutable
# define SvPV_flags_mutable(sv, lp, flags) \
((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \
? ((lp = SvCUR(sv)), SvPVX_mutable(sv)) : \
sv_2pv_flags(sv, &lp, flags|SV_MUTABLE_RETURN))
#endif
#ifndef SvPV_force
# define SvPV_force(sv, lp) SvPV_force_flags(sv, lp, SV_GMAGIC)
#endif
#ifndef SvPV_force_nolen
# define SvPV_force_nolen(sv) SvPV_force_flags_nolen(sv, SV_GMAGIC)
#endif
#ifndef SvPV_force_mutable
#ifndef SvPV_force_nomg
# define SvPV_force_nomg(sv, lp) SvPV_force_flags(sv, lp, 0)
#endif
#ifndef SvPV_force_nomg_nolen
# define SvPV_force_nomg_nolen(sv) SvPV_force_flags_nolen(sv, 0)
#endif
#ifndef SvPV_force_flags
# define SvPV_force_flags(sv, lp, flags) \
((SvFLAGS(sv) & (SVf_POK|SVf_THINKFIRST)) == SVf_POK \
? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_pvn_force_flags(sv, &lp, flags))
#endif
#ifndef SvPV_force_flags_nolen
# define SvPV_force_flags_nolen(sv, flags) \
((SvFLAGS(sv) & (SVf_POK|SVf_THINKFIRST)) == SVf_POK \
? SvPVX(sv) : sv_pvn_force_flags(sv, 0, flags))
#endif
#ifndef SvPV_force_flags_mutable
# define SvPV_force_flags_mutable(sv, lp, flags) \
((SvFLAGS(sv) & (SVf_POK|SVf_THINKFIRST)) == SVf_POK \
? ((lp = SvCUR(sv)), SvPVX_mutable(sv)) \
: sv_pvn_force_flags(sv, &lp, flags|SV_MUTABLE_RETURN))
#endif
#ifndef SvPV_nolen
# define SvPV_nolen(sv) \
((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \
? SvPVX(sv) : sv_2pv_flags(sv, 0, SV_GMAGIC))
#endif
#ifndef SvPV_nolen_const
# define SvPV_nolen_const(sv) \
((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \
? SvPVX_const(sv) : sv_2pv_flags(sv, 0, SV_GMAGIC|SV_CONST_RETURN))
#endif
#ifndef SvPV_nomg
# define SvPV_nomg(sv, lp) SvPV_flags(sv, lp, 0)
#endif
#ifndef SvPV_nomg_const
# define SvPV_nomg_const(sv, lp) SvPV_flags_const(sv, lp, 0)
#endif
#ifndef SvPV_nomg_const_nolen
# define SvPV_nomg_const_nolen(sv) SvPV_flags_const_nolen(sv, 0)
#endif
#ifndef SvMAGIC_set
# define SvMAGIC_set(sv, val) \
STMT_START { assert(SvTYPE(sv) >= SVt_PVMG); \
(((XPVMG*) SvANY(sv))->xmg_magic = (val)); } STMT_END
#endif
#if (PERL_BCDVERSION < 0x5009003)
#ifndef SvPVX_const
# define SvPVX_const(sv) ((const char*) (0 + SvPVX(sv)))
#endif
#ifndef SvPVX_mutable
# define SvPVX_mutable(sv) (0 + SvPVX(sv))
#endif
#ifndef SvRV_set
# define SvRV_set(sv, val) \
STMT_START { assert(SvTYPE(sv) >= SVt_RV); \
(((XRV*) SvANY(sv))->xrv_rv = (val)); } STMT_END
#endif
#else
#ifndef SvPVX_const
# define SvPVX_const(sv) ((const char*)((sv)->sv_u.svu_pv))
#endif
#ifndef SvPVX_mutable
# define SvPVX_mutable(sv) ((sv)->sv_u.svu_pv)
#endif
#ifndef SvRV_set
# define SvRV_set(sv, val) \
STMT_START { assert(SvTYPE(sv) >= SVt_RV); \
((sv)->sv_u.svu_rv = (val)); } STMT_END
#endif
#endif
#ifndef SvSTASH_set
# define SvSTASH_set(sv, val) \
STMT_START { assert(SvTYPE(sv) >= SVt_PVMG); \
(((XPVMG*) SvANY(sv))->xmg_stash = (val)); } STMT_END
#endif
#if (PERL_BCDVERSION < 0x5004000)
#ifndef SvUV_set
# define SvUV_set(sv, val) \
STMT_START { assert(SvTYPE(sv) == SVt_IV || SvTYPE(sv) >= SVt_PVIV); \
(((XPVIV*) SvANY(sv))->xiv_iv = (IV) (val)); } STMT_END
#endif
#else
#ifndef SvUV_set
# define SvUV_set(sv, val) \
STMT_START { assert(SvTYPE(sv) == SVt_IV || SvTYPE(sv) >= SVt_PVIV); \
(((XPVUV*) SvANY(sv))->xuv_uv = (val)); } STMT_END
#endif
#endif
#if (PERL_BCDVERSION >= 0x5004000) && !defined(vnewSVpvf)
#if defined(NEED_vnewSVpvf)
static SV * DPPP_(my_vnewSVpvf)(pTHX_ const char * pat, va_list * args);
static
#else
extern SV * DPPP_(my_vnewSVpvf)(pTHX_ const char * pat, va_list * args);
# undef vnewSVpvf
#endif
#define vnewSVpvf(a,b) DPPP_(my_vnewSVpvf)(aTHX_ a,b)
#define Perl_vnewSVpvf DPPP_(my_vnewSVpvf)
#if defined(NEED_vnewSVpvf) || defined(NEED_vnewSVpvf_GLOBAL)
SV *
DPPP_(my_vnewSVpvf)(pTHX_ const char *pat, va_list *args)
{
register SV *sv = newSV(0);
sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*));
return sv;
}
#endif
#endif
#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vcatpvf)
# define sv_vcatpvf(sv, pat, args) sv_vcatpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*))
#endif
#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vsetpvf)
extern void DPPP_(my_sv_catpvf_mg)(pTHX_ SV * sv, const char * pat, ...);
#endif
#define Perl_sv_catpvf_mg DPPP_(my_sv_catpvf_mg)
#if defined(NEED_sv_catpvf_mg) || defined(NEED_sv_catpvf_mg_GLOBAL)
void
DPPP_(my_sv_catpvf_mg)(pTHX_ SV *sv, const char *pat, ...)
{
va_list args;
va_start(args, pat);
sv_vcatpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*));
SvSETMAGIC(sv);
va_end(args);
}
#endif
#endif
#ifdef PERL_IMPLICIT_CONTEXT
#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_catpvf_mg_nocontext)
#if defined(NEED_sv_catpvf_mg_nocontext)
static void DPPP_(my_sv_catpvf_mg_nocontext)(SV * sv, const char * pat, ...);
static
#endif
#define sv_catpvf_mg_nocontext DPPP_(my_sv_catpvf_mg_nocontext)
#define Perl_sv_catpvf_mg_nocontext DPPP_(my_sv_catpvf_mg_nocontext)
#if defined(NEED_sv_catpvf_mg_nocontext) || defined(NEED_sv_catpvf_mg_nocontext_GLOBAL)
void
DPPP_(my_sv_catpvf_mg_nocontext)(SV *sv, const char *pat, ...)
{
dTHX;
va_list args;
va_start(args, pat);
sv_vcatpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*));
SvSETMAGIC(sv);
va_end(args);
}
#endif
#endif
#endif
/* sv_catpvf_mg depends on sv_catpvf_mg_nocontext */
#ifndef sv_catpvf_mg
# ifdef PERL_IMPLICIT_CONTEXT
# define sv_catpvf_mg Perl_sv_catpvf_mg_nocontext
# else
# define sv_catpvf_mg Perl_sv_catpvf_mg
# endif
#endif
#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vcatpvf_mg)
# define sv_vcatpvf_mg(sv, pat, args) \
STMT_START { \
sv_vcatpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)); \
SvSETMAGIC(sv); \
} STMT_END
#endif
#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_setpvf_mg)
#if defined(NEED_sv_setpvf_mg)
static void DPPP_(my_sv_setpvf_mg)(pTHX_ SV * sv, const char * pat, ...);
static
#else
extern void DPPP_(my_sv_setpvf_mg)(pTHX_ SV * sv, const char * pat, ...);
#endif
#define Perl_sv_setpvf_mg DPPP_(my_sv_setpvf_mg)
#if defined(NEED_sv_setpvf_mg) || defined(NEED_sv_setpvf_mg_GLOBAL)
void
DPPP_(my_sv_setpvf_mg)(pTHX_ SV *sv, const char *pat, ...)
{
va_list args;
va_start(args, pat);
sv_vsetpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*));
SvSETMAGIC(sv);
va_end(args);
}
#endif
#endif
#ifdef PERL_IMPLICIT_CONTEXT
#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_setpvf_mg_nocontext)
#if defined(NEED_sv_setpvf_mg_nocontext)
static void DPPP_(my_sv_setpvf_mg_nocontext)(SV * sv, const char * pat, ...);
static
#endif
#define sv_setpvf_mg_nocontext DPPP_(my_sv_setpvf_mg_nocontext)
#define Perl_sv_setpvf_mg_nocontext DPPP_(my_sv_setpvf_mg_nocontext)
#if defined(NEED_sv_setpvf_mg_nocontext) || defined(NEED_sv_setpvf_mg_nocontext_GLOBAL)
void
DPPP_(my_sv_setpvf_mg_nocontext)(SV *sv, const char *pat, ...)
{
dTHX;
va_list args;
va_start(args, pat);
sv_vsetpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*));
SvSETMAGIC(sv);
va_end(args);
}
#endif
#endif
#endif
/* sv_setpvf_mg depends on sv_setpvf_mg_nocontext */
#ifndef sv_setpvf_mg
# ifdef PERL_IMPLICIT_CONTEXT
# define sv_setpvf_mg Perl_sv_setpvf_mg_nocontext
# else
# define sv_setpvf_mg Perl_sv_setpvf_mg
# endif
#endif
#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vsetpvf_mg)
# define sv_vsetpvf_mg(sv, pat, args) \
STMT_START { \
sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)); \
SvSETMAGIC(sv); \
} STMT_END
#endif
#ifndef newSVpvn_share
#if defined(NEED_newSVpvn_share)
static SV * DPPP_(my_newSVpvn_share)(pTHX_ const char *src, I32 len, U32 hash);
static
#else
extern SV * DPPP_(my_newSVpvn_share)(pTHX_ const char *src, I32 len, U32 hash);
#endif
# undef newSVpvn_share
#endif
#define newSVpvn_share(a,b,c) DPPP_(my_newSVpvn_share)(aTHX_ a,b,c)
#define Perl_newSVpvn_share DPPP_(my_newSVpvn_share)
#if defined(NEED_newSVpvn_share) || defined(NEED_newSVpvn_share_GLOBAL)
SV *
DPPP_(my_newSVpvn_share)(pTHX_ const char *src, I32 len, U32 hash)
{
SV *sv;
if (len < 0)
len = -len;
if (!hash)
PERL_HASH(hash, (char*) src, len);
sv = newSVpvn((char *) src, len);
sv_upgrade(sv, SVt_PVIV);
SvIVX(sv) = hash;
SvREADONLY_on(sv);
SvPOK_on(sv);
return sv;
}
#endif
#endif
#ifndef SvSHARED_HASH
# define SvSHARED_HASH(sv) (0 + SvUVX(sv))
#endif
#ifndef WARN_ALL
# define WARN_ALL 0
extern void DPPP_(my_warner)(U32 err, const char *pat, ...);
#endif
#define Perl_warner DPPP_(my_warner)
#if defined(NEED_warner) || defined(NEED_warner_GLOBAL)
void
DPPP_(my_warner)(U32 err, const char *pat, ...)
{
SV *sv;
va_list args;
PERL_UNUSED_ARG(err);
va_start(args, pat);
sv = vnewSVpvf(pat, &args);
va_end(args);
sv_2mortal(sv);
warn("%s", SvPV_nolen(sv));
}
#define warner Perl_warner
#define Perl_warner_nocontext Perl_warner
#endif
#endif
/* concatenating with "" ensures that only literal strings are accepted as argument
* note that STR_WITH_LEN() can't be used as argument to macros or functions that
* under some configurations might be macros
*/
#ifndef STR_WITH_LEN
# define STR_WITH_LEN(s) (s ""), (sizeof(s)-1)
#endif
#ifndef newSVpvs
# define newSVpvs(str) newSVpvn(str "", sizeof(str) - 1)
#endif
#ifndef sv_catpvs
# define sv_catpvs(sv, str) sv_catpvn(sv, str "", sizeof(str) - 1)
#endif
#ifndef SvIV_nomg
# define SvIV_nomg SvIV
#endif
#ifndef SvUV_nomg
# define SvUV_nomg SvUV
#endif
#ifndef sv_catpv_mg
# define sv_catpv_mg(sv, ptr) \
STMT_START { \
SV *TeMpSv = sv; \
sv_catpv(TeMpSv,ptr); \
SvSETMAGIC(TeMpSv); \
} STMT_END
#endif
#ifndef sv_catpvn_mg
# define sv_catpvn_mg(sv, ptr, len) \
STMT_START { \
SV *TeMpSv = sv; \
sv_catpvn(TeMpSv,ptr,len); \
SvSETMAGIC(TeMpSv); \
} STMT_END
#endif
#ifndef sv_catsv_mg
# define sv_catsv_mg(dsv, ssv) \
STMT_START { \
SV *TeMpSv = dsv; \
sv_catsv(TeMpSv,ssv); \
SvSETMAGIC(TeMpSv); \
} STMT_END
#endif
#ifndef sv_setiv_mg
# define sv_setiv_mg(sv, i) \
STMT_START { \
SV *TeMpSv = sv; \
sv_setiv(TeMpSv,i); \
SvSETMAGIC(TeMpSv); \
} STMT_END
#endif
#ifndef sv_setnv_mg
# define sv_setnv_mg(sv, num) \
STMT_START { \
SV *TeMpSv = sv; \
sv_setnv(TeMpSv,num); \
SvSETMAGIC(TeMpSv); \
} STMT_END
#endif
#ifndef sv_setpv_mg
# define sv_setpv_mg(sv, ptr) \
STMT_START { \
SV *TeMpSv = sv; \
sv_setpv(TeMpSv,ptr); \
SvSETMAGIC(TeMpSv); \
} STMT_END
#endif
#ifndef sv_setpvn_mg
# define sv_setpvn_mg(sv, ptr, len) \
STMT_START { \
SV *TeMpSv = sv; \
sv_setpvn(TeMpSv,ptr,len); \
SvSETMAGIC(TeMpSv); \
} STMT_END
#endif
#ifndef sv_setsv_mg
# define sv_setsv_mg(dsv, ssv) \
STMT_START { \
SV *TeMpSv = dsv; \
sv_setsv(TeMpSv,ssv); \
SvSETMAGIC(TeMpSv); \
} STMT_END
#endif
#ifndef sv_setuv_mg
# define sv_setuv_mg(sv, i) \
STMT_START { \
SV *TeMpSv = sv; \
sv_setuv(TeMpSv,i); \
SvSETMAGIC(TeMpSv); \
} STMT_END
#endif
#ifndef sv_usepvn_mg
# define sv_usepvn_mg(sv, ptr, len) \
STMT_START { \
SV *TeMpSv = sv; \
sv_usepvn(TeMpSv,ptr,len); \
SvSETMAGIC(TeMpSv); \
} STMT_END
#endif
#ifndef SvVSTRING_mg
# define SvVSTRING_mg(sv) (SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_vstring) : NULL)
#endif
/* Hint: sv_magic_portable
* This is a compatibility function that is only available with
* Devel::PPPort. It is NOT in the perl core.
* Its purpose is to mimic the 5.8.0 behaviour of sv_magic() when
* it is being passed a name pointer with namlen == 0. In that
* case, perl 5.8.0 and later store the pointer, not a copy of it.
* The compatibility can be provided back to perl 5.004. With
* earlier versions, the code will not compile.
*/
#if (PERL_BCDVERSION < 0x5004000)
/* code that uses sv_magic_portable will not compile */
#elif (PERL_BCDVERSION < 0x5008000)
# define sv_magic_portable(sv, obj, how, name, namlen) \
STMT_START { \
SV *SvMp_sv = (sv); \
char *SvMp_name = (char *) (name); \
I32 SvMp_namlen = (namlen); \
if (SvMp_name && SvMp_namlen == 0) \
{ \
MAGIC *mg; \
sv_magic(SvMp_sv, obj, how, 0, 0); \
mg = SvMAGIC(SvMp_sv); \
mg->mg_len = -42; /* XXX: this is the tricky part */ \
mg->mg_ptr = SvMp_name; \
} \
else \
{ \
sv_magic(SvMp_sv, obj, how, SvMp_name, SvMp_namlen); \
} \
} STMT_END
#else
# define sv_magic_portable(a, b, c, d, e) sv_magic(a, b, c, d, e)
#endif
#ifdef USE_ITHREADS
#ifndef CopFILE
# define CopFILE(c) ((c)->cop_file)
#ifndef CopSTASH
# define CopSTASH(c) (CopSTASHPV(c) ? gv_stashpv(CopSTASHPV(c),GV_ADD) : Nullhv)
#endif
#ifndef CopSTASH_set
# define CopSTASH_set(c,hv) CopSTASHPV_set(c, (hv) ? HvNAME(hv) : Nullch)
#endif
#ifndef CopSTASH_eq
# define CopSTASH_eq(c,hv) ((hv) && (CopSTASHPV(c) == HvNAME(hv) \
|| (CopSTASHPV(c) && HvNAME(hv) \
&& strEQ(CopSTASHPV(c), HvNAME(hv)))))
#endif
#else
#ifndef CopFILEGV
# define CopFILEGV(c) ((c)->cop_filegv)
#endif
#ifndef CopFILEGV_set
# define CopFILEGV_set(c,gv) ((c)->cop_filegv = (GV*)SvREFCNT_inc(gv))
#endif
#endif
#define grok_numeric_radix(a,b) DPPP_(my_grok_numeric_radix)(aTHX_ a,b)
#define Perl_grok_numeric_radix DPPP_(my_grok_numeric_radix)
#if defined(NEED_grok_numeric_radix) || defined(NEED_grok_numeric_radix_GLOBAL)
bool
DPPP_(my_grok_numeric_radix)(pTHX_ const char **sp, const char *send)
{
#ifdef USE_LOCALE_NUMERIC
#ifdef PL_numeric_radix_sv
if (PL_numeric_radix_sv && IN_LOCALE) {
STRLEN len;
char* radix = SvPV(PL_numeric_radix_sv, len);
if (*sp + len <= send && memEQ(*sp, radix, len)) {
*sp += len;
return TRUE;
}
}
#else
/* older perls don't have PL_numeric_radix_sv so the radix
* must manually be requested from locale.h
*/
#include <locale.h>
dTHR; /* needed for older threaded perls */
struct lconv *lc = localeconv();
char *radix = lc->decimal_point;
if (radix && IN_LOCALE) {
STRLEN len = strlen(radix);
if (*sp + len <= send && memEQ(*sp, radix, len)) {
*sp += len;
return TRUE;
}
}
#endif
#endif /* USE_LOCALE_NUMERIC */
/* always try "." if numeric radix didn't match because
* we may have data from different locales mixed */
if (*sp < send && **sp == '.') {
++*sp;
return TRUE;
}
return FALSE;
}
#endif
#endif
#ifndef grok_number
#if defined(NEED_grok_number)
static int DPPP_(my_grok_number)(pTHX_ const char * pv, STRLEN len, UV * valuep);
static
#else
extern int DPPP_(my_grok_number)(pTHX_ const char * pv, STRLEN len, UV * valuep);
#ifdef grok_number
# undef grok_number
#endif
#define grok_number(a,b,c) DPPP_(my_grok_number)(aTHX_ a,b,c)
#define Perl_grok_number DPPP_(my_grok_number)
#if defined(NEED_grok_number) || defined(NEED_grok_number_GLOBAL)
int
DPPP_(my_grok_number)(pTHX_ const char *pv, STRLEN len, UV *valuep)
{
const char *s = pv;
const char *send = pv + len;
const UV max_div_10 = UV_MAX / 10;
const char max_mod_10 = UV_MAX % 10;
int numtype = 0;
int sawinf = 0;
int sawnan = 0;
while (s < send && isSPACE(*s))
s++;
if (s == send) {
return 0;
} else if (*s == '-') {
s++;
numtype = IS_NUMBER_NEG;
}
else if (*s == '+')
s++;
if (s == send)
return 0;
/* next must be digit or the radix separator or beginning of infinity */
if (isDIGIT(*s)) {
/* UVs are at least 32 bits, so the first 9 decimal digits cannot
overflow. */
UV value = *s - '0';
/* This construction seems to be more optimiser friendly.
(without it gcc does the isDIGIT test and the *s - '0' separately)
With it gcc on arm is managing 6 instructions (6 cycles) per digit.
In theory the optimiser could deduce how far to unroll the loop
before checking for overflow. */
if (++s < send) {
int digit = *s - '0';
if (digit >= 0 && digit <= 9) {
value = value * 10 + digit;
if (++s < send) {
digit = *s - '0';
if (digit >= 0 && digit <= 9) {
value = value * 10 + digit;
if (++s < send) {
digit = *s - '0';
if (digit >= 0 && digit <= 9) {
value = value * 10 + digit;
if (++s < send) {
digit = *s - '0';
if (digit >= 0 && digit <= 9) {
value = value * 10 + digit;
if (++s < send) {
digit = *s - '0';
if (digit >= 0 && digit <= 9) {
value = value * 10 + digit;
if (++s < send) {
digit = *s - '0';
if (digit >= 0 && digit <= 9) {
value = value * 10 + digit;
if (++s < send) {
digit = *s - '0';
if (digit >= 0 && digit <= 9) {
value = value * 10 + digit;
if (++s < send) {
digit = *s - '0';
if (digit >= 0 && digit <= 9) {
value = value * 10 + digit;
if (++s < send) {
/* Now got 9 digits, so need to check
each time for overflow. */
digit = *s - '0';
while (digit >= 0 && digit <= 9
&& (value < max_div_10
|| (value == max_div_10
&& digit <= max_mod_10))) {
value = value * 10 + digit;
if (++s < send)
digit = *s - '0';
else
break;
}
if (digit >= 0 && digit <= 9
&& (s < send)) {
/* value overflowed.
skip the remaining digits, don't
worry about setting *valuep. */
do {
s++;
} while (s < send && isDIGIT(*s));
numtype |=
IS_NUMBER_GREATER_THAN_UV_MAX;
goto skip_value;
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
numtype |= IS_NUMBER_IN_UV;
if (valuep)
*valuep = value;
skip_value:
if (GROK_NUMERIC_RADIX(&s, send)) {
numtype |= IS_NUMBER_NOT_INT;
while (s < send && isDIGIT(*s)) /* optional digits after the radix */
s++;
}
}
else if (GROK_NUMERIC_RADIX(&s, send)) {
numtype |= IS_NUMBER_NOT_INT | IS_NUMBER_IN_UV; /* valuep assigned below */
/* no digits before the radix means we need digits after it */
if (s < send && isDIGIT(*s)) {
do {
s++;
} while (s < send && isDIGIT(*s));
if (valuep) {
/* integer approximation is valid - it's 0. */
*valuep = 0;
}
}
else
return 0;
} else if (*s == 'I' || *s == 'i') {
s++; if (s == send || (*s != 'N' && *s != 'n')) return 0;
s++; if (s == send || (*s != 'F' && *s != 'f')) return 0;
s++; if (s < send && (*s == 'I' || *s == 'i')) {
s++; if (s == send || (*s != 'N' && *s != 'n')) return 0;
s++; if (s == send || (*s != 'I' && *s != 'i')) return 0;
s++; if (s == send || (*s != 'T' && *s != 't')) return 0;
s++; if (s == send || (*s != 'Y' && *s != 'y')) return 0;
s++;
}
sawinf = 1;
} else if (*s == 'N' || *s == 'n') {
/* XXX TODO: There are signaling NaNs and quiet NaNs. */
s++; if (s == send || (*s != 'A' && *s != 'a')) return 0;
s++; if (s == send || (*s != 'N' && *s != 'n')) return 0;
s++;
sawnan = 1;
} else
return 0;
if (sawinf) {
numtype &= IS_NUMBER_NEG; /* Keep track of sign */
numtype |= IS_NUMBER_INFINITY | IS_NUMBER_NOT_INT;
} else if (sawnan) {
numtype &= IS_NUMBER_NEG; /* Keep track of sign */
numtype |= IS_NUMBER_NAN | IS_NUMBER_NOT_INT;
} else if (s < send) {
/* we can have an optional exponent part */
if (*s == 'e' || *s == 'E') {
/* The only flag we keep is sign. Blow away any "it's UV" */
numtype &= IS_NUMBER_NEG;
numtype |= IS_NUMBER_NOT_INT;
s++;
if (s < send && (*s == '-' || *s == '+'))
s++;
if (s < send && isDIGIT(*s)) {
do {
s++;
} while (s < send && isDIGIT(*s));
}
else
return 0;
}
}
while (s < send && isSPACE(*s))
s++;
if (s >= send)
return numtype;
if (len == 10 && memEQ(pv, "0 but true", 10)) {
if (valuep)
*valuep = 0;
return IS_NUMBER_IN_UV;
}
return 0;
}
#endif
#endif
/*
* The grok_* routines have been modified to use warn() instead of
* Perl_warner(). Also, 'hexdigit' was the former name of PL_hexdigit,
* which is why the stack variable has been renamed to 'xdigit'.
*/
#ifndef grok_bin
#if defined(NEED_grok_bin)
static UV DPPP_(my_grok_bin)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result);
static
#else
extern UV DPPP_(my_grok_bin)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result);
#endif
#ifdef grok_bin
# undef grok_bin
#endif
#define grok_bin(a,b,c,d) DPPP_(my_grok_bin)(aTHX_ a,b,c,d)
#define Perl_grok_bin DPPP_(my_grok_bin)
#if defined(NEED_grok_bin) || defined(NEED_grok_bin_GLOBAL)
UV
DPPP_(my_grok_bin)(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result)
{
const char *s = start;
STRLEN len = *len_p;
UV value = 0;
NV value_nv = 0;
const UV max_div_2 = UV_MAX / 2;
bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES;
bool overflowed = FALSE;
if (!(*flags & PERL_SCAN_DISALLOW_PREFIX)) {
/* strip off leading b or 0b.
for compatibility silently suffer "b" and "0b" as valid binary
numbers. */
if (len >= 1) {
if (s[0] == 'b') {
s++;
len--;
}
else if (len >= 2 && s[0] == '0' && s[1] == 'b') {
s+=2;
len-=2;
}
}
}
for (; len-- && *s; s++) {
char bit = *s;
if (bit == '0' || bit == '1') {
/* Write it in this wonky order with a goto to attempt to get the
compiler to make the common case integer-only loop pretty tight.
With gcc seems to be much straighter code than old scan_bin. */
redo:
if (!overflowed) {
if (value <= max_div_2) {
value = (value << 1) | (bit - '0');
continue;
}
/* Bah. We're just overflowed. */
warn("Integer overflow in binary number");
overflowed = TRUE;
value_nv = (NV) value;
}
value_nv *= 2.0;
/* If an NV has not enough bits in its mantissa to
* represent a UV this summing of small low-order numbers
* is a waste of time (because the NV cannot preserve
* the low-order bits anyway): we could just remember when
* did we overflow and in the end just multiply value_nv by the
* right amount. */
value_nv += (NV)(bit - '0');
continue;
}
if (bit == '_' && len && allow_underscores && (bit = s[1])
&& (bit == '0' || bit == '1'))
{
--len;
++s;
goto redo;
}
if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT))
warn("Illegal binary digit '%c' ignored", *s);
break;
}
if ( ( overflowed && value_nv > 4294967295.0)
#if UVSIZE > 4
|| (!overflowed && value > 0xffffffff )
#endif
) {
warn("Binary number > 0b11111111111111111111111111111111 non-portable");
}
*len_p = s - start;
if (!overflowed) {
*flags = 0;
return value;
}
*flags = PERL_SCAN_GREATER_THAN_UV_MAX;
if (result)
*result = value_nv;
return UV_MAX;
}
#endif
#endif
#ifndef grok_hex
#if defined(NEED_grok_hex)
static UV DPPP_(my_grok_hex)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result);
static
#else
extern UV DPPP_(my_grok_hex)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result);
#ifdef grok_hex
# undef grok_hex
#endif
#define grok_hex(a,b,c,d) DPPP_(my_grok_hex)(aTHX_ a,b,c,d)
#define Perl_grok_hex DPPP_(my_grok_hex)
#if defined(NEED_grok_hex) || defined(NEED_grok_hex_GLOBAL)
UV
DPPP_(my_grok_hex)(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result)
{
const char *s = start;
STRLEN len = *len_p;
UV value = 0;
NV value_nv = 0;
const UV max_div_16 = UV_MAX / 16;
bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES;
bool overflowed = FALSE;
const char *xdigit;
if (!(*flags & PERL_SCAN_DISALLOW_PREFIX)) {
/* strip off leading x or 0x.
for compatibility silently suffer "x" and "0x" as valid hex numbers.
*/
if (len >= 1) {
if (s[0] == 'x') {
s++;
len--;
}
else if (len >= 2 && s[0] == '0' && s[1] == 'x') {
s+=2;
len-=2;
}
}
}
for (; len-- && *s; s++) {
xdigit = strchr((char *) PL_hexdigit, *s);
if (xdigit) {
/* Write it in this wonky order with a goto to attempt to get the
compiler to make the common case integer-only loop pretty tight.
With gcc seems to be much straighter code than old scan_hex. */
redo:
if (!overflowed) {
if (value <= max_div_16) {
value = (value << 4) | ((xdigit - PL_hexdigit) & 15);
continue;
}
warn("Integer overflow in hexadecimal number");
overflowed = TRUE;
value_nv = (NV) value;
}
value_nv *= 16.0;
/* If an NV has not enough bits in its mantissa to
* represent a UV this summing of small low-order numbers
* is a waste of time (because the NV cannot preserve
* the low-order bits anyway): we could just remember when
* did we overflow and in the end just multiply value_nv by the
* right amount of 16-tuples. */
value_nv += (NV)((xdigit - PL_hexdigit) & 15);
continue;
}
if (*s == '_' && len && allow_underscores && s[1]
&& (xdigit = strchr((char *) PL_hexdigit, s[1])))
{
--len;
++s;
goto redo;
}
if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT))
warn("Illegal hexadecimal digit '%c' ignored", *s);
break;
}
if ( ( overflowed && value_nv > 4294967295.0)
#if UVSIZE > 4
|| (!overflowed && value > 0xffffffff )
#endif
) {
warn("Hexadecimal number > 0xffffffff non-portable");
}
*len_p = s - start;
if (!overflowed) {
*flags = 0;
return value;
}
*flags = PERL_SCAN_GREATER_THAN_UV_MAX;
if (result)
*result = value_nv;
return UV_MAX;
}
#endif
#endif
#ifndef grok_oct
#if defined(NEED_grok_oct)
static UV DPPP_(my_grok_oct)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result);
static
#else
extern UV DPPP_(my_grok_oct)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result);
#ifdef grok_oct
# undef grok_oct
#endif
#define grok_oct(a,b,c,d) DPPP_(my_grok_oct)(aTHX_ a,b,c,d)
#define Perl_grok_oct DPPP_(my_grok_oct)
#if defined(NEED_grok_oct) || defined(NEED_grok_oct_GLOBAL)
UV
DPPP_(my_grok_oct)(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result)
{
const char *s = start;
STRLEN len = *len_p;
UV value = 0;
NV value_nv = 0;
const UV max_div_8 = UV_MAX / 8;
bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES;
bool overflowed = FALSE;
for (; len-- && *s; s++) {
/* gcc 2.95 optimiser not smart enough to figure that this subtraction
out front allows slicker code. */
int digit = *s - '0';
if (digit >= 0 && digit <= 7) {
/* Write it in this wonky order with a goto to attempt to get the
compiler to make the common case integer-only loop pretty tight.
*/
redo:
if (!overflowed) {
if (value <= max_div_8) {
value = (value << 3) | digit;
continue;
}
/* Bah. We're just overflowed. */
warn("Integer overflow in octal number");
overflowed = TRUE;
value_nv = (NV) value;
}
value_nv *= 8.0;
/* If an NV has not enough bits in its mantissa to
* represent a UV this summing of small low-order numbers
* is a waste of time (because the NV cannot preserve
* the low-order bits anyway): we could just remember when
* did we overflow and in the end just multiply value_nv by the
* right amount of 8-tuples. */
value_nv += (NV)digit;
continue;
}
if (digit == ('_' - '0') && len && allow_underscores
&& (digit = s[1] - '0') && (digit >= 0 && digit <= 7))
{
--len;
++s;
goto redo;
}
/* Allow \octal to work the DWIM way (that is, stop scanning
* as soon as non-octal characters are seen, complain only iff
* someone seems to want to use the digits eight and nine). */
if (digit == 8 || digit == 9) {
if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT))
warn("Illegal octal digit '%c' ignored", *s);
}
break;
}
if ( ( overflowed && value_nv > 4294967295.0)
#if UVSIZE > 4
|| (!overflowed && value > 0xffffffff )
#endif
) {
warn("Octal number > 037777777777 non-portable");
}
*len_p = s - start;
if (!overflowed) {
*flags = 0;
return value;
}
*flags = PERL_SCAN_GREATER_THAN_UV_MAX;
if (result)
*result = value_nv;
return UV_MAX;
}
#endif
#endif
#if !defined(my_snprintf)
#if defined(NEED_my_snprintf)
static int DPPP_(my_my_snprintf)(char * buffer, const Size_t len, const char * format, ...);
static
#else
extern int DPPP_(my_my_snprintf)(char * buffer, const Size_t len, const char * format, ...);
#endif
#define my_snprintf DPPP_(my_my_snprintf)
#define Perl_my_snprintf DPPP_(my_my_snprintf)
#if defined(NEED_my_snprintf) || defined(NEED_my_snprintf_GLOBAL)
int
DPPP_(my_my_snprintf)(char *buffer, const Size_t len, const char *format, ...)
{
dTHX;
int retval;
va_list ap;
va_start(ap, format);
#ifdef HAS_VSNPRINTF
retval = vsnprintf(buffer, len, format, ap);
#else
retval = vsprintf(buffer, format, ap);
#endif
va_end(ap);
if (retval >= (int)len)
Perl_croak(aTHX_ "panic: my_snprintf buffer overflow");
return retval;
}
#endif
#endif
#ifdef NO_XSLOCKS
# ifdef dJMPENV
# define dXCPT dJMPENV; int rEtV = 0
# define XCPT_TRY_START JMPENV_PUSH(rEtV); if (rEtV == 0)
# define XCPT_TRY_END JMPENV_POP;
#endif
#define my_strlcat DPPP_(my_my_strlcat)
#define Perl_my_strlcat DPPP_(my_my_strlcat)
#if defined(NEED_my_strlcat) || defined(NEED_my_strlcat_GLOBAL)
Size_t
DPPP_(my_my_strlcat)(char *dst, const char *src, Size_t size)
{
Size_t used, length, copy;
used = strlen(dst);
length = strlen(src);
if (size > 0 && used < size - 1) {
copy = (length >= size - used) ? size - used - 1 : length;
memcpy(dst + used, src, copy);
dst[used + copy] = '\0';
}
return used + length;
}
#endif
#endif
#if !defined(my_strlcpy)
#if defined(NEED_my_strlcpy)
static Size_t DPPP_(my_my_strlcpy)(char * dst, const char * src, Size_t size);
static
#else
extern Size_t DPPP_(my_my_strlcpy)(char * dst, const char * src, Size_t size);
#endif
#define my_strlcpy DPPP_(my_my_strlcpy)
#define Perl_my_strlcpy DPPP_(my_my_strlcpy)
#if defined(NEED_my_strlcpy) || defined(NEED_my_strlcpy_GLOBAL)
Size_t
DPPP_(my_my_strlcpy)(char *dst, const char *src, Size_t size)
{
Size_t length, copy;
length = strlen(src);
if (size > 0) {
copy = (length >= size) ? size - 1 : length;
memcpy(dst, src, copy);
dst[copy] = '\0';
}
return length;
}
#endif
#endif
#endif /* _P_P_PORTABILITY_H_ */
/* End of File ppport.h */
samples/add.pl view on Meta::CPAN
use strict;
use warnings;
use AI::FANN qw(:all);
my $n = 500;
if ($ARGV[0] eq 'train') {
# create an ANN with 2 inputs, a hidden layer with 3 neurons and an
# output layer with 1 neuron:
my $ann = AI::FANN->new_standard(2, 5, 3, 1);
$ann->hidden_activation_function(FANN_SIGMOID_SYMMETRIC);
$ann->output_activation_function(FANN_SIGMOID_SYMMETRIC);
my $train = AI::FANN::TrainData->new_empty($n, 2, 1);
for (0..$n-1) {
my $a = rand(2) - 1;
my $b = rand(2) - 1;
my $c = 0.5 * ($a + $b);
$train->data($_, [$a, $b], [$c]);
}
$ann->train_on_data($train, 25000, 250, 0.00001);
$ann->save("add.ann");
}
elsif ($ARGV[0] eq 'test') {
my $ann = AI::FANN->new_from_file("add.ann");
for (1..10) {
my $a = rand(2) - 1;
my $b = rand(2) - 1;
my $c = 0.5 * ($a + $b);
my $out = $ann->run([$a, $b]);
printf "%f + %f = %f (good: %f, error: %4.1f%%)\n",
$a, $b, $out->[0], $c, 50*abs($out->[0] - $c);
}
}
else {
die "bad action\n"
}
samples/ox.pl view on Meta::CPAN
use GD;
use AI::FANN qw(:all);
my $num = 500;
my $size = 16;
$| = 1;
sub draw_o {
my ($im, $color) = @_;
my $r = int (0.2 + rand(0.25 * $size));
my $x0 = $r + int rand($size - 2 * $r);
my $y0 = $r + int rand($size - 2 * $r);
$im->arc($x0, $y0, $r, $r, 0, 360, $color);
return 2*$r/$size
}
sub draw_x {
my ($im, $color) = @_;
my $r = int (0.2 + rand(0.25 * $size));
my $x0 = $r + int rand($size - 2 * $r);
my $y0 = $r + int rand($size - 2 * $r);
$im->line($x0-$r, $y0-$r, $x0+$r, $y0+$r, $color);
$im->line($x0-$r, $y0+$r, $x0+$r, $y0-$r, $color);
return 2*$r/$size
}
sub image_to_input {
my ($im, $type) = @_;
my @data;
for my $x (0..$size-1) {
for my $y (0..$size-1) {
push @data, $im->getPixel($x, $y);
}
}
return \@data;
}
sub make_train {
my $train = AI::FANN::TrainData->new_empty($num, $size * $size, 2);
for (0..$num - 1) {
print ".";
my $im = GD::Image->new($size, $size);
my $white = $im->colorAllocate(255,255,255);
my $black = $im->colorAllocate(0,0,0);
my $type = (rand > .5);
my $r = $type ? draw_x($im, $black) : draw_o($im, $black);
$train->data($_, image_to_input($im), [$type, $r]);
}
print "\n";
my $ann = AI::FANN->new_standard(@_);
for (1..40) {
$ann->train_on_data($train, 100, 1, 0.0001);
# $ann->print_connections;
$ann->print_parameters;
$ann->save("ox.ann");
}
}
sub make_test {
my $rep = shift;
my $ann = AI::FANN->new_from_file("ox.ann");
print "ann read\n";
for (0..$rep - 1) {
my $im = GD::Image->new($size, $size);
my $white = $im->colorAllocate(255,255,255);
my $black = $im->colorAllocate(0,0,0);
my $type = (rand > .5);
my $r = $type ? draw_x($im, $black) : draw_o($im, $black);
my $out = $ann->run(image_to_input($im));
printf ("type: %f, r: %4.2f out type: %f, r: %4.2f\n", $type, $r, $out->[0], $out->[1]);
}
}
if ($ARGV[0] eq 'train') {
make_train($size * $size, 4 * $size * $size, 240, 200, 60, 20, 2);
}
elsif ($ARGV[0] eq 'test') {
make_test($ARGV[1] || 10);
}
else {
die "wrong action"
}
samples/xor.pl view on Meta::CPAN
#!/usr/bin/perl
use strict;
use warnings;
use AI::FANN qw(:all);
if ($ARGV[0] eq 'train') {
# create an ANN with 2 inputs, a hidden layer with 3 neurons and an
# output layer with 1 neuron:
my $ann = AI::FANN->new_standard(2, 3, 1);
$ann->hidden_activation_function(FANN_SIGMOID_SYMMETRIC);
$ann->output_activation_function(FANN_SIGMOID_SYMMETRIC);
# create the training data for a XOR operator:
my $xor_train = AI::FANN::TrainData->new( [-1, -1], [-1],
[-1, 1], [1],
[1, -1], [1],
[1, 1], [-1] );
$ann->train_on_data($xor_train, 500000, 100, 0.0001);
$ann->save("xor.ann");
}
elsif ($ARGV[0] eq 'test') {
my $ann = AI::FANN->new_from_file("xor.ann");
for my $a (-1, 1) {
for my $b (-1, 1) {
my $out = $ann->run([$a, $b]);
printf "xor(%f, %f) = %f\n", $a, $b, $out->[0];
}
}
}
else {
die "bad action\n"
}
#!/usr/bin/perl
use strict;
use Test::More;
plan skip_all => "Only the author needs to check that POD docs are right"
unless eval "no warnings; getlogin eq 'salva'";
eval "use Test::Pod 1.00";
plan skip_all => "Test::Pod 1.00 required for testing POD" if $@;
all_pod_files_ok( all_pod_files( qw(blib) ) );
enum fann_activationfunc_enum T_UV
enum fann_train_enum T_FANN_TRAIN_ENUM
enum fann_activationfunc_enum T_FANN_ACTIVATIONFUNC_ENUM
enum fann_errorfunc_enum T_FANN_ERRORFUNC_ENUM
enum fann_stopfunc_enum T_STOPFUNC_ENUM
INPUT
T_PTROBJ_MAGIC
$var = ($type)_sv2obj(aTHX_ $arg, \"${type}\", 1);
T_FTA_INPUT
$var = _sv2fta(aTHX_ $arg, self->num_input, WANT_MORTAL, \"${var}\");
T_FTA_OUTPUT
$var = _sv2fta(aTHX_ $arg, self->num_output, WANT_MORTAL, \"${var}\");
T_FANN_TRAIN_ENUM
$var = _sv2fann_train_enum($arg)
T_FANN_ACTIVATIONFUNC_ENUM
$var = _sv2fann_activationfunc_enum($arg)
T_FANN_ERRORFUNC_ENUM
$var = _sv2fann_errorfunc_enum($arg)
T_STOPFUNC_ENUM
$var = _sv2fann_stopfunc_enum($arg)
OUTPUT
T_PTROBJ_MAGIC
$arg = _obj2sv(aTHX_ $var, ST(0), "$type");
T_FTA_OUTPUT
$arg = _fta2sv(aTHX_ $var, self->num_output);
T_FANN_TRAIN_ENUM
$arg = _fann_train_enum2sv($var);
T_FANN_ACTIVATIONFUNC_ENUM
$arg = _fann_activationfunc_enum2sv($var);
T_FANN_ERRORFUNC_ENUM
$arg = _fann_errorfunc_enum2sv($var);
T_STOPFUNC_ENUM
$arg = _fann_stopfunc_enum2sv($var);
( run in 1.085 second using v1.01-cache-2.11-cpan-4d50c553e7e )