## root/dbeng/dbfxp.c

/* [<][>][^][v][top][bottom][index][help] */

## DEFINITIONS

This source file includes following definitions.

1. dbfxp_get
2. dbfxp_put
3. dbfxp_get_subfield
4. dbfxp_put_subfield
5. dbfxp_get_subsubfield
6. dbfxp_put_subsubfield

    /* Database fixed point number API.
       Rick Smereka, Copyright (C) 2002-2004.

       This program is free software; you can redistribute it and/or modify
       it under the terms of the GNU General Public License as published by
       the Free Software Foundation; either version 2 of the License, or
       (at your option) any later version.

       This program is distributed in the hope that it will be useful,
       but WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       GNU General Public License for more details.

       You should have received a copy of the GNU General Public License
       along with this program; if not, get a copy via the Internet at
       http://gnu.org/copyleft/gpl.html or write to the Free Software
       Foundation, Inc., 59 Temple Place, Suite 330, Boston,
       MA 02111-1307 USA

       You can contact the author via email at rsmereka@future-lab.com

       This module contains functions that support read and write of
       database fields which contain fixed point numbers. The numbers
       are stored in database fields without the decimal point. You
       must know where the decimal point belongs. Anytime this module
       is used the fixed-point math API ('fxp') must be linked with
       your program.

       Original Linux version. Ported to 32-bit Windows, DOS and QNX 4.x.
       Jul/2002, Rick Smereka

       Added functions 'dbfxp_get_subfield', 'dbfxp_put_subfield',
       'dbfxp_get_subsubfield' and 'dbfxp_put_subsubfield'. Aug/2002,
       Rick Smereka

       Ported to Debian Linux. Nov/2002, Rick Smereka

       Changed all logging calls from 'sys_log' to 'logman'.
       Mar/2004, Rick Smereka */

    #include "stdhead.h"
    #include "dbfxp.h"
    #include "dbmess.h"
    #include "dbiocode.h"
    #ifdef MULTIUSER
    #include "dbcs.h"
    #else
    #include "dblocal.h"
    #endif

    int dbfxp_get(int tid, int field_no, int sc, struct fxp **r1)
    {
       /* Obtain field contents from the 'tid' table, field 'field_no'.
          The field contents will be used to create a fixed-point
          number ('fxp') with the decimal located in the 'sc'
          position (from the right). Function returns a 'dbeng'
          code with a dynamically allocated 'fxp' structure
          upon success. The 'fxp' structure must be de-allocated
          by the caller. */

       struct fxp *result;
       char mname[] = "dbfxp_get", *field;
       int field_size, ret;

       logman("%s:enter", mname);
       *r1 = FXP_OT_NULL;

       if (tid <= 0)
          {
          db_io_code_log(mname, "out of range[tid]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (field_no <= 0)
          {
          db_io_code_log(mname, "out of range[field_no]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (sc < 0)
          {
          db_io_code_log(mname, "out of range[scale]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       /* get the field size */

       if ((ret = db_get_field_size(tid, field_no, &field_size)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from db_get_field", ret);
          return(ret);
          }

       if (field_size <= 0)
          {
          db_io_code_log(mname, "field is empty", DBENG_NO_SUCH_FIELD);
          return(DBENG_NO_SUCH_FIELD);
          }

       if ((field = (char *)malloc(field_size + 1)) == (char *)NULL)
          {
          dbeng_io_code_log(mname, "alloc fail[field]", DBENG_MEMORY_FAIL);
          return(DBENG_MEMORY_FAIL);
          }

       /* get the field contents and validate */

       if ((ret = db_get_field(tid, field_no, field)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from db_get_field[field]", ret);
          free(field);
          return(ret);
          }

       if (!num(field))
          {
          db_io_code_log(mname, "non-numeric[field]", DBENG_INVALID_FUNCTION);
          free(field);
          return(ret);
          }

       if ((result = fxp_iconv(field)) == FXP_OT_NULL)
          {
          db_io_code_log(mname, "bad rc from fxp_iconv[field]",
                         DBENG_INTERNAL_ERROR);
          free(field);
          return(DBENG_INTERNAL_ERROR);
          }

       /* manually fix-up scale */

       free(field);
       result->scale = sc;
       *r1 = result;
       db_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }

    int dbfxp_put(int tid, int field_no, int sc, struct fxp *r1)
    {
       /* Write a fixed-point number to a database field. The number
          will be written without a decimal point (if any). The
          number will have its scale adjusted (position of the
          decimal point) to 'sc'. The caller must know the number scale.
          A database write will not take place after writing the
          field contents. The field number may be zero indicating an
          append to the record. Function returns a 'dbeng' code. */

       char mname[] = "dbfxp_put", o1[25], o2[25], ch;
       int ret;

       logman("%s:enter", mname);

       if (tid <= 0)
          {
          db_io_code_log(mname, "out of range[tid]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (field_no < 0)
          {
          db_io_code_log(mname, "out of range[field_no]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (r1 == FXP_OT_NULL)
          {
          db_io_code_log(mname, "null[r1]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       logman("%s:tid=%d,fn=%d,sc=%d,cv=%s", mname, tid, field_no, sc,
                     r1->charval);

       if (!fxp_oconv(r1, sc, o1))
          {
          db_io_code_log(mname, "bad rc from fxp_oconv[r1]",
                         DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       /* copy to final output eliminating decimal point */

       fxp_remove_decimal(o1, o2);

       if ((ret = db_put_field(tid, field_no, o2)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from db_put_field[o2]", ret);
          return(ret);
          }

       db_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }

    int dbfxp_get_subfield(int tid, int f, int sf, int sc, struct fxp **r1)
    {
       /* Obtain subfield contents from the 'tid' table, field 'f' and
          subfield 'sf'. The subfield contents will be used to create a
          fixed-point number ('fxp') with the decimal located in the 'sc'
          position (from the right). Function returns a 'dbeng'
          code with a dynamically allocated 'fxp' structure
          upon success. The 'fxp' structure must be de-allocated
          by the caller. The subfield contents must be a number
          (0-9,-) without any decimal point. */

       struct fxp *result;
       char mname[] = "dbfxp_get_subfield", *subfield;
       int subfield_size, ret;

       logman("%s:enter", mname);
       *r1 = FXP_OT_NULL;

       if (tid <= 0)
          {
          db_io_code_log(mname, "out of range[tid]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (f <= 0)
          {
          db_io_code_log(mname, "out of range[f]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (sf <= 0)
          {
          db_io_code_log(mname, "out of range[sf]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (sc < 0)
          {
          db_io_code_log(mname, "out of range[scale]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       /* get the subfield size */

       if ((ret = db_get_subfield_size(tid, f, sf, &subfield_size)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from db_get_subfield", ret);
          return(ret);
          }

       if (subfield_size <= 0)
          {
          db_io_code_log(mname, "subfield is empty", DBENG_NO_SUCH_SUBFIELD);
          return(DBENG_NO_SUCH_SUBFIELD);
          }

       if ((subfield = (char *)malloc(subfield_size + 1)) == (char *)NULL)
          {
          dbeng_io_code_log(mname, "alloc fail[subfield]", DBENG_MEMORY_FAIL);
          return(DBENG_MEMORY_FAIL);
          }

       /* get the subfield contents and validate */

       if ((ret = db_get_subfield(tid, f, sf, subfield)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from db_get_subfield[subfield]", ret);
          free(subfield);
          return(ret);
          }

       if (!num(subfield))
          {
          db_io_code_log(mname, "non-numeric[subfield]", DBENG_INVALID_FUNCTION);
          free(subfield);
          return(ret);
          }

       if ((result = fxp_iconv(subfield)) == FXP_OT_NULL)
          {
          db_io_code_log(mname, "bad rc from fxp_iconv[subfield]",
                         DBENG_INTERNAL_ERROR);
          free(subfield);
          return(DBENG_INTERNAL_ERROR);
          }

       /* manually fix-up scale */

       free(subfield);
       result->scale = sc;
       *r1 = result;
       db_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }

    int dbfxp_put_subfield(int tid, int f, int sf, int sc, struct fxp *r1)
    {
       /* Write a fixed-point number to a database subfield. The number
          will be written without a decimal point (if any). The
          number will have its scale adjusted (position of the
          decimal point) to 'sc'. The caller must know the number scale.
          A database write will not take place after writing the
          subfield contents. The field number or subfield number
          may be zero to indicate an append to the record.
          Function returns a 'dbeng' code. */

       char mname[] = "dbfxp_put_subfield", o1[25], o2[25], ch;
       int ret;

       logman("%s:enter", mname);

       if (tid <= 0)
          {
          db_io_code_log(mname, "out of range[tid]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (f < 0)
          {
          db_io_code_log(mname, "out of range[f]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (sf < 0)
          {
          db_io_code_log(mname, "out of range[sf]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (r1 == FXP_OT_NULL)
          {
          db_io_code_log(mname, "null[r1]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (!fxp_oconv(r1, sc, o1))
          {
          db_io_code_log(mname, "bad rc from fxp_oconv[r1]",
                         DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       /* copy to final output eliminating decimal point */

       fxp_remove_decimal(o1, o2);

       if ((ret = db_put_subfield(tid, f, sf, o2)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from db_put_subfield[o2]", ret);
          return(ret);
          }

       db_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }

    int dbfxp_get_subsubfield(int tid, int f, int sf, int ssf, int sc,
                              struct fxp **r1)
    {
       /* Obtain subsubfield contents from the 'tid' table, field 'f',
          subfield 'sf' and subsubfield 'ssf'. The subsubfield contents
          will be used to create a fixed-point number ('fxp') with the
          decimal located in the 'sc' position (from the right). Function
          returns a 'dbeng' code with a dynamically allocated 'fxp' structure
          upon success. The 'fxp' structure must be de-allocated
          by the caller. The subsubfield contents must be a number
          (0-9,-) without any decimal point. */

       struct fxp *result;
       char mname[] = "dbfxp_get_subsubfield", *subsubfield;
       int subsubfield_size, ret;

       logman("%s:enter", mname);
       *r1 = FXP_OT_NULL;

       if (tid <= 0)
          {
          db_io_code_log(mname, "out of range[tid]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (f <= 0)
          {
          db_io_code_log(mname, "out of range[f]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (sf <= 0)
          {
          db_io_code_log(mname, "out of range[sf]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (ssf <= 0)
          {
          db_io_code_log(mname, "out of range[ssf]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (sc < 0)
          {
          db_io_code_log(mname, "out of range[scale]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       /* get the subsubfield size */

       if ((ret = db_get_subsubfield_size(tid, f, sf, ssf, &subsubfield_size)) !=
           DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from db_get_subsubfield", ret);
          return(ret);
          }

       if (subsubfield_size <= 0)
          {
          db_io_code_log(mname, "subsubfield is empty", DBENG_NO_SUCH_SUBSUBFIELD);
          return(DBENG_NO_SUCH_SUBSUBFIELD);
          }

       if ((subsubfield = (char *)malloc(subsubfield_size + 1)) == (char *)NULL)
          {
          dbeng_io_code_log(mname, "alloc fail[subsubfield]", DBENG_MEMORY_FAIL);
          return(DBENG_MEMORY_FAIL);
          }

       /* get the subsubfield contents and validate */

       if ((ret = db_get_subsubfield(tid, f, sf, ssf, subsubfield)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from db_get_subsubfield[subsubfield]", ret);
          free(subsubfield);
          return(ret);
          }

       if (!num(subsubfield))
          {
          db_io_code_log(mname, "non-numeric[subsubfield]", DBENG_INVALID_FUNCTION);
          free(subsubfield);
          return(ret);
          }

       if ((result = fxp_iconv(subsubfield)) == FXP_OT_NULL)
          {
          db_io_code_log(mname, "bad rc from fxp_iconv[subsubfield]",
                         DBENG_INTERNAL_ERROR);
          free(subsubfield);
          return(DBENG_INTERNAL_ERROR);
          }

       /* manually fix-up scale */

       free(subsubfield);
       result->scale = sc;
       *r1 = result;
       db_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }

    int dbfxp_put_subsubfield(int tid, int f, int sf, int ssf, int sc,
                              struct fxp *r1)
    {
       /* Write a fixed-point number to a database subsubfield. The number
          will be written without a decimal point (if any). The
          number will have its scale adjusted (position of the
          decimal point) to 'sc'. The caller must know the number scale.
          A database write will not take place after writing the
          subsubfield contents. The field number, subfield number
          or subsubfield number may be zero to indicate an append
          to the record. Function returns a 'dbeng' code. */

       char mname[] = "dbfxp_put_subsubfield", o1[25], o2[25], ch;
       int ret;

       logman("%s:enter", mname);

       if (tid <= 0)
          {
          db_io_code_log(mname, "out of range[tid]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (f < 0)
          {
          db_io_code_log(mname, "out of range[f]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (sf < 0)
          {
          db_io_code_log(mname, "out of range[sf]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (ssf < 0)
          {
          db_io_code_log(mname, "out of range[ssf]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (r1 == FXP_OT_NULL)
          {
          db_io_code_log(mname, "null[r1]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (!fxp_oconv(r1, sc, o1))
          {
          db_io_code_log(mname, "bad rc from fxp_oconv[r1]",
                         DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       /* copy to final output eliminating decimal point */

       fxp_remove_decimal(o1, o2);

       if ((ret = db_put_subsubfield(tid, f, sf, ssf, o2)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from db_put_subsubfield[o2]", ret);
          return(ret);
          }

       db_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }

/* [<][>][^][v][top][bottom][index][help] */