mirror of
https://github.com/postgres/postgres.git
synced 2025-05-13 01:13:08 -04:00
The parenthesized style has only been used in a few modules. Change that to use the style that is predominant across the whole tree. Reviewed-by: Michael Paquier <michael.paquier@gmail.com> Reviewed-by: Ryan Murphy <ryanfmurphy@gmail.com>
1054 lines
18 KiB
C
1054 lines
18 KiB
C
/* src/interfaces/ecpg/compatlib/informix.c */
|
|
|
|
#define POSTGRES_ECPG_INTERNAL
|
|
#include "postgres_fe.h"
|
|
|
|
#include <math.h>
|
|
#include <ctype.h>
|
|
#include <limits.h>
|
|
|
|
#include <ecpgtype.h>
|
|
#include <ecpg_informix.h>
|
|
#include <pgtypes_error.h>
|
|
#include <pgtypes_date.h>
|
|
#include <pgtypes_numeric.h>
|
|
#include <sqltypes.h>
|
|
#include <sqlca.h>
|
|
#include <ecpgerrno.h>
|
|
|
|
/* this is also defined in ecpglib/misc.c, by defining it twice we don't have to export the symbol */
|
|
|
|
static struct sqlca_t sqlca_init =
|
|
{
|
|
{
|
|
'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '
|
|
},
|
|
sizeof(struct sqlca_t),
|
|
0,
|
|
{
|
|
0,
|
|
{
|
|
0
|
|
}
|
|
},
|
|
{
|
|
'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '
|
|
},
|
|
{
|
|
0, 0, 0, 0, 0, 0
|
|
},
|
|
{
|
|
0, 0, 0, 0, 0, 0, 0, 0
|
|
},
|
|
{
|
|
'0', '0', '0', '0', '0'
|
|
}
|
|
};
|
|
static int
|
|
deccall2(decimal *arg1, decimal *arg2, int (*ptr) (numeric *, numeric *))
|
|
{
|
|
numeric *a1,
|
|
*a2;
|
|
int i;
|
|
|
|
if ((a1 = PGTYPESnumeric_new()) == NULL)
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
|
|
if ((a2 = PGTYPESnumeric_new()) == NULL)
|
|
{
|
|
PGTYPESnumeric_free(a1);
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
}
|
|
|
|
if (PGTYPESnumeric_from_decimal(arg1, a1) != 0)
|
|
{
|
|
PGTYPESnumeric_free(a1);
|
|
PGTYPESnumeric_free(a2);
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
}
|
|
|
|
if (PGTYPESnumeric_from_decimal(arg2, a2) != 0)
|
|
{
|
|
PGTYPESnumeric_free(a1);
|
|
PGTYPESnumeric_free(a2);
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
}
|
|
|
|
i = (*ptr) (a1, a2);
|
|
|
|
PGTYPESnumeric_free(a1);
|
|
PGTYPESnumeric_free(a2);
|
|
|
|
return i;
|
|
}
|
|
|
|
static int
|
|
deccall3(decimal *arg1, decimal *arg2, decimal *result, int (*ptr) (numeric *, numeric *, numeric *))
|
|
{
|
|
numeric *a1,
|
|
*a2,
|
|
*nres;
|
|
int i;
|
|
|
|
/*
|
|
* we must NOT set the result to NULL here because it may be the same
|
|
* variable as one of the arguments
|
|
*/
|
|
if (risnull(CDECIMALTYPE, (char *) arg1) || risnull(CDECIMALTYPE, (char *) arg2))
|
|
return 0;
|
|
|
|
if ((a1 = PGTYPESnumeric_new()) == NULL)
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
|
|
if ((a2 = PGTYPESnumeric_new()) == NULL)
|
|
{
|
|
PGTYPESnumeric_free(a1);
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
}
|
|
|
|
if ((nres = PGTYPESnumeric_new()) == NULL)
|
|
{
|
|
PGTYPESnumeric_free(a1);
|
|
PGTYPESnumeric_free(a2);
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
}
|
|
|
|
if (PGTYPESnumeric_from_decimal(arg1, a1) != 0)
|
|
{
|
|
PGTYPESnumeric_free(a1);
|
|
PGTYPESnumeric_free(a2);
|
|
PGTYPESnumeric_free(nres);
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
}
|
|
|
|
if (PGTYPESnumeric_from_decimal(arg2, a2) != 0)
|
|
{
|
|
PGTYPESnumeric_free(a1);
|
|
PGTYPESnumeric_free(a2);
|
|
PGTYPESnumeric_free(nres);
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
}
|
|
|
|
i = (*ptr) (a1, a2, nres);
|
|
|
|
if (i == 0) /* No error */
|
|
{
|
|
|
|
/* set the result to null in case it errors out later */
|
|
rsetnull(CDECIMALTYPE, (char *) result);
|
|
PGTYPESnumeric_to_decimal(nres, result);
|
|
}
|
|
|
|
PGTYPESnumeric_free(nres);
|
|
PGTYPESnumeric_free(a1);
|
|
PGTYPESnumeric_free(a2);
|
|
|
|
return i;
|
|
}
|
|
|
|
/* we start with the numeric functions */
|
|
int
|
|
decadd(decimal *arg1, decimal *arg2, decimal *sum)
|
|
{
|
|
errno = 0;
|
|
deccall3(arg1, arg2, sum, PGTYPESnumeric_add);
|
|
|
|
if (errno == PGTYPES_NUM_OVERFLOW)
|
|
return ECPG_INFORMIX_NUM_OVERFLOW;
|
|
else if (errno == PGTYPES_NUM_UNDERFLOW)
|
|
return ECPG_INFORMIX_NUM_UNDERFLOW;
|
|
else if (errno != 0)
|
|
return -1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
deccmp(decimal *arg1, decimal *arg2)
|
|
{
|
|
return deccall2(arg1, arg2, PGTYPESnumeric_cmp);
|
|
}
|
|
|
|
void
|
|
deccopy(decimal *src, decimal *target)
|
|
{
|
|
memcpy(target, src, sizeof(decimal));
|
|
}
|
|
|
|
static char *
|
|
ecpg_strndup(const char *str, size_t len)
|
|
{
|
|
size_t real_len = strlen(str);
|
|
int use_len = (int) ((real_len > len) ? len : real_len);
|
|
|
|
char *new = malloc(use_len + 1);
|
|
|
|
if (new)
|
|
{
|
|
memcpy(new, str, use_len);
|
|
new[use_len] = '\0';
|
|
}
|
|
else
|
|
errno = ENOMEM;
|
|
|
|
return new;
|
|
}
|
|
|
|
int
|
|
deccvasc(char *cp, int len, decimal *np)
|
|
{
|
|
char *str;
|
|
int ret = 0;
|
|
numeric *result;
|
|
|
|
rsetnull(CDECIMALTYPE, (char *) np);
|
|
if (risnull(CSTRINGTYPE, cp))
|
|
return 0;
|
|
|
|
str = ecpg_strndup(cp, len); /* decimal_in always converts the complete
|
|
* string */
|
|
if (!str)
|
|
ret = ECPG_INFORMIX_NUM_UNDERFLOW;
|
|
else
|
|
{
|
|
errno = 0;
|
|
result = PGTYPESnumeric_from_asc(str, NULL);
|
|
if (!result)
|
|
{
|
|
switch (errno)
|
|
{
|
|
case PGTYPES_NUM_OVERFLOW:
|
|
ret = ECPG_INFORMIX_NUM_OVERFLOW;
|
|
break;
|
|
case PGTYPES_NUM_BAD_NUMERIC:
|
|
ret = ECPG_INFORMIX_BAD_NUMERIC;
|
|
break;
|
|
default:
|
|
ret = ECPG_INFORMIX_BAD_EXPONENT;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int i = PGTYPESnumeric_to_decimal(result, np);
|
|
|
|
PGTYPESnumeric_free(result);
|
|
if (i != 0)
|
|
ret = ECPG_INFORMIX_NUM_OVERFLOW;
|
|
}
|
|
}
|
|
|
|
free(str);
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
deccvdbl(double dbl, decimal *np)
|
|
{
|
|
numeric *nres;
|
|
int result = 1;
|
|
|
|
rsetnull(CDECIMALTYPE, (char *) np);
|
|
if (risnull(CDOUBLETYPE, (char *) &dbl))
|
|
return 0;
|
|
|
|
nres = PGTYPESnumeric_new();
|
|
if (nres == NULL)
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
|
|
result = PGTYPESnumeric_from_double(dbl, nres);
|
|
if (result == 0)
|
|
result = PGTYPESnumeric_to_decimal(nres, np);
|
|
|
|
PGTYPESnumeric_free(nres);
|
|
return result;
|
|
}
|
|
|
|
int
|
|
deccvint(int in, decimal *np)
|
|
{
|
|
numeric *nres;
|
|
int result = 1;
|
|
|
|
rsetnull(CDECIMALTYPE, (char *) np);
|
|
if (risnull(CINTTYPE, (char *) &in))
|
|
return 0;
|
|
|
|
nres = PGTYPESnumeric_new();
|
|
if (nres == NULL)
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
|
|
result = PGTYPESnumeric_from_int(in, nres);
|
|
if (result == 0)
|
|
result = PGTYPESnumeric_to_decimal(nres, np);
|
|
|
|
PGTYPESnumeric_free(nres);
|
|
return result;
|
|
}
|
|
|
|
int
|
|
deccvlong(long lng, decimal *np)
|
|
{
|
|
numeric *nres;
|
|
int result = 1;
|
|
|
|
rsetnull(CDECIMALTYPE, (char *) np);
|
|
if (risnull(CLONGTYPE, (char *) &lng))
|
|
return 0;
|
|
|
|
nres = PGTYPESnumeric_new();
|
|
if (nres == NULL)
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
|
|
result = PGTYPESnumeric_from_long(lng, nres);
|
|
if (result == 0)
|
|
result = PGTYPESnumeric_to_decimal(nres, np);
|
|
|
|
PGTYPESnumeric_free(nres);
|
|
return result;
|
|
}
|
|
|
|
int
|
|
decdiv(decimal *n1, decimal *n2, decimal *result)
|
|
{
|
|
int i;
|
|
|
|
errno = 0;
|
|
i = deccall3(n1, n2, result, PGTYPESnumeric_div);
|
|
|
|
if (i != 0)
|
|
switch (errno)
|
|
{
|
|
case PGTYPES_NUM_DIVIDE_ZERO:
|
|
return ECPG_INFORMIX_DIVIDE_ZERO;
|
|
break;
|
|
case PGTYPES_NUM_OVERFLOW:
|
|
return ECPG_INFORMIX_NUM_OVERFLOW;
|
|
break;
|
|
default:
|
|
return ECPG_INFORMIX_NUM_UNDERFLOW;
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
decmul(decimal *n1, decimal *n2, decimal *result)
|
|
{
|
|
int i;
|
|
|
|
errno = 0;
|
|
i = deccall3(n1, n2, result, PGTYPESnumeric_mul);
|
|
|
|
if (i != 0)
|
|
switch (errno)
|
|
{
|
|
case PGTYPES_NUM_OVERFLOW:
|
|
return ECPG_INFORMIX_NUM_OVERFLOW;
|
|
break;
|
|
default:
|
|
return ECPG_INFORMIX_NUM_UNDERFLOW;
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
decsub(decimal *n1, decimal *n2, decimal *result)
|
|
{
|
|
int i;
|
|
|
|
errno = 0;
|
|
i = deccall3(n1, n2, result, PGTYPESnumeric_sub);
|
|
|
|
if (i != 0)
|
|
switch (errno)
|
|
{
|
|
case PGTYPES_NUM_OVERFLOW:
|
|
return ECPG_INFORMIX_NUM_OVERFLOW;
|
|
break;
|
|
default:
|
|
return ECPG_INFORMIX_NUM_UNDERFLOW;
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
dectoasc(decimal *np, char *cp, int len, int right)
|
|
{
|
|
char *str;
|
|
numeric *nres;
|
|
|
|
rsetnull(CSTRINGTYPE, (char *) cp);
|
|
if (risnull(CDECIMALTYPE, (char *) np))
|
|
return 0;
|
|
|
|
nres = PGTYPESnumeric_new();
|
|
if (nres == NULL)
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
|
|
if (PGTYPESnumeric_from_decimal(np, nres) != 0)
|
|
{
|
|
PGTYPESnumeric_free(nres);
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
}
|
|
|
|
if (right >= 0)
|
|
str = PGTYPESnumeric_to_asc(nres, right);
|
|
else
|
|
str = PGTYPESnumeric_to_asc(nres, nres->dscale);
|
|
|
|
PGTYPESnumeric_free(nres);
|
|
if (!str)
|
|
return -1;
|
|
|
|
/*
|
|
* TODO: have to take care of len here and create exponential notation if
|
|
* necessary
|
|
*/
|
|
if ((int) (strlen(str) + 1) > len)
|
|
{
|
|
if (len > 1)
|
|
{
|
|
cp[0] = '*';
|
|
cp[1] = '\0';
|
|
}
|
|
free(str);
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
strcpy(cp, str);
|
|
free(str);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int
|
|
dectodbl(decimal *np, double *dblp)
|
|
{
|
|
int i;
|
|
numeric *nres = PGTYPESnumeric_new();
|
|
|
|
if (nres == NULL)
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
|
|
if (PGTYPESnumeric_from_decimal(np, nres) != 0)
|
|
{
|
|
PGTYPESnumeric_free(nres);
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
}
|
|
|
|
i = PGTYPESnumeric_to_double(nres, dblp);
|
|
PGTYPESnumeric_free(nres);
|
|
|
|
return i;
|
|
}
|
|
|
|
int
|
|
dectoint(decimal *np, int *ip)
|
|
{
|
|
int ret;
|
|
numeric *nres = PGTYPESnumeric_new();
|
|
|
|
if (nres == NULL)
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
|
|
if (PGTYPESnumeric_from_decimal(np, nres) != 0)
|
|
{
|
|
PGTYPESnumeric_free(nres);
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
}
|
|
|
|
ret = PGTYPESnumeric_to_int(nres, ip);
|
|
PGTYPESnumeric_free(nres);
|
|
|
|
if (ret == PGTYPES_NUM_OVERFLOW)
|
|
ret = ECPG_INFORMIX_NUM_OVERFLOW;
|
|
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
dectolong(decimal *np, long *lngp)
|
|
{
|
|
int ret;
|
|
numeric *nres = PGTYPESnumeric_new();
|
|
|
|
if (nres == NULL)
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
|
|
if (PGTYPESnumeric_from_decimal(np, nres) != 0)
|
|
{
|
|
PGTYPESnumeric_free(nres);
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
}
|
|
|
|
ret = PGTYPESnumeric_to_long(nres, lngp);
|
|
PGTYPESnumeric_free(nres);
|
|
|
|
if (ret == PGTYPES_NUM_OVERFLOW)
|
|
ret = ECPG_INFORMIX_NUM_OVERFLOW;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Now the date functions */
|
|
int
|
|
rdatestr(date d, char *str)
|
|
{
|
|
char *tmp = PGTYPESdate_to_asc(d);
|
|
|
|
if (!tmp)
|
|
return ECPG_INFORMIX_DATE_CONVERT;
|
|
|
|
/* move to user allocated buffer */
|
|
strcpy(str, tmp);
|
|
free(tmp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*
|
|
* the input for this function is mmddyyyy and any non-numeric
|
|
* character can be used as a separator
|
|
*
|
|
*/
|
|
int
|
|
rstrdate(char *str, date * d)
|
|
{
|
|
return rdefmtdate(d, "mm/dd/yyyy", str);
|
|
}
|
|
|
|
void
|
|
rtoday(date * d)
|
|
{
|
|
PGTYPESdate_today(d);
|
|
return;
|
|
}
|
|
|
|
int
|
|
rjulmdy(date d, short mdy[3])
|
|
{
|
|
int mdy_int[3];
|
|
|
|
PGTYPESdate_julmdy(d, mdy_int);
|
|
mdy[0] = (short) mdy_int[0];
|
|
mdy[1] = (short) mdy_int[1];
|
|
mdy[2] = (short) mdy_int[2];
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
rdefmtdate(date * d, char *fmt, char *str)
|
|
{
|
|
/* TODO: take care of DBCENTURY environment variable */
|
|
/* PGSQL functions allow all centuries */
|
|
|
|
errno = 0;
|
|
if (PGTYPESdate_defmt_asc(d, fmt, str) == 0)
|
|
return 0;
|
|
|
|
switch (errno)
|
|
{
|
|
case PGTYPES_DATE_ERR_ENOSHORTDATE:
|
|
return ECPG_INFORMIX_ENOSHORTDATE;
|
|
case PGTYPES_DATE_ERR_EARGS:
|
|
case PGTYPES_DATE_ERR_ENOTDMY:
|
|
return ECPG_INFORMIX_ENOTDMY;
|
|
case PGTYPES_DATE_BAD_DAY:
|
|
return ECPG_INFORMIX_BAD_DAY;
|
|
case PGTYPES_DATE_BAD_MONTH:
|
|
return ECPG_INFORMIX_BAD_MONTH;
|
|
default:
|
|
return ECPG_INFORMIX_BAD_YEAR;
|
|
}
|
|
}
|
|
|
|
int
|
|
rfmtdate(date d, char *fmt, char *str)
|
|
{
|
|
errno = 0;
|
|
if (PGTYPESdate_fmt_asc(d, fmt, str) == 0)
|
|
return 0;
|
|
|
|
if (errno == ENOMEM)
|
|
return ECPG_INFORMIX_OUT_OF_MEMORY;
|
|
|
|
return ECPG_INFORMIX_DATE_CONVERT;
|
|
}
|
|
|
|
int
|
|
rmdyjul(short mdy[3], date * d)
|
|
{
|
|
int mdy_int[3];
|
|
|
|
mdy_int[0] = mdy[0];
|
|
mdy_int[1] = mdy[1];
|
|
mdy_int[2] = mdy[2];
|
|
PGTYPESdate_mdyjul(mdy_int, d);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
rdayofweek(date d)
|
|
{
|
|
return PGTYPESdate_dayofweek(d);
|
|
}
|
|
|
|
/* And the datetime stuff */
|
|
|
|
void
|
|
dtcurrent(timestamp * ts)
|
|
{
|
|
PGTYPEStimestamp_current(ts);
|
|
}
|
|
|
|
int
|
|
dtcvasc(char *str, timestamp * ts)
|
|
{
|
|
timestamp ts_tmp;
|
|
int i;
|
|
char **endptr = &str;
|
|
|
|
errno = 0;
|
|
ts_tmp = PGTYPEStimestamp_from_asc(str, endptr);
|
|
i = errno;
|
|
if (i)
|
|
/* TODO: rewrite to Informix error codes */
|
|
return i;
|
|
if (**endptr)
|
|
{
|
|
/* extra characters exist at the end */
|
|
return ECPG_INFORMIX_EXTRA_CHARS;
|
|
}
|
|
/* TODO: other Informix error codes missing */
|
|
|
|
/* everything went fine */
|
|
*ts = ts_tmp;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
dtcvfmtasc(char *inbuf, char *fmtstr, timestamp * dtvalue)
|
|
{
|
|
return PGTYPEStimestamp_defmt_asc(inbuf, fmtstr, dtvalue);
|
|
}
|
|
|
|
int
|
|
dtsub(timestamp * ts1, timestamp * ts2, interval * iv)
|
|
{
|
|
return PGTYPEStimestamp_sub(ts1, ts2, iv);
|
|
}
|
|
|
|
int
|
|
dttoasc(timestamp * ts, char *output)
|
|
{
|
|
char *asctime = PGTYPEStimestamp_to_asc(*ts);
|
|
|
|
strcpy(output, asctime);
|
|
free(asctime);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
dttofmtasc(timestamp * ts, char *output, int str_len, char *fmtstr)
|
|
{
|
|
return PGTYPEStimestamp_fmt_asc(ts, output, str_len, fmtstr);
|
|
}
|
|
|
|
int
|
|
intoasc(interval * i, char *str)
|
|
{
|
|
char *tmp;
|
|
|
|
errno = 0;
|
|
tmp = PGTYPESinterval_to_asc(i);
|
|
|
|
if (!tmp)
|
|
return -errno;
|
|
|
|
memcpy(str, tmp, strlen(tmp));
|
|
free(tmp);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* rfmt.c - description
|
|
* by Carsten Wolff <carsten.wolff@credativ.de>, Wed Apr 2 2003
|
|
*/
|
|
|
|
static struct
|
|
{
|
|
long val;
|
|
int maxdigits;
|
|
int digits;
|
|
int remaining;
|
|
char sign;
|
|
char *val_string;
|
|
} value;
|
|
|
|
/**
|
|
* initialize the struct, which holds the different forms
|
|
* of the long value
|
|
*/
|
|
static int
|
|
initValue(long lng_val)
|
|
{
|
|
int i,
|
|
j;
|
|
long l,
|
|
dig;
|
|
|
|
/* set some obvious things */
|
|
value.val = lng_val >= 0 ? lng_val : lng_val * (-1);
|
|
value.sign = lng_val >= 0 ? '+' : '-';
|
|
value.maxdigits = log10(2) * (8 * sizeof(long) - 1);
|
|
|
|
/* determine the number of digits */
|
|
i = 0;
|
|
l = 1;
|
|
do
|
|
{
|
|
i++;
|
|
l *= 10;
|
|
}
|
|
while ((l - 1) < value.val && l <= LONG_MAX / 10);
|
|
|
|
if (l <= LONG_MAX / 10)
|
|
{
|
|
value.digits = i;
|
|
l /= 10;
|
|
}
|
|
else
|
|
value.digits = i + 1;
|
|
|
|
value.remaining = value.digits;
|
|
|
|
/* convert the long to string */
|
|
if ((value.val_string = (char *) malloc(value.digits + 1)) == NULL)
|
|
return -1;
|
|
dig = value.val;
|
|
for (i = value.digits, j = 0; i > 0; i--, j++)
|
|
{
|
|
value.val_string[j] = dig / l + '0';
|
|
dig = dig % l;
|
|
l /= 10;
|
|
}
|
|
value.val_string[value.digits] = '\0';
|
|
return 0;
|
|
}
|
|
|
|
/* return the position oft the right-most dot in some string */
|
|
static int
|
|
getRightMostDot(char *str)
|
|
{
|
|
size_t len = strlen(str);
|
|
int i,
|
|
j;
|
|
|
|
j = 0;
|
|
for (i = len - 1; i >= 0; i--)
|
|
{
|
|
if (str[i] == '.')
|
|
return len - j - 1;
|
|
j++;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/* And finally some misc functions */
|
|
int
|
|
rfmtlong(long lng_val, char *fmt, char *outbuf)
|
|
{
|
|
size_t fmt_len = strlen(fmt);
|
|
size_t temp_len;
|
|
int i,
|
|
j, /* position in temp */
|
|
k,
|
|
dotpos;
|
|
int leftalign = 0,
|
|
blank = 0,
|
|
sign = 0,
|
|
entitydone = 0,
|
|
signdone = 0,
|
|
brackets_ok = 0;
|
|
char *temp;
|
|
char tmp[2] = " ";
|
|
char lastfmt = ' ',
|
|
fmtchar = ' ';
|
|
|
|
temp = (char *) malloc(fmt_len + 1);
|
|
if (!temp)
|
|
{
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
|
|
/* put all info about the long in a struct */
|
|
if (initValue(lng_val) == -1)
|
|
{
|
|
free(temp);
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
|
|
/* '<' is the only format, where we have to align left */
|
|
if (strchr(fmt, (int) '<'))
|
|
leftalign = 1;
|
|
|
|
/* '(' requires ')' */
|
|
if (strchr(fmt, (int) '(') && strchr(fmt, (int) ')'))
|
|
brackets_ok = 1;
|
|
|
|
/* get position of the right-most dot in the format-string */
|
|
/* and fill the temp-string wit '0's up to there. */
|
|
dotpos = getRightMostDot(fmt);
|
|
|
|
/* start to parse the formatstring */
|
|
temp[0] = '\0';
|
|
k = value.digits - 1; /* position in the value_string */
|
|
for (i = fmt_len - 1, j = 0; i >= 0; i--, j++)
|
|
{
|
|
/* qualify, where we are in the value_string */
|
|
if (k < 0)
|
|
{
|
|
blank = 1;
|
|
if (k == -1)
|
|
sign = 1;
|
|
if (leftalign)
|
|
{
|
|
/* can't use strncat(,,0) here, Solaris would freek out */
|
|
if (sign)
|
|
if (signdone)
|
|
{
|
|
temp[j] = '\0';
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* if we're right side of the right-most dot, print '0' */
|
|
if (dotpos >= 0 && dotpos <= i)
|
|
{
|
|
if (dotpos < i)
|
|
{
|
|
if (fmt[i] == ')')
|
|
tmp[0] = value.sign == '-' ? ')' : ' ';
|
|
else
|
|
tmp[0] = '0';
|
|
}
|
|
else
|
|
tmp[0] = '.';
|
|
strcat(temp, tmp);
|
|
continue;
|
|
}
|
|
/* the ',' needs special attention, if it is in the blank area */
|
|
if (blank && fmt[i] == ',')
|
|
fmtchar = lastfmt;
|
|
else
|
|
fmtchar = fmt[i];
|
|
/* waiting for the sign */
|
|
if (k < 0 && leftalign && sign && !signdone && fmtchar != '+' && fmtchar != '-')
|
|
continue;
|
|
/* analyse this format-char */
|
|
switch (fmtchar)
|
|
{
|
|
case ',':
|
|
tmp[0] = ',';
|
|
k++;
|
|
break;
|
|
case '*':
|
|
if (blank)
|
|
tmp[0] = '*';
|
|
else
|
|
tmp[0] = value.val_string[k];
|
|
break;
|
|
case '&':
|
|
if (blank)
|
|
tmp[0] = '0';
|
|
else
|
|
tmp[0] = value.val_string[k];
|
|
break;
|
|
case '#':
|
|
if (blank)
|
|
tmp[0] = ' ';
|
|
else
|
|
tmp[0] = value.val_string[k];
|
|
break;
|
|
case '-':
|
|
if (sign && value.sign == '-' && !signdone)
|
|
{
|
|
tmp[0] = '-';
|
|
signdone = 1;
|
|
}
|
|
else if (blank)
|
|
tmp[0] = ' ';
|
|
else
|
|
tmp[0] = value.val_string[k];
|
|
break;
|
|
case '+':
|
|
if (sign && !signdone)
|
|
{
|
|
tmp[0] = value.sign;
|
|
signdone = 1;
|
|
}
|
|
else if (blank)
|
|
tmp[0] = ' ';
|
|
else
|
|
tmp[0] = value.val_string[k];
|
|
break;
|
|
case '(':
|
|
if (sign && brackets_ok && value.sign == '-')
|
|
tmp[0] = '(';
|
|
else if (blank)
|
|
tmp[0] = ' ';
|
|
else
|
|
tmp[0] = value.val_string[k];
|
|
break;
|
|
case ')':
|
|
if (brackets_ok && value.sign == '-')
|
|
tmp[0] = ')';
|
|
else
|
|
tmp[0] = ' ';
|
|
break;
|
|
case '$':
|
|
if (blank && !entitydone)
|
|
{
|
|
tmp[0] = '$';
|
|
entitydone = 1;
|
|
}
|
|
else if (blank)
|
|
tmp[0] = ' ';
|
|
else
|
|
tmp[0] = value.val_string[k];
|
|
break;
|
|
case '<':
|
|
tmp[0] = value.val_string[k];
|
|
break;
|
|
default:
|
|
tmp[0] = fmt[i];
|
|
}
|
|
strcat(temp, tmp);
|
|
lastfmt = fmt[i];
|
|
k--;
|
|
}
|
|
/* safety-net */
|
|
temp[fmt_len] = '\0';
|
|
|
|
/* reverse the temp-string and put it into the outbuf */
|
|
temp_len = strlen(temp);
|
|
outbuf[0] = '\0';
|
|
for (i = temp_len - 1; i >= 0; i--)
|
|
{
|
|
tmp[0] = temp[i];
|
|
strcat(outbuf, tmp);
|
|
}
|
|
outbuf[temp_len] = '\0';
|
|
|
|
/* cleaning up */
|
|
free(temp);
|
|
free(value.val_string);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
rupshift(char *str)
|
|
{
|
|
for (; *str != '\0'; str++)
|
|
if (islower((unsigned char) *str))
|
|
*str = toupper((unsigned char) *str);
|
|
return;
|
|
}
|
|
|
|
int
|
|
byleng(char *str, int len)
|
|
{
|
|
for (len--; str[len] && str[len] == ' '; len--);
|
|
return (len + 1);
|
|
}
|
|
|
|
void
|
|
ldchar(char *src, int len, char *dest)
|
|
{
|
|
int dlen = byleng(src, len);
|
|
|
|
memmove(dest, src, dlen);
|
|
dest[dlen] = '\0';
|
|
}
|
|
|
|
int
|
|
rgetmsg(int msgnum, char *s, int maxsize)
|
|
{
|
|
(void) msgnum; /* keep the compiler quiet */
|
|
(void) s; /* keep the compiler quiet */
|
|
(void) maxsize; /* keep the compiler quiet */
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
rtypalign(int offset, int type)
|
|
{
|
|
(void) offset; /* keep the compiler quiet */
|
|
(void) type; /* keep the compiler quiet */
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
rtypmsize(int type, int len)
|
|
{
|
|
(void) type; /* keep the compiler quiet */
|
|
(void) len; /* keep the compiler quiet */
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
rtypwidth(int sqltype, int sqllen)
|
|
{
|
|
(void) sqltype; /* keep the compiler quiet */
|
|
(void) sqllen; /* keep the compiler quiet */
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
ECPG_informix_set_var(int number, void *pointer, int lineno)
|
|
{
|
|
ECPGset_var(number, pointer, lineno);
|
|
}
|
|
|
|
void *
|
|
ECPG_informix_get_var(int number)
|
|
{
|
|
return ECPGget_var(number);
|
|
}
|
|
|
|
void
|
|
ECPG_informix_reset_sqlca(void)
|
|
{
|
|
struct sqlca_t *sqlca = ECPGget_sqlca();
|
|
|
|
if (sqlca == NULL)
|
|
return;
|
|
|
|
memcpy((char *) sqlca, (char *) &sqlca_init, sizeof(struct sqlca_t));
|
|
}
|
|
|
|
int
|
|
rsetnull(int t, char *ptr)
|
|
{
|
|
ECPGset_noind_null(t, ptr);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
risnull(int t, char *ptr)
|
|
{
|
|
return ECPGis_noind_null(t, ptr);
|
|
}
|