Db-GTM
view release on metacpan or search on metacpan
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#include "gtmxc_types.h" // For GTM call-in function prototypes
#include "string.h" // strlen(), memcpy(), strncmp()
#include "GTM.h" // my prototypes
#include "stdlib.h" // setenv
static void err_gtm(const GtmEnv *gt) {
char *msgbuf = gt ? gt->errmsg : (char *)calloc(1024,sizeof(gtm_char_t));
gtm_zstatus(msgbuf,1024); if(!gt || (gt && !(gt->flags & NO_WARN))) {
warn("GTM ERROR: (%d) %s\n", gt->last_err, msgbuf);
}
if(!gt) free(msgbuf); return;
}
// Returns 1 if you should free the GVN after you're done with it
int packgvn(GtmEnv *gtenv, unsigned len,strpack strs[],
const unsigned flags, gtm_string_t *gvn) {
unsigned i,xlen=(gtenv && !(flags & NO_PREFIX))?gtenv->pfx_elem:0,sz,tmp;
unsigned err=0,freestrs=0; char *ret=NULL,*loc; strpack *seek;
if(!gvn) return; sz = ((len+xlen)>1) ? (len+xlen)*3 : 2; if(xlen) {
sz += (unsigned)gtenv->pfx_length;
for(i=xlen;i--;) if(gtenv->prefix[i].num) sz -= 2;
}
if((flags & TIED) && len == 1 && strchr(strs[0].address,'\034')) {
// Multidimensional array with \034 separators
loc = strs[0].address; while( loc = index(loc,'\034') ) { len++; loc++; }
loc = strs[0].address; freestrs=len; i = 0; sz += (len-1)*3;
strs = (strpack *)calloc(len,sizeof(strpack));
while( loc ) {
ret = index(loc,'\034'); if(ret) *ret = '\0'; tmp = strlen(loc);
strs[i].address = (char *)calloc(tmp+1,sizeof(char));
strs[i].length = tmp; memcpy(strs[i].address, loc, tmp);
loc = ret ? ret+1 : ret; i++;
}
}
// Validate global, calculate final GLVN size
if(len||xlen) ret = (xlen) ? gtenv->prefix->address : strs[0].address;
if(len == 1 && *strs[0].address == '^') {
gvn->address = strs[0].address; gvn->length = strs[0].length; return 0;
} else if(!(len || xlen) || !ret ||
!(xlen || (strs[0].length && strs[0].length <= _GT_MAX_GVNSIZE)) ||
!((*ret >= 'a' && *ret <= 'z') || (*ret >= 'A' && *ret <= 'Z'))
) err++; else for(i=len;i--;) {
if(!strs[i].length && !((flags & ZEROLEN_OK) && i==(len-1))) err++;
else sz += strs[i].length;
if(is_number(strs[i].address)) { sz -= 2; strs[i].num++; }
}
if(err || !sz || sz > _GT_MAX_GVNLENGTH) {
if(!(flags & NO_WARN)) warn("ERROR: Poorly-specified node name.\n");
if(gtenv) {
gtenv->last_err = 1;
sprintf(gtenv->errmsg,"ERROR: Poorly-specified node name.");
}
if(freestrs) strpack_clear(strs,len); gvn->address = NULL; return 0;
} else ret = (char *)calloc(sz+1,sizeof(char)); loc = ret;
*loc = '^'; loc++; for(i=0;i<(len+xlen);i++) {
seek = (i<xlen) ? >env->prefix[i] : &strs[i-xlen];
if(i) {
if(!seek->num) { *loc = '"'; loc++; }
memcpy(loc, seek->address, seek->length); loc += seek->length;
if(!seek->num) { *loc = '"'; loc++; }
*loc = ((i+1) == (len+xlen)) ? ')' : ','; loc++;
} else {
new(...)
ALIAS:
TIEHASH = 1
TIESCALAR = 2
GtmEnvPtr::sub = 3
CODE:
{
strpack *strp, *gvnprefix;
GtmEnv *setup = (GtmEnv *)calloc(1,sizeof(GtmEnv)), *sub;
unsigned i,len=0,tlen=0,err=0; char *test;
#ifdef _GT_NEED_SIGFIX
sig_t sigint;
#endif
setup->errmsg = (char *)calloc(1024,sizeof(char));
setup->xfer_buf = (char *)calloc(_GT_MAX_BLOCKSIZE,sizeof(char));
setup->flags &= (ix == 0 || ix == 3) ? NO_WARN : TIED;
if(items > 256) { warn("Init fail; excessive prefixes...\n"); err++; }
else if(items < 2) { warn("Init fail; no prefix given...\n"); err++; }
else {
if(ix == 3 && sv_isa(ST(0),"GtmEnvPtr") ) {
sub = (GtmEnv *)SvIV((SV*)SvRV(ST(0)));
len = sub->pfx_elem; tlen = sub->pfx_length;
} else {
test = (char *)SvPV(ST(1),i); len = 0; tlen = 0;
if(!((*test>='a' && *test<='z')||(*test>='A' && *test<='Z'))) {
warn("Init fail; invalid starting prefix character.\n"); err++;
}
}
setup->prefix = (strpack *)calloc(items+len-1,sizeof(strpack));
if(ix==3&&sv_isa(ST(0),"GtmEnvPtr")) for(i=sub->pfx_elem;i--;) {
strp = &sub->prefix[i]; gvnprefix = &setup->prefix[i];
gvnprefix->length = strp->length; gvnprefix->num = strp->num;
gvnprefix->address=(char *)calloc(strp->length+1,sizeof(char));
memcpy(gvnprefix->address, strp->address, strp->length);
}
for(i=1;i<items;i++) {
strp = &setup->prefix[i-1+len];
test = (char *)SvPV(ST(i), strp->length);
strp->address = (char *)calloc((strp->length)+1,sizeof(char));
memcpy(strp->address, test, strp->length);
strp->num = is_number(strp->address);
if(!strp->length) { warn("Init fail; null subscript.\n"); err++; }
else tlen += strp->length;
}
setup->pfx_elem = (items+len-1); setup->pfx_length = tlen;
if(tlen > _GT_MAX_GVNLENGTH) {
warn("Init fail; prefix too long...\n"); err++;
}
if(err) { gtenv_clear(setup); }
}
if(!err) {
if(!_GTMinvoc) { // Save terminal settings to restore during END()
#ifdef _GT_NEED_TERMFIX
_GTMterm = (struct termios *)calloc(1,sizeof(struct termios));
tcgetattr(STDIN_FILENO, _GTMterm);
#endif
#ifdef _GT_NEED_SIGFIX
sigint = signal(SIGINT, SIG_DFL); // Save SIGINT handler
#endif
setenv("GTMCI",_GT_GTMCI_LOC,0);
setenv("gtmroutines",_GT_GTMRTN_LOC,0);
setenv("gtmgbldir",_GT_GTMGBL_LOC,0);
setup->last_err = gtm_init();
#ifdef _GT_NEED_SIGFIX
signal(SIGINT, sigint); // Restore SIGINT handler
#endif
} else setup->last_err = 0;
if(setup->last_err) {
err_gtm(setup); gtenv_clear(setup); XSRETURN_UNDEF;
} else {
_GTMinvoc++; setup->gtmEnvId = _GTMinvoc; RETVAL = setup;
}
} else XSRETURN_UNDEF;
}
OUTPUT:
RETVAL
void
gvn2list(...)
ALIAS:
_str2list = 1
GTM::gvn2list = 2
GTM::_str2list = 3
GtmEnvPtr::gvn2list = 4
GtmEnvPtr::_str2list = 5
PPCODE:
{
cppack *start = NULL, *next; SV *ret; unsigned s , x; char *glvn;
s = (ix < 4) ? 0 : 1; if(items < s) XSRETURN_UNDEF;
start = unpackgvn( SvPV(ST(s),x) ); while(start) {
ret = sv_newmortal(); sv_setpv(ret, start->loc); XPUSHs(ret);
next = start->next; free(start); start = next;
}
}
void
list2gvn(...)
ALIAS:
_list2str = 1
GTM::list2gvn = 2
GTM::_list2str = 3
GtmEnvPtr::list2gvn = 4
GtmEnvPtr::_list2str = 5
GtmEnvPtr::node = 6
PPCODE:
{
strpack *args;
GtmEnv *pfx = (ix<4) ? NULL : (GtmEnv *)SvIV((SV*)SvRV(ST(0)));
unsigned i,s = (ix<4) ? 0 : 1, n; SV *ret;
gtm_string_t value, glvn;
EXTEND(SP,1); if(items>s) {
args = (strpack *)calloc(items-s,sizeof(strpack));
for(i=s;i<items;i++)
args[i-s].address = (char *)SvPV(ST(i),args[i-s].length);
n=packgvn(pfx,items-s,args,(ix<4)?NO_PREFIX:0,&glvn); free(args);
} else { n = packgvn(pfx,0,NULL,0,&glvn); }
if(glvn.address) {
ret = sv_newmortal(); sv_setpv(ret, glvn.address); PUSHs(ret);
if(n) free(glvn.address);
} else PUSHs(&PL_sv_undef);
( run in 2.683 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )