/* -*- c -*-
* File: pstring.h
* Author: Igor Vlasenko <vlasenko@imath.kiev.ua>
* Created: Fri Jul 1 20:11:51 2005
*
* $Id$
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <string.h>
#include "pstring.h"
#include "tmpllog.h"
#include "exprval.h"
#include "pmiscdef.h" /*for snprintf */
static
PSTRING
double_to_pstring (double number, char buffer[], size_t bufsize) {
size_t len=0;
size_t tmplen=0;
PSTRING retval;
snprintf(buffer,bufsize,"%f",number);
len=strlen(buffer);
tmplen=len;
/* removing trailing 0 as 2.00000... */
while (buffer[tmplen-1]=='0' && tmplen-->0);
if (buffer[tmplen-1]=='.') {
tmplen--;
len=tmplen;
}
retval.begin=buffer;
retval.endnext=buffer+len;
return retval;
}
static
PSTRING
int_to_pstring (EXPR_int64 number, char buffer[], size_t bufsize) {
size_t len=0;
PSTRING retval;
snprintf(buffer, bufsize,"%" EXPR_PRId64 , number);
len=strlen(buffer);
retval.begin=buffer;
retval.endnext=buffer+len;
return retval;
}
static
int
pstring_ge(PSTRING a, PSTRING b) {
const char* in_a=a.begin;
const char* in_b=b.begin;
if (in_b==NULL) return 1;
if (in_a==NULL) return 0;
while (in_a<a.endnext && in_b < b.endnext && *in_a++==*in_b++);
if ((in_a==a.endnext && in_b==b.endnext) || *(--in_a) >= *(--in_b) ) return 1; else return 0;
}
static
int
pstring_le(PSTRING a, PSTRING b) {
const char* in_a=a.begin;
const char* in_b=b.begin;
if (in_a==NULL) return 1;
if (in_b==NULL) return 0;
while (in_a<a.endnext && in_b < b.endnext && *in_a++==*in_b++);
if ((in_a==a.endnext && in_b==b.endnext) || *(--in_a) <= *(--in_b) ) return 1; else return 0;
}
static
int
pstring_ne(PSTRING a, PSTRING b) {
const char* in_a=a.begin;
const char* in_b=b.begin;
if (in_a==NULL || in_b==NULL) return in_a != in_b;
while (in_a<a.endnext && in_b < b.endnext && *in_a++==*in_b++);
if (in_a==a.endnext && in_b==b.endnext && *(--in_a) == *(--in_b)) return 0; else return 1;
}
static
int
pstring_eq(PSTRING a, PSTRING b) {
const char* in_a=a.begin;
const char* in_b=b.begin;
if (in_a==NULL || in_b==NULL) return in_a == in_b;
if (in_a==a.endnext) return in_b==b.endnext;
while (in_a<a.endnext && in_b < b.endnext && *in_a++==*in_b++);
if (in_a==a.endnext && in_b==b.endnext && *(--in_a) == *(--in_b)) return 1; else return 0;
}
static
int
pstring_gt(PSTRING a, PSTRING b) {
const char* in_a=a.begin;
const char* in_b=b.begin;
if (in_a==NULL) return 0;
if (in_b==NULL) return 1;
while (in_a<a.endnext && in_b < b.endnext && *in_a++==*in_b++);
if ((in_b==b.endnext && in_a!=a.endnext)
|| (*(--in_a) > *(--in_b)) ) return 1; else return 0;
}
static
int
pstring_lt(PSTRING a, PSTRING b) {
const char* in_a=a.begin;
const char* in_b=b.begin;
if (in_b==NULL) return 0;
if (in_a==NULL) return 1;
while (in_a<a.endnext && in_b < b.endnext && *in_a++==*in_b++);
if ((in_b!=b.endnext && in_a==a.endnext)
|| *(--in_a) < *(--in_b) ) return 1; else return 0;
}
static
int
re_notlike(struct expr_parser* exprobj, PSTRING a, PSTRING b) {
return ! re_like(exprobj, a,b);
}
#ifdef HAVE_PCRE2
/* https://github.com/luvit/pcre2/blob/master/src/pcre2demo.c */
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
static
int
re_like(struct expr_parser* exprobj, PSTRING a, PSTRING b) {
pcre2_code* re;
int rc, errornumber;
PCRE2_SIZE erroroffset;
PCRE2_SPTR subject=(PCRE2_SPTR)a.begin;
size_t subject_length=(a.endnext-a.begin);
char* pattern;
pcre2_match_data *match_data;
if (subject==NULL) {
log_expr(exprobj,TMPL_LOG_INFO, "regular expression: applied to undefined value.\n");
return 0;
}
if (b.begin==NULL || (b.endnext-b.begin)==0) {
log_expr(exprobj,TMPL_LOG_INFO, "regular expression: the pattern is empty or undefined.\n");
return 1;
}
pattern=(char*)malloc(b.endnext-b.begin);
if (pattern==NULL) {
log_expr(exprobj,TMPL_LOG_ERROR, "regular expression: memory allocation failed.\n");
return 0;
}
strncpy(pattern, b.begin, (b.endnext-b.begin));
*(pattern+(b.endnext-b.begin))=0;
re = pcre2_compile((PCRE2_SPTR)pattern,PCRE2_ZERO_TERMINATED,0,&errornumber,&erroroffset,NULL);
free(pattern);
if (re==NULL) {
PCRE2_UCHAR buffer[256];
pcre2_get_error_message(errornumber, buffer, sizeof(buffer));
log_expr(exprobj,TMPL_LOG_ERROR, "regular expression: PCRE2 compilation failed at offset %zd: %s\n",
erroroffset, buffer);
return 0;
}
match_data = pcre2_match_data_create_from_pattern(re, NULL);
rc = pcre2_match(re,subject,subject_length,0,0,match_data,NULL);
/* Matching failed: handle error cases */
if(rc<0 && PCRE2_ERROR_NOMATCH != rc) {
PCRE2_UCHAR buffer[256];
pcre2_get_error_message(errornumber, buffer, sizeof(buffer));
log_expr(exprobj,TMPL_LOG_ERROR, "regular expression: PCRE2 reported run error %d: %s\n",errornumber, buffer);
}
pcre2_match_data_free(match_data); /* Release memory used for the match */
pcre2_code_free(re); /* data and the compiled pattern. */
return (rc<0)?0:1;
}
#else
#ifdef HAVE_PCRE
#include <pcre.h>
static
int
re_like(struct expr_parser* exprobj, PSTRING a, PSTRING b) {
pcre* re;
int ovector[30];
int rc, erroffset;
const char* error;
const char* subject=a.begin;
int subject_length=(int)(a.endnext-a.begin);
char* pattern;
if (subject==NULL) {
log_expr(exprobj,TMPL_LOG_INFO, "regular expression: applied to undefined value.\n");
return 0;
}
if (b.begin==NULL || (b.endnext-b.begin)==0) {
log_expr(exprobj,TMPL_LOG_INFO, "regular expression: the pattern is empty or undefined.\n");
return 1;
}
pattern=(char*)malloc(b.endnext-b.begin);
if (pattern==NULL) {
log_expr(exprobj,TMPL_LOG_ERROR, "regular expression: memory allocation failed.\n");
return 0;
}
strncpy(pattern, b.begin, (b.endnext-b.begin));
*(pattern+(b.endnext-b.begin))=0;
re = pcre_compile(pattern, 0, &error, &erroffset, NULL); /* default character set */
free(pattern);
if (re==NULL) {
log_expr(exprobj,TMPL_LOG_ERROR, "regular expression: PCRE compilation failed at offset %d: %s\n",
erroffset, error);
return 0;
}
rc=pcre_exec(re, NULL, subject, subject_length, 0, 0, ovector, 30);
return (rc<0)?0:1;
}
#else
static
int
re_like(struct expr_parser* exprobj, PSTRING a, PSTRING b) {
log_expr(exprobj,TMPL_LOG_ERROR,"can't parse the regular expression (sorry, Stanislav Yadykin regexp extension is disabled at compile time) \n");
return 0;
}
#endif
#endif