summaryrefslogtreecommitdiffstats
path: root/src/interfaces/ecpg/compatlib
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:15:05 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:15:05 +0000
commit46651ce6fe013220ed397add242004d764fc0153 (patch)
tree6e5299f990f88e60174a1d3ae6e48eedd2688b2b /src/interfaces/ecpg/compatlib
parentInitial commit. (diff)
downloadpostgresql-14-46651ce6fe013220ed397add242004d764fc0153.tar.xz
postgresql-14-46651ce6fe013220ed397add242004d764fc0153.zip
Adding upstream version 14.5.upstream/14.5upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/interfaces/ecpg/compatlib')
-rw-r--r--src/interfaces/ecpg/compatlib/.gitignore3
-rw-r--r--src/interfaces/ecpg/compatlib/Makefile59
-rw-r--r--src/interfaces/ecpg/compatlib/exports.txt44
-rw-r--r--src/interfaces/ecpg/compatlib/informix.c1027
4 files changed, 1133 insertions, 0 deletions
diff --git a/src/interfaces/ecpg/compatlib/.gitignore b/src/interfaces/ecpg/compatlib/.gitignore
new file mode 100644
index 0000000..926385c
--- /dev/null
+++ b/src/interfaces/ecpg/compatlib/.gitignore
@@ -0,0 +1,3 @@
+/compatlib.def
+/blibecpg_compatdll.def
+/exports.list
diff --git a/src/interfaces/ecpg/compatlib/Makefile b/src/interfaces/ecpg/compatlib/Makefile
new file mode 100644
index 0000000..1c2866f
--- /dev/null
+++ b/src/interfaces/ecpg/compatlib/Makefile
@@ -0,0 +1,59 @@
+#-------------------------------------------------------------------------
+#
+# Makefile for ecpg compatibility library
+#
+# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+# Portions Copyright (c) 1994, Regents of the University of California
+#
+# src/interfaces/ecpg/compatlib/Makefile
+#
+#-------------------------------------------------------------------------
+
+subdir = src/interfaces/ecpg/compatlib
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+
+PGFILEDESC = "ECPG compat - compatibility library for ECPG"
+NAME= ecpg_compat
+SO_MAJOR_VERSION= 3
+SO_MINOR_VERSION= $(MAJORVERSION)
+
+override CPPFLAGS := -I../include -I$(top_srcdir)/src/interfaces/ecpg/include \
+ -I$(libpq_srcdir) -DFRONTEND $(CPPFLAGS)
+override CFLAGS += $(PTHREAD_CFLAGS)
+
+SHLIB_LINK_INTERNAL = -L../ecpglib -lecpg -L../pgtypeslib -lpgtypes $(libpq_pgport_shlib)
+SHLIB_LINK = $(filter -lintl -lm, $(LIBS)) $(PTHREAD_LIBS)
+SHLIB_PREREQS = submake-ecpglib submake-pgtypeslib
+
+SHLIB_EXPORTS = exports.txt
+
+OBJS = \
+ $(WIN32RES) \
+ informix.o
+
+PKG_CONFIG_REQUIRES_PRIVATE = libecpg libpgtypes
+
+all: all-lib
+
+.PHONY: submake-ecpglib submake-pgtypeslib
+
+submake-ecpglib:
+ $(MAKE) -C $(top_builddir)/src/interfaces/ecpg/ecpglib all
+
+submake-pgtypeslib:
+ $(MAKE) -C $(top_builddir)/src/interfaces/ecpg/pgtypeslib all
+
+# Shared library stuff
+include $(top_srcdir)/src/Makefile.shlib
+
+install: all installdirs install-lib
+
+installdirs: installdirs-lib
+
+uninstall: uninstall-lib
+
+clean distclean: clean-lib
+ rm -f $(OBJS)
+
+maintainer-clean: distclean
diff --git a/src/interfaces/ecpg/compatlib/exports.txt b/src/interfaces/ecpg/compatlib/exports.txt
new file mode 100644
index 0000000..86e9ca1
--- /dev/null
+++ b/src/interfaces/ecpg/compatlib/exports.txt
@@ -0,0 +1,44 @@
+# src/interfaces/ecpg/compatlib/exports.txt
+# Functions to be exported by libecpg_compat DLL
+ECPG_informix_get_var 1
+ECPG_informix_set_var 2
+decadd 3
+deccmp 4
+deccopy 5
+deccvasc 6
+deccvdbl 7
+deccvint 8
+deccvlong 9
+decdiv 10
+decmul 11
+decsub 12
+dectoasc 13
+dectodbl 14
+dectoint 15
+dectolong 16
+dtcurrent 17
+dtcvasc 18
+dtcvfmtasc 19
+dtsub 20
+dttoasc 21
+dttofmtasc 22
+intoasc 23
+rdatestr 24
+rdayofweek 25
+rdefmtdate 26
+rfmtdate 27
+rfmtlong 28
+rgetmsg 29
+risnull 30
+rjulmdy 31
+rmdyjul 32
+rsetnull 33
+rstrdate 34
+rtoday 35
+rtypalign 36
+rtypmsize 37
+rtypwidth 38
+rupshift 39
+ldchar 40
+byleng 41
+ECPG_informix_reset_sqlca 42
diff --git a/src/interfaces/ecpg/compatlib/informix.c b/src/interfaces/ecpg/compatlib/informix.c
new file mode 100644
index 0000000..dccf395
--- /dev/null
+++ b/src/interfaces/ecpg/compatlib/informix.c
@@ -0,0 +1,1027 @@
+/* src/interfaces/ecpg/compatlib/informix.c */
+
+#define POSTGRES_ECPG_INTERNAL
+#include "postgres_fe.h"
+
+#include <math.h>
+#include <ctype.h>
+#include <limits.h>
+
+#include "ecpg_informix.h"
+#include "ecpgerrno.h"
+#include "ecpgtype.h"
+#include "pgtypes_date.h"
+#include "pgtypes_error.h"
+#include "pgtypes_numeric.h"
+#include "sqlca.h"
+#include "sqltypes.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));
+}
+
+int
+deccvasc(const char *cp, int len, decimal *np)
+{
+ char *str;
+ int ret = 0;
+ numeric *result;
+
+ rsetnull(CDECIMALTYPE, (char *) np);
+ if (risnull(CSTRINGTYPE, cp))
+ return 0;
+
+ str = pnstrdup(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(const char *str, date * d)
+{
+ return rdefmtdate(d, "mm/dd/yyyy", str);
+}
+
+void
+rtoday(date * d)
+{
+ PGTYPESdate_today(d);
+}
+
+int
+rjulmdy(date d, short *mdy)
+{
+ 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, const char *fmt, const 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, const 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, 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;
+}
+
+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 of the right-most dot in some string */
+static int
+getRightMostDot(const 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, const 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 format-string */
+ 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 freak 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);
+}
+
+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, const char *ptr)
+{
+ return ECPGis_noind_null(t, ptr);
+}