## root/dbeng/iexlib.c

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

## DEFINITIONS

This source file includes following definitions.

1. iexlib_import
2. iexlib_start
3. iexlib_stop
4. iexlib_active
5. iexlib_dump
6. iexlib_import_do_line
7. iexlib_config_set_sd
8. iexlib_config_set_conv
9. iexlib_config_get_sd
10. iexlib_import_get_ascii_field
11. iexlib_import_match
12. iexlib_import_do_wind_dir
13. iexlib_import_do_time
14. iexlib_import_do_fxp
15. iexlib_import_do_int
16. iexlib_import_do_pint
17. iexlib_import_do_month
18. iexlib_import_conv_wind_dir
19. iexlib_import_conv_time
20. iexlib_import_conv_int
21. iexlib_import_conv_pint
22. iexlib_import_conv_fxp
23. iexlib_import_conv_month
24. iexlib_import_put_fxp
25. iexlib_import_put_data
26. iexlib_import_conv_get_token

    /* iexlib - Import/export library for the 'Bbuuzzb' database and ASCII files.
       Rick Smereka. Copyright (C) 2003-2006.

       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 will import (and eventually export) ascii data into
       a 'bbuuzzb' table. The field ascii data may be fixed or delimited (by
       any single character). The import is template or profile
       based. An import profile record is expected in the 'bbuuzzb' table
       'iex.config'. The field layout for import profile record is as follows:

          field #  description

            1      profile name (any length)
            2      comment
            3      'i' for import, 'x' for export (no export currently)
            4      ascii format, 'f' for fixed or field delimiter otherwise
            5      array of specs, each complete spec is a subfield containing
                   the following subsubfields:
            5,*,1  source field, field number for delimited or 'start,chars'
                   for fixed, note that start byte is zero based
            5,*,2  conversion, one of:
                      'fxp[,n]' - fxp number with 'n' scale (zero if no scale)
                      'time' - convert hh:mm[a|p] to 24hrs. no colon
                      'int[,n]' - integer padded on the left with zeros to 'n' len
                      'pint,n' - integer plus the parameter which is mandatory
                      'winddir' - convert a wind direction alpha (N,NW,S,SSE etc)
                                  to degrees (result is fxp with scale of one)
                      'month' - convert a 3 char alpha month name to an integer
                                (base one) zero padded on the left to two digits
                   a empty value here will denote no conversion
            5,*,3  destination which may be a 'bbuuzzb' field, subfield or
                   or subsubfield in the form 'f[,sf][,ssf]', zero may be
                   used in any part to indicate an append (not recommended)
            6      auto record locate/create switch (see below)
            7      'bbuuzzb' field to match (optional), if present, an
                   attempt will be made to locate an existing matching record
            8      ascii null field signature (optional), if present,
                   these chars will denote an empty input ascii field

       There must be at least six fields present in the iex profile.
       This module may be used in a couple of different ways. To import an
       entire file at once without any special processsing, use 'iexlib_import'.
       You also may import one ascii line at a time with any processing you
       like by first using the function 'iexlib_start' to load the profile
       followed by the function 'iexlib_import_do_line' for each ascii input
       line and 'iexlib_stop' when all lines are completed. The function
       'iexlib_import' is a good example of manually controlling the import.
       The auto record locate/create switch is used in conjunction with
       the match field. If the auto record switch is off, the caller is
       assumed to have already set the 'bbuuzzb' file position and no
       automatic record location or creation will take place. If the
       auto switch is on and there is a match field present, an
       attempt will be made to find the matching 'bbuuzzb' record before
       the import of that ascii line takes place. If the find of the
       'bbuuzzb' record fails, a new output record will be created.
       If the auto switch is on and there is no match field present,
       a new 'bbuuzzb' output record will be created for each ascii
       input line. As a guideline, set the auto switch high when you
       will be using the function 'iexlib_import' (high level) to
       import the entire ascii file at once. Set the auto switch low
       when you will be manually controlling the import. When the
       auto record switch is low, any value in the match field will
       be ignored.

       Original Linux version. Mar/2003, Rick Smereka

       Ported to 32-bit Windows, DOS and QNX. Aug/2003, Rick Smereka

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

       Fixed bug in 'iexlib_import' where 'db_write' was being called
       when the input ASCII line was empty. Jun/2006, Rick Smereka */

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

    /* global data */

    static struct iex_spec *iex_ihead = IEX_OT_NULL; /* config link list head */
    static int iex_is_export;                    /* are we processing an export? */
    static int iex_is_fixed;                     /* is the ASCII format fixed? */
    static char iex_ascii_delim;                 /* ASCII field delimiter */
    static int iex_auto_rec;                     /* auto record locate/create? */
    static int iex_match_field;                  /* dest field number to match */
    static char iex_null_field[10];              /* null ascii field char seq */

    /* private functions */

    static int iexlib_config_set_sd(int, int, int, struct iex_spec *);
    static int iexlib_config_set_conv(int, int, struct iex_spec *);
    static int iexlib_config_get_sd(char *, int *, int *, int *);
    static int iexlib_import_get_ascii_field(char *, char *, struct iex_spec *);
    static int iexlib_import_match(int, char *);
    static int iexlib_import_do_wind_dir(int, char *, struct iex_spec *);
    static int iexlib_import_do_time(int, char *, struct iex_spec *);
    static int iexlib_import_do_fxp(int, char *, struct iex_spec *);
    static int iexlib_import_do_int(int, char *, struct iex_spec *);
    static int iexlib_import_do_pint(int, char *, struct iex_spec *);
    static int iexlib_import_do_month(int, char *, struct iex_spec *);
    static int iexlib_import_conv_wind_dir(char *, struct iex_spec *, char *);
    static int iexlib_import_conv_time(char *, char *);
    static int iexlib_import_conv_fxp(char *, struct iex_spec *, char *);
    static int iexlib_import_conv_int(char *, struct iex_spec *, char *);
    static int iexlib_import_conv_pint(char *, struct iex_spec *, char *);
    static int iexlib_import_conv_month(char *, char *);
    static int iexlib_import_put_fxp(int, struct fxp *, struct iex_spec *);
    static int iexlib_import_put_data(int, char *, struct iex_spec *);
    static int iexlib_import_conv_get_token(char *);

    int iexlib_import(char *profile_name, char *in_file_name,
                      char *out_table_name)
    {
       /* Perform a complete import of the input ascii file into the
          'bbuuzzb' table using the supplied profile. Function returns
          a 'dbeng' code. */

       FILE *in;
       char mname[] = "iexlib_import", *in_line;
       int ret, tid, line_no;

       if (profile_name == (char *)NULL || !strlen(profile_name))
          {
          db_io_code_log(mname, "null or empty[profile_name]",
                         DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (in_file_name == (char *)NULL || !strlen(in_file_name))
          {
          db_io_code_log(mname, "null or empty[in_file_name]",
                         DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (out_table_name == (char *)NULL || !strlen(out_table_name))
          {
          db_io_code_log(mname, "null or empty[out_table_name]",
                         DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if ((ret = iexlib_start(profile_name)) != DBENG_OK)
          {
          db_io_code_log(mname, "error loading profile", ret);
          return(ret);
          }

       if ((in = fopen(in_file_name, "r")) == (FILE *)NULL)
          {
          logman("%s:unable to open %s", mname, in_file_name);
          iexlib_stop();
          return(DBENG_UNABLE_TO_OPEN);
          }

       if ((ret = db_open(out_table_name, &tid)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from db_open[tid]", ret);
          fclose(in);
          iexlib_stop();
          return(ret);
          }

       if ((in_line = (char *)malloc(BUFSIZE)) == (char *)NULL)
          {
          db_io_code_log(mname, "alloc fail[in_line]", DBENG_MEMORY_FAIL);
          fclose(in);
          (void)db_close(tid);
          iexlib_stop();
          return(DBENG_MEMORY_FAIL);
          }

       get_rec(in, in_line);
       line_no = 1;

       if (ferror(in))
          {
          logman("%s:error getting first line of:%s", mname, in_file_name);
          fclose(in);
          (void)db_close(tid);
          free(in_line);
          iexlib_stop();
          return(DBENG_INVALID_FUNCTION);
          }

       while(!feof(in))
          {
          if ((ret = iexlib_import_do_line(tid, in_line)) != DBENG_OK)
             {
             logman("%s:exit[%d]:bad rc from iexlib_import_do_line[%d]",
                           mname, ret, line_no);
             (void)db_close(tid);
             fclose(in);
             free(in_line);
             iexlib_stop();
             return(ret);
             }

          if (strlen(in_line))
             if ((ret = db_write(tid)) != DBENG_OK)
                {
                db_io_code_log(mname, "error writing", ret);
                (void)db_close(tid);
                fclose(in);
                free(in_line);
                iexlib_stop();
                return(ret);
                }

          get_rec(in, in_line);
          line_no++;
          }

       (void)db_close(tid);
       fclose(in);
       free(in_line);
       iexlib_stop();
       return(DBENG_OK);
    }

    int iexlib_start(char *profile_name)
    {
       /* Obtain the iex configuration record from the 'profile_name' and
          load all module globals and the iex spec link list. Function
          returns a 'dbeng' code. */

       struct iex_spec *ot, *rov;
       char mname[] = "iexlib_start", fdat[25];
       int tid, ret, count, i, size;

       if (profile_name == (char *)NULL || !strlen(profile_name))
          {
          db_io_code_log(mname, "null or empty[profile_name]",
                         DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       /* if link list exists, delete it */

       if (iex_ihead != IEX_OT_NULL)
          iexlib_stop();

       /* open the iex config table and find the config record */

       if ((ret = db_open(IEX_CONFIG_TABLE_NAME, &tid)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from db_open[iex.config]", ret);
          return(ret);
          }

       if ((ret = db_find_field(tid, 0, profile_name,
           IEX_CONFIG_FIELD_PROFILE_NAME)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from db_find_field[profile_name]", ret);
          (void)db_close(tid);
          return(ret);
          }

       /* get the number of fields in the config record, must have min */

       if ((ret = db_get_nfields(tid, &count)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from db_get_nfields[profile_name]", ret);
          (void)db_close(tid);
          return(ret);
          }

       if (count < IEX_CONFIG_MIN_ALLOW_FIELDS)
          {
          db_io_code_log(mname, "insufficient number of fields[profile_name]",
                         DBENG_INVALID_FUNCTION);
          (void)db_close(tid);
          return(DBENG_INVALID_FUNCTION);
          }

       /* get and load module globals */
       /* import or export */

       if ((ret = db_get_field(tid, IEX_CONFIG_FIELD_TYPE, fdat)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from db_get_field[profile_name,type]", ret);
          (void)db_close(tid);
          return(ret);
          }

       switch(fdat[0])
          {
          case 'i':
          case 'I':
             iex_is_export = FALSE;
             break;

          case 'x':
          case 'X':
             iex_is_export = TRUE;
             break;

          default:
             db_io_code_log(mname, "unknown iex type", DBENG_INVALID_FUNCTION);
             (void)db_close(tid);
             return(DBENG_INVALID_FUNCTION);
          };

       /* fixed or delimited with delimiter */

       if ((ret = db_get_field(tid, IEX_CONFIG_FIELD_FORMAT, fdat)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from db_get_field[profile_name,format]",
                         ret);
          (void)db_close(tid);
          return(ret);
          }

       if (fdat[0] == 'f' || fdat[0] == 'F')
          {
          iex_is_fixed = TRUE;
          iex_ascii_delim = EOS;
          }
       else
          {
          iex_is_fixed = FALSE;
          iex_ascii_delim = fdat[0];
          }

       /* auto record locate/create */

       if ((ret = db_get_field(tid, IEX_CONFIG_FIELD_AUTO_REC, fdat)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from db_get_field[profile_name,auto_rec]",
                         ret);
          (void)db_close(tid);
          return(ret);
          }

       if (!strlen(fdat))
          {
          db_io_code_log(mname, "empty profile field[auto_rec]",
                         DBENG_INVALID_FUNCTION);
          (void)db_close(tid);
          return(DBENG_INVALID_FUNCTION);
          }

       if (!qatoi(fdat, &iex_auto_rec))
          {
          db_io_code_log(mname, "bad rc[FALSE] from qatoi[auto_rec]",
                         DBENG_INVALID_FUNCTION);
          (void)db_close(tid);
          return(DBENG_INVALID_FUNCTION);
          }

       /* 'bbuuzzb' field number to match */

       if (count >= IEX_CONFIG_FIELD_MATCH)
          {
          if ((ret = db_get_field(tid, IEX_CONFIG_FIELD_MATCH, fdat)) != DBENG_OK)
             {
             db_io_code_log(mname, "bad rc from db_get_field[profile_name,match]",
                            ret);
             (void)db_close(tid);
             return(ret);
             }

          if (strlen(fdat))
             {
             if (!qatoi(fdat, &iex_match_field))
                {
                db_io_code_log(mname, "bad rc[FALSE] from qatoi[match_field]",
                               DBENG_INVALID_FUNCTION);
                (void)db_close(tid);
                return(DBENG_INVALID_FUNCTION);
                }
             }
          else
             iex_match_field = IEXLIB_LL_PARM_NULL;
          }
       else
          iex_match_field = IEXLIB_LL_PARM_NULL;

       /* ascii null field signature */

       if (count > IEX_CONFIG_FIELD_MATCH)
          {
          if ((ret = db_get_field(tid, IEX_CONFIG_FIELD_NULL, fdat)) != DBENG_OK)
             {
             db_io_code_log(mname,
                            "bad rc from db_get_field[profile_name,null_field]",
                            ret);
             (void)db_close(tid);
             return(ret);
             }

          if (strlen(fdat))
             strcpy(iex_null_field, fdat);
          else
             iex_null_field[0] = EOS;
          }
       else
          iex_null_field[0] = EOS;

       /* load iex specs into link list */
       /* get number of specs (subfields) */

       if ((ret = db_get_nsubfields(tid, IEX_CONFIG_FIELD_SPECS, &count)) !=
           DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from db_get_nsubfields[specs]",
                         ret);
          (void)db_close(tid);
          return(ret);
          }

       size = sizeof(struct iex_spec);

       for(i = 1; i <= count; i++)
          {
          /* allocate a new node */

          if ((ot = (struct iex_spec *)malloc(size)) == IEX_OT_NULL)
             {
             db_io_code_log(mname, "alloc fail[ot]", DBENG_MEMORY_FAIL);
             (void)db_close(tid);
             iexlib_stop();
             return(DBENG_MEMORY_FAIL);
             }

          ot->next = IEX_OT_NULL;
          ot->source = ot->source_add1 = ot->source_add2 = ot->conversion =
                       ot->conversion_parm = ot->dest = ot->dest_add1 =
                       ot->dest_add2 = IEXLIB_LL_PARM_NULL;

          /* load the source field of this spec */

          if ((ret = iexlib_config_set_sd(1, tid, i, ot)) != DBENG_OK)
             {
             db_io_code_log(mname, "bad rc from iexlib_conifg_set_sd[source]", ret);
             (void)db_close(tid);
             free(ot);
             iexlib_stop();
             return(ret);
             }

          /* load the conversion spec */

          if ((ret = iexlib_config_set_conv(tid, i, ot)) != DBENG_OK)
             {
             db_io_code_log(mname, "bad rc from iexlib_config_set_conv", ret);
             (void)db_close(tid);
             free(ot);
             iexlib_stop();
             return(ret);
             }

          /* load the dest field */

          if ((ret = iexlib_config_set_sd(0, tid, i, ot)) != DBENG_OK)
             {
             db_io_code_log(mname, "bad rc from iexlib_conifg_set_sd[dest]", ret);
             (void)db_close(tid);
             free(ot);
             iexlib_stop();
             return(ret);
             }

          /* set head of list if this is the first entry */

          if (iex_ihead == IEX_OT_NULL)
             iex_ihead = ot;
          else
             {
             /* find last entry and hook into it */

             rov = iex_ihead;

             while(rov->next != IEX_OT_NULL)
                rov = rov->next;

             rov->next = ot;
             }
          }

       (void)db_close(tid);

    #ifdef DEBUG
       iexlib_dump();
    #endif

       return(DBENG_OK);
    }

    void iexlib_stop(void)
    {
       /* Delete the iex spec link list and set module globals to zero/null. */

       struct iex_spec *tmp, *rov = iex_ihead;

       iex_is_export = iex_is_fixed = iex_auto_rec = FALSE;
       iex_match_field = IEXLIB_LL_PARM_NULL;
       iex_ascii_delim = iex_null_field[0] = EOS;

       while(rov != IEX_OT_NULL)
          {
          tmp = rov->next;
          free(rov);
          rov = tmp;
          }

       iex_ihead = IEX_OT_NULL;
    }

    int iexlib_active(void)
    {
       /* Determine whether there is a current iex profile loaded into
          the link list. Function returns 'TRUE' if there is a profile
          loaded, 'FALSE' otherwise. */

       if (iex_ihead != IEX_OT_NULL)
          return(TRUE);

       return(FALSE);
    }

    void iexlib_dump(void)
    {
       /* Output the contents of the global data and the iex link list to the
          log manager. Note that logging must already be turned on. */

       struct iex_spec *rov = iex_ihead;
       char mname[] = "iexlib_dump";
       int i = 1;

       if (iex_is_fixed)
          logman("%s:is_export=%d,is_fixed=%d,auto_rec=%d,match_field=%d"
                        ",null_field=%s", mname, iex_is_export, iex_is_fixed,
                        iex_auto_rec, iex_match_field, iex_null_field);
       else
          logman("%s:is_export=%d,is_fixed=%d,ascii_delim=%c,%d,auto_rec=%d"
                        ",match_field=%d,null_field=%s", mname, iex_is_export,
                        iex_is_fixed, iex_ascii_delim, iex_ascii_delim,
                        iex_auto_rec, iex_match_field, iex_null_field);

       if (rov == IEX_OT_NULL)
          {
          logman("%s:iex link list empty", mname);
          return;
          }

       while(rov != IEX_OT_NULL)
          {
          logman("%s:spec[%d]:source=%d,source_add1=%d,source_add2=%d,"
                        "conv=%d,conv_parm=%d,dest=%d,dest_add1=%d,dest_add2=%d",
                        mname, i++, rov->source, rov->source_add1, rov->source_add2,
                        rov->conversion, rov->conversion_parm, rov->dest,
                        rov->dest_add1, rov->dest_add2);
          rov = rov->next;
          }
    }

    int iexlib_import_do_line(int out_tid, char *line)
    {
       /* Import an entire line from the input ascii file into the
          'bbuuzzb' table. Function returns a 'dbeng' code. */

       struct iex_spec *rov = iex_ihead;
       char mname[] = "iexlib_import_do_line", *ascii_field;
       int ret;

       if (line == (char *)NULL || !strlen(line))
          {
          /* null or empty line is not fatal */

          db_io_code_log(mname, "null or empty[line]", DBENG_OK);
          return(DBENG_OK);
          }

       if (rov == IEX_OT_NULL)
          {
          db_io_code_log(mname, "no spec link list", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       /* if the auto record locate/create switch is on, attempt to locate
          an existing bbuuzzb record if there is a match field, if the locate
          fails, create a new output record, if the auto switch is on and there
          is no match field, create a new output record, if the auto switch
          is off, assume the caller has already set the bbuuzzb file position
          and do nothing */

       if (iex_auto_rec)
          if (iex_match_field != IEXLIB_LL_PARM_NULL)
             {
             if ((ret = iexlib_import_match(out_tid, line)) != DBENG_OK)
                {
                /* if match fails, create a new 'bbuuzzb' record */

                logman("%s:no match,creating new record", mname);
                (void)db_new(out_tid);
                }
             else
                logman("%s:found matching bbuuzzb record", mname);
             }
          else
             (void)db_new(out_tid);

       if ((ascii_field = initstring(line)) == (char *)NULL)
          {
          db_io_code_log(mname, "alloc fail[ascii_field]", DBENG_MEMORY_FAIL);
          return(DBENG_MEMORY_FAIL);
          }

       ascii_field[0] = EOS;

       /* loop through all the specs, for each spec, get the ascii
          field, perform the conversion and put to the bbuuzzb record */

       while(rov != IEX_OT_NULL)
          {
          if ((ret = iexlib_import_get_ascii_field(line, ascii_field, rov)) !=
              DBENG_OK)
             {
             // if the ascii field cannot be obtained, skip the spec

             logman("%s:cannot get ascii field data[f=%s,dest=%d]",
                           mname, ascii_field, rov->dest);
             rov = rov->next;
             continue;
             }

          /* if the field is empty, skip */

          if (!strlen(ascii_field))
             {
             logman("%s:empty field[dest=%d]", mname, rov->dest);
             rov = rov->next;
             continue;
             }

          /* if there is a null signature present and it matches, skip */

          if (strlen(iex_null_field))
             // compare only to length of null signature

             if (!strncmp(ascii_field, iex_null_field, strlen(iex_null_field)))
                {
                logman("%s:null field[dest=%d]", mname, rov->dest);
                rov = rov->next;
                continue;
                }

          /* logman("%s:ascii field[%d,%d]=%s,%d", mname, rov->source,
                        rov->source_add1, ascii_field, strlen(ascii_field)); */

          switch(rov->conversion)
             {
             case IEX_CONV_TYPE_IFXP:
                ret = iexlib_import_do_fxp(out_tid, ascii_field, rov);
                break;

             case IEX_CONV_TYPE_ITIME:
                ret = iexlib_import_do_time(out_tid, ascii_field, rov);
                break;

             case IEX_CONV_TYPE_IINT:
                ret = iexlib_import_do_int(out_tid, ascii_field, rov);
                break;

             case IEX_CONV_TYPE_IPINT:
                ret = iexlib_import_do_pint(out_tid, ascii_field, rov);
                break;

             case IEX_CONV_TYPE_IWINDDIR:
                ret = iexlib_import_do_wind_dir(out_tid, ascii_field, rov);
                break;

             case IEX_CONV_TYPE_IMONTH:
                ret = iexlib_import_do_month(out_tid, ascii_field, rov);
                break;

             default:
                // no conversion

                ret = iexlib_import_put_data(out_tid, ascii_field, rov);
             };

          if (ret != DBENG_OK)
             logman("%s:bad rc from do[conv=%d,dest=%d]", mname,
                           rov->conversion, rov->dest);

          rov = rov->next;
          }

       return(DBENG_OK);
    }

    // private functions

    static int iexlib_config_set_sd(int is_source, int tid, int rsf,
                                    struct iex_spec *ot)
    {
       /* Load the source or destination field specification into the
          link list node. Function returns a 'dbeng' code. */

       char mname[] = "iexlib_config_set_sd", fdat[25];
       int ret, f, sf, ssf;

       ssf = (is_source) ? IEX_CONFIG_SUBSUBFIELD_SOURCE :
             IEX_CONFIG_SUBSUBFIELD_DEST;

       if ((ret = db_get_subsubfield(tid, IEX_CONFIG_FIELD_SPECS, rsf, ssf, fdat))
           != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from db_get_subsubfield", ret);
          return(ret);
          }

       if ((ret = iexlib_config_get_sd(fdat, &f, &sf, &ssf)) !=
           DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from iexlib_config_get_sd", ret);
          return(ret);
          }

       if (is_source)
          {
          ot->source = f;
          ot->source_add1 = sf;
          ot->source_add2 = ssf;
          }
       else
          {
          ot->dest = f;
          ot->dest_add1 = sf;
          ot->dest_add2 = ssf;
          }

       return(DBENG_OK);
    }

    static int iexlib_config_set_conv(int tid, int rsf, struct iex_spec *ot)
    {
       /* Load the conversion spec into the link list node. Function
          returns a 'dbeng' code. */

       char mname[] = "iexlib_config_set_conv", fdat[25], parm[25];
       int ret, nwords;

       if ((ret = db_get_subsubfield(tid, IEX_CONFIG_FIELD_SPECS, rsf,
                                     IEX_CONFIG_SUBSUBFIELD_CONV, fdat))
           != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from db_get_subsubfield", ret);
          return(ret);
          }

       /* separate out keyword and any additional parameter */

       nwords = ll_words(fdat, IEXLIB_CONFIG_SPEC_SEP);

       /* if the conversion subsubfield is empty, assume no conversion */

       if (!nwords)
          {
          db_io_code_log(mname, "exit:no conv spec,assuming no conv", DBENG_OK);
          ot->conversion = ot->conversion_parm = IEX_CONV_TYPE_UNKNOWN;
          return(DBENG_OK);
          }

       if (nwords > 2)
          {
          db_io_code_log(mname, "improper number of conversion parms",
                         DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (nwords > 1)
          {
          if (!ll_word(fdat, parm, 1, IEXLIB_CONFIG_SPEC_SEP))
             {
             db_io_code_log(mname, "bad rc from ll_word[1]", DBENG_INTERNAL_ERROR);
             return(DBENG_INTERNAL_ERROR);
             }
          }
       else
          {
          strcpy(parm, fdat);
          ot->conversion_parm = IEXLIB_LL_PARM_NULL;
          }

       if ((ret = iexlib_import_conv_get_token(parm)) == IEX_CONV_TYPE_UNKNOWN)
          {
          logman("%s:exit:unknown conv type[%s]", mname, parm);
          return(DBENG_INVALID_FUNCTION);
          }

       ot->conversion = ret;

       if (nwords > 1)
          {
          if (!ll_word(fdat, parm, 2, IEXLIB_CONFIG_SPEC_SEP))
             {
             db_io_code_log(mname, "bad rc from ll_word[2]", DBENG_INTERNAL_ERROR);
             return(DBENG_INTERNAL_ERROR);
             }

          if (!qatoi(parm, &ret))
             {
             db_io_code_log(mname, "non-numeric[conv parm]",
                            DBENG_INVALID_FUNCTION);
             return(DBENG_INVALID_FUNCTION);
             }

          ot->conversion_parm = ret;
          }

       return(DBENG_OK);
    }

    static int iexlib_config_get_sd(char *fdat, int *f, int *sf, int *ssf)
    {
       /* Parse a source or destination field spec into its
          component parts. Function returns a 'dbeng' code. */

       char mname[] = "iexlib_config_get_sd", wrd[25];
       int nelements, i, num_wrd;

       nelements = ll_words(fdat, IEXLIB_CONFIG_SPEC_SEP);
       *f = *sf = *ssf = IEXLIB_LL_PARM_NULL;

       if (!nelements)
          {
          db_io_code_log(mname, "empty[fdat]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (nelements == 1)
          {
          if (!qatoi(fdat, f))
             {
             db_io_code_log(mname, "non-numeric[fdat]", DBENG_INVALID_FUNCTION);
             return(DBENG_INVALID_FUNCTION);
             }

          return(DBENG_OK);
          }

       for(i = 1; i <= nelements; i++)
          {
          if (!ll_word(fdat, wrd, i, IEXLIB_CONFIG_SPEC_SEP))
             {
             logman("%s:exit:bad rc from ll_word[fdat=%s,wrd=%s,i=%d]",
                           mname, fdat, wrd, i);
             return(DBENG_INTERNAL_ERROR);
             }

          if (!qatoi(wrd, &num_wrd))
             {
             logman("%s:exit:non-numeric[fdat=%s,wrd=%s,i=%d]",
                           mname, fdat, wrd, i);
             return(DBENG_INVALID_FUNCTION);
             }

          switch(i)
             {
             case 1:
                *f = num_wrd;
                break;

             case 2:
                *sf = num_wrd;
                break;

             case 3:
                *ssf = num_wrd;
                break;

             default:
                logman("%s:exit:unknown parameter[fdat=%s,wrd=%s,i=%d]",
                              mname, fdat, wrd, i);
                return(DBENG_INVALID_FUNCTION);
             };
          }

       return(DBENG_OK);
    }

    static int iexlib_import_get_ascii_field(char *line, char *outfield,
                                             struct iex_spec *ot)
    {
       /* Obtain a field within the ascii import line. The field data
          is retrieved based on whether the input format
          is fixed or delimited (contained in the globals). The pointer
          'ot' must point to a valid iex specification and the field
          will be obtained from this spec and placed into 'outfield'
          upon success. Function returns a 'dbeng' code. */

       char mname[] = "iexlib_import_get_ascii_field", *tfield;
       int nwords, len, ret;

       if (line == (char *)NULL || !strlen(line))
          {
          db_io_code_log(mname, "null or empty[line]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (outfield == (char *)NULL)
          {
          db_io_code_log(mname, "null[outfield]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       outfield[0] = EOS;

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

       /* validate source field spec */

       if (ot->source == IEXLIB_LL_PARM_NULL)
          {
          db_io_code_log(mname, "ot->source[null]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (iex_is_fixed)
          {
          len = strlen(line);

          if (ot->source_add1 == IEXLIB_LL_PARM_NULL)
             {
             db_io_code_log(mname, "ot->source_add1[null]", DBENG_INVALID_FUNCTION);
             return(DBENG_INVALID_FUNCTION);
             }

          if (ot->source_add1 < 1)
             {
             db_io_code_log(mname, "ot->source_add1[out of range]",
                            DBENG_INVALID_FUNCTION);
             return(DBENG_INVALID_FUNCTION);
             }

          if (ot->source > len || (ot->source + ot->source_add1) > len)
             {
             db_io_code_log(mname, "out of range source", DBENG_INVALID_FUNCTION);
             return(DBENG_INVALID_FUNCTION);
             }
          }
       else
          {
          nwords = ll_words(line, iex_ascii_delim);

          if (ot->source > nwords)
             {
             db_io_code_log(mname, "out of range source", DBENG_INVALID_FUNCTION);
             return(DBENG_INVALID_FUNCTION);
             }
          }

       if ((tfield = initstring(line)) == (char *)NULL)
          {
          db_io_code_log(mname, "alloc fail[tfield]", DBENG_MEMORY_FAIL);
          return(DBENG_MEMORY_FAIL);
          }

       /* obtain the field data */

       if (iex_is_fixed)
          {
          strncpy(tfield, &line[ot->source], ot->source_add1);
          tfield[ot->source_add1] = EOS;
          }
       else
          {
          if (!ll_word(line, tfield, ot->source, iex_ascii_delim))
             {
             db_io_code_log(mname, "bad rc from ll_word", DBENG_INTERNAL_ERROR);
             free(tfield);
             return(DBENG_INTERNAL_ERROR);
             }
          }

       trim(tfield, outfield);
       free(tfield);
       return(DBENG_OK);
    }

    static int iexlib_import_match(int tid, char *line)
    {
       /* Attempt to match the input ascii field with 'bbuuzzb' data
          by applying the specified conversion to the input ascii field
          and attempting to locate a 'bbuuzzb' record with the matching
          data. Function returns a 'dbeng' code. */

       static struct iex_spec *iex_import_match = IEX_OT_NULL;
       struct iex_spec *rov = iex_ihead;
       char mname[] = "iexlib_import_match", *in_field, *out_field;
       int ret;

       if (rov == IEX_OT_NULL)
          {
          db_io_code_log(mname, "no spec link list", DBENG_INTERNAL_ERROR);
          return(DBENG_INTERNAL_ERROR);
          }

       /* locate matching spec struct in the link list only if this
          pointer is NULL */

       if (iex_import_match == IEX_OT_NULL)
          {
          while(rov != IEX_OT_NULL)
             {
             if (rov->dest == iex_match_field)
                {
                iex_import_match = rov;
                break;
                }

             rov = rov->next;
             }

          if (iex_import_match == IEX_OT_NULL)
             {
             db_io_code_log(mname, "not found[match_field]", DBENG_NO_SUCH_FIELD);
             return(DBENG_NO_SUCH_FIELD);
             }
          }

       if ((in_field = initstring(line)) == (char *)NULL)
          {
          db_io_code_log(mname,"alloc fail[in_field]", DBENG_MEMORY_FAIL);
          return(DBENG_MEMORY_FAIL);
          }

       if ((out_field = initstring(line)) == (char *)NULL)
          {
          db_io_code_log(mname,"alloc fail[out_field]", DBENG_MEMORY_FAIL);
          return(DBENG_MEMORY_FAIL);
          }

       in_field[0] = out_field[0] = EOS;

       /* get the raw ascii input field */

       if ((ret = iexlib_import_get_ascii_field(line, in_field, iex_import_match))
           != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from iexlib_import_get_ascii_field", ret);
          free(in_field);
          free(out_field);
          return(ret);
          }

       /* unknown conversion is a signal to not apply any conversion */

       if (iex_import_match->conversion == IEX_CONV_TYPE_UNKNOWN)
          {
          logman("%s:conv[unknown]:no conv applied", mname);
          strcpy(out_field, in_field);
          }
       else
          {
          /* apply conversion */

          switch(iex_import_match->conversion)
             {
             case IEX_CONV_TYPE_IFXP:
                ret = iexlib_import_conv_fxp(in_field, iex_import_match, out_field);
                break;

             case IEX_CONV_TYPE_ITIME:
                ret = iexlib_import_conv_time(in_field, out_field);
                break;

             case IEX_CONV_TYPE_IINT:
                ret = iexlib_import_conv_int(in_field, iex_import_match,
                                             out_field);
                break;

             case IEX_CONV_TYPE_IPINT:
                ret = iexlib_import_conv_pint(in_field, iex_import_match,
                                             out_field);
                break;

             case IEX_CONV_TYPE_IWINDDIR:
                ret = iexlib_import_conv_wind_dir(in_field, iex_import_match,
                                                  out_field);
                break;

             case IEX_CONV_TYPE_IMONTH:
                ret = iexlib_import_conv_month(in_field, out_field);
                break;

             default:
                db_io_code_log(mname, "unknown conv", DBENG_INVALID_FUNCTION);
                return(DBENG_INVALID_FUNCTION);
             };
          }

       if (!ret)
          {
          db_io_code_log(mname, "conv failed", DBENG_INVALID_FUNCTION);
          free(in_field);
          free(out_field);
          return(DBENG_INVALID_FUNCTION);
          }

       /* attempt to locate the 'bbuuzzb' record with the matching data */

       (void)db_top(tid);
       ret = db_find_field(tid, 0, out_field, iex_import_match->dest);
       free(in_field);
       free(out_field);
       return(ret);
    }

    static int iexlib_import_do_wind_dir(int out_tid, char *in_field,
                                         struct iex_spec *ot)
    {
       /* Convert the wind direction from alpha to degrees and place into
          the 'bbuuzzb' record. Function returns a 'dbeng' code. */

       struct fxp *result;
       char mname[] = "iexlib_import_do_wind_dir";
       int ret;

       if (in_field == (char *)NULL || !strlen(in_field))
          {
          db_io_code_log(mname, "null or empty[in_field]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

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

       /* convert the field to wind direction in degrees */

       if (!wlib_wdir_desc_2_deg(in_field, &result))
          {
          logman("%s:bad rc[FALSE] from wlib_wdir_desc_2_deg[%s]",
                        mname, in_field);
          return(DBENG_INVALID_FUNCTION);
          }

       /* place the 'fxp' data into the 'bbuuzzb' record */

       if ((ret = iexlib_import_put_fxp(out_tid, result, ot)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from iexlib_import_put_fxp", ret);
          fxp_free(result);
          return(ret);
          }

       fxp_free(result);
       return(DBENG_OK);
    }

    static int iexlib_import_do_time(int out_tid, char *in_field,
                                     struct iex_spec *ot)
    {
       /* Convert a time field (in the form hh:mm[a|p]) to 24 hour
          and place into a 'bbuuzzb' record. Function returns a
          'dbeng' code. */

       char mname[] = "iexlib_import_do_time", out_field[100];
       int ret;

       if (in_field == (char *)NULL || !strlen(in_field))
          {
          db_io_code_log(mname, "null or empty[in_field]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

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

       /* convert the time field to 24hr clock */

       if (!iexlib_import_conv_time(in_field, out_field))
          {
          logman("%s:bad rc[FALSE] from iexlib_import_conv_time[%s]", mname,
                        in_field);
          return(DBENG_INVALID_FUNCTION);
          }

       if ((ret = iexlib_import_put_data(out_tid, out_field, ot)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from iexlib_import_put_data", ret);
          return(ret);
          }

       return(DBENG_OK);
    }

    static int iexlib_import_do_fxp(int out_tid, char *in_field,
                                     struct iex_spec *ot)
    {
       /* Convert an 'fxp' field and place it into the 'bbuuzzb' record.
          Function returns a 'dbeng' code. */

       struct fxp *result;
       char mname[] = "iexlib_import_do_fxp";
       int ret;

       if (in_field == (char *)NULL || !strlen(in_field))
          {
          db_io_code_log(mname, "null or empty[in_field]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

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

       if ((result = fxp_iconv(in_field)) == FXP_OT_NULL)
          {
          logman("%s:bad rc[NULL] from fxp_iconv[%s]", mname, in_field);
          return(DBENG_INVALID_FUNCTION);
          }

       /* place the 'fxp' data into the 'bbuuzzb' record */

       if ((ret = iexlib_import_put_fxp(out_tid, result, ot)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from iexlib_import_put_fxp", ret);
          fxp_free(result);
          return(ret);
          }

       fxp_free(result);
       return(DBENG_OK);
    }

    static int iexlib_import_do_int(int out_tid, char *in_field,
                                    struct iex_spec *ot)
    {
       /* Convert an integer and place into the 'bbuuzzb' record.
          Function returns a 'dbeng' code. */

       char mname[] = "iexlib_import_do_int", out_field[100];
       int ret;

       if (in_field == (char *)NULL || !strlen(in_field))
          {
          db_io_code_log(mname, "null or empty[in_field]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

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

       if (!iexlib_import_conv_int(in_field, ot, out_field))
          {
          db_io_code_log(mname, "bad rc[FALSE] from iexlib_import_conv_int",
                         DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if ((ret = iexlib_import_put_data(out_tid, out_field, ot)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from iexlib_import_put_data", ret);
          return(ret);
          }

       return(DBENG_OK);
    }

    static int iexlib_import_do_pint(int out_tid, char *in_field,
                                     struct iex_spec *ot)
    {
       /* Convert an integer plus a constant and place into the 'bbuuzzb' record.
          Function returns a 'dbeng' code. */

       char mname[] = "iexlib_import_do_pint", out_field[100];
       int ret;

       if (in_field == (char *)NULL || !strlen(in_field))
          {
          db_io_code_log(mname, "null or empty[in_field]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

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

       if (!iexlib_import_conv_pint(in_field, ot, out_field))
          {
          db_io_code_log(mname, "bad rc[FALSE] from iexlib_import_conv_pint",
                         DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if ((ret = iexlib_import_put_data(out_tid, out_field, ot)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from iexlib_import_put_data", ret);
          return(ret);
          }

       return(DBENG_OK);
    }

    static int iexlib_import_do_month(int out_tid, char *in_field,
                                      struct iex_spec *ot)
    {
       /* Convert a month name (3 chars) to a month number (base 1)
          and place into a 'bbuuzzb' record. Function returns a
          'dbeng' code. */

       char mname[] = "iexlib_import_do_month", out_field[3];
       int ret;

       if (in_field == (char *)NULL || !strlen(in_field))
          {
          db_io_code_log(mname, "null or empty[in_field]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

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

       /* convert the month to a number */

       if (!iexlib_import_conv_month(in_field, out_field))
          {
          logman("%s:bad rc[FALSE] from iexlib_import_conv_month[%s]", mname,
                        in_field);
          return(DBENG_INVALID_FUNCTION);
          }

       if ((ret = iexlib_import_put_data(out_tid, out_field, ot)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from iexlib_import_put_data", ret);
          return(ret);
          }

       return(DBENG_OK);
    }

    static int iexlib_import_conv_wind_dir(char *in_field, struct iex_spec *ot,
                                           char *out_field)
    {
       /* Convert the wind direction from alpha to degrees. Function
          returns 'TRUE' upon success with the result loaded into
          'out_field', 'FALSE' otherwise. Note that the result is
          in 'bbuuzzb' 'fxp' format (no decimal and padded on the
          right with zeros to the desired precision or scale). This
          function is used only to match records ('iexlib_import_match'). */

       struct fxp *result;
       char mname[] = "iexlib_import_conv_wind_dir";
       int ret;

       if (in_field == (char *)NULL || !strlen(in_field))
          {
          logman("%s:exit[FALSE]:null or empty[in_field]", mname);
          return(FALSE);
          }

       if (ot == IEX_OT_NULL)
          {
          logman("%s:null[ot]", mname);
          return(FALSE);
          }

       if (out_field == (char *)NULL)
          {
          logman("%s:null[out_field]", mname);
          return(FALSE);
          }

       out_field[0] = EOS;

       /* convert the field to wind direction in degrees */

       if (!wlib_wdir_desc_2_deg(in_field, &result))
          {
          logman("%s:bad rc[FALSE] from wlib_wdir_desc_2_deg[%s]",
                        mname, in_field);
          return(FALSE);
          }

       /* use the raw fxp number string */

       strcpy(out_field, result->charval);
       fxp_free(result);
       return(TRUE);
    }

    static int iexlib_import_conv_time(char *in_field, char *out_field)
    {
       /* Convert a time field (in the form hh:mm[a|p]) to 24 hour.
          Function returns 'TRUE' upon success, 'FALSE' otherwise. */

       char mname[] = "iexlib_import_conv_time";
       int ret;

       if (in_field == (char *)NULL || !strlen(in_field))
          {
          logman("%s:null or empty[in_field]", mname);
          return(FALSE);
          }

       if (out_field == (char *)NULL)
          {
          logman("%s:null[out_field]", mname);
          return(FALSE);
          }

       out_field[0] = EOS;

       /* convert the time field to 24hr clock */

       if (!datime_hour12_2_hour24(in_field, out_field, FALSE))
          {
          logman("%s:bad rc[FALSE] from datime_hour12_2_hour24[%s]", mname,
                        in_field);
          return(FALSE);
          }

       return(TRUE);
    }

    static int iexlib_import_conv_int(char *in_field, struct iex_spec *ot,
                                      char *out_field)
    {
       /* Convert an integer. Function returns 'TRUE' upon success with
          the result loaded into 'out_field'. Function returns 'FALSE'
          otherwise. */

       char mname[] = "iexlib_import_conv_int";
       int ret;

       if (in_field == (char *)NULL || !strlen(in_field))
          {
          logman("%s:null or empty[in_field]", mname);
          return(FALSE);
          }

       if (out_field == (char *)NULL)
          {
          logman("%s:null[out_field]", mname);
          return(FALSE);
          }

       out_field[0] = EOS;

       /* make sure data is numeric */

       if (!qatoi(in_field, &ret))
          {
          logman("%s:bad rc[FALSE] from qatoi[%s]", mname, in_field);
          return(FALSE);
          }

       /* pad on left with zeros if requested */

       if (ot->conversion_parm != IEXLIB_LL_PARM_NULL)
          lpad(in_field, out_field, ot->conversion_parm, '0');
       else
          strcpy(out_field, in_field);

       return(TRUE);
    }

    static int iexlib_import_conv_pint(char *in_field, struct iex_spec *ot,
                                       char *out_field)
    {
       /* Convert a plus integer, which is an integer plus a constant.
          Function returns 'TRUE' upon success with the result loaded
          into 'out_field'. Function returns 'FALSE' otherwise. */

       char mname[] = "iexlib_import_conv_pint";
       int ret;

       if (in_field == (char *)NULL || !strlen(in_field))
          {
          logman("%s:null or empty[in_field]", mname);
          return(FALSE);
          }

       if (out_field == (char *)NULL)
          {
          logman("%s:null[out_field]", mname);
          return(FALSE);
          }

       out_field[0] = EOS;

       if (ot == IEX_OT_NULL)
          {
          logman("%s:null[ot]", mname);
          return(FALSE);
          }

       /* make sure data is numeric */

       if (!qatoi(in_field, &ret))
          {
          logman("%s:bad rc[FALSE] from qatoi[%s]", mname, in_field);
          return(FALSE);
          }

       /* make sure a parm (the constant) was supplied */

       if (ot->conversion_parm == IEXLIB_LL_PARM_NULL)
          {
          logman("%s:no constant supplied", mname);
          return(FALSE);
          }

       ret += ot->conversion_parm;
       sprintf(out_field, "%d", ret);
       return(TRUE);
    }

    static int iexlib_import_conv_fxp(char *in_field, struct iex_spec *ot,
                                      char *out_field)
    {
       /* Convert an fxp number. Function returns 'TRUE' upon success with
          the result loaded into 'out_field', 'FALSE' otherwise. Note that
          the result is in 'bbuuzzb' 'fxp' format (no decimal and padded on the
          right with zeros to the desired precision or scale). This
          function is used only to match records ('iexlib_import_match'). */

       struct fxp *result;
       char mname[] = "iexlib_import_conv_fxp";
       int ret, scale;

       if (in_field == (char *)NULL || !strlen(in_field))
          {
          logman("%s:exit[FALSE]:null or empty[in_field]", mname);
          return(FALSE);
          }

       if (ot == IEX_OT_NULL)
          {
          logman("%s:null[ot]", mname);
          return(FALSE);
          }

       if (out_field == (char *)NULL)
          {
          logman("%s:null[out_field]", mname);
          return(FALSE);
          }

       out_field[0] = EOS;

       /* convert the number from a string to fxp */

       if ((result = fxp_iconv(in_field)) == FXP_OT_NULL)
          {
          logman("%s:bad rc[NULL] from fxp_iconv[%s]",
                        mname, in_field);
          return(FALSE);
          }

       scale = (ot->conversion_parm == IEXLIB_LL_PARM_NULL) ? 0 :
               ot->conversion_parm;

       /* force the 'fxp' number to the specified scale */

       if (!fxp_scale(result, scale))
          {
          fxp_free(result);
          logman("%s:bad rc[FALSE] from fxp_scale", mname);
          return(FALSE);
          }

       /* use the raw fxp number string */

       strcpy(out_field, result->charval);
       fxp_free(result);
       return(TRUE);
    }

    static int iexlib_import_conv_month(char *in_field, char *out_field)
    {
       /* Convert a month name (3 chars) to a month number zero padded
          to two digits. Function returns 'TRUE' with the month number
          loaded into 'out_field' upon success. Function returns 'FALSE'
          otherwise. */

       char mname[] = "iexlib_import_conv_month", tmp[3];
       int ret;

       if (in_field == (char *)NULL || !strlen(in_field))
          {
          logman("%s:null or empty[in_field]", mname);
          return(FALSE);
          }

       if (out_field == (char *)NULL)
          {
          logman("%s:null[out_field]", mname);
          return(FALSE);
          }

       out_field[0] = EOS;

       if ((ret = datime_month_name_2_num(in_field)) == 0)
          {
          logman("%s:bad rc[FALSE] from datime_month_name_2_num[%s]",
                        mname, in_field);
          return(FALSE);
          }

       sprintf(tmp, "%d", ret);
       lpad(tmp, out_field, 2, '0');
       return(TRUE);
    }

    static int iexlib_import_put_fxp(int out_tid, struct fxp *dat,
                                     struct iex_spec *ot)
    {
       /* Place 'fxp' data into a 'bbuuzzb' record. Function returns a
          'dbeng' code. */

       char mname[] = "iexlib_import_put_fxp";
       int ret, scale;

       if (ot->dest == IEXLIB_LL_PARM_NULL)
          {
          db_io_code_log(mname, "out of range[ot->dest]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       /* if no scale was supplied, assume zero (int) unless we are
          processing a windir direction in which case we use a
          pre-defined scale */

       if (ot->conversion == IEX_CONV_TYPE_IWINDDIR)
          scale = IEXLIB_SCALE_WIND_DIR;
       else
          scale = (ot->conversion_parm == IEXLIB_LL_PARM_NULL) ? 0 :
                  ot->conversion_parm;

       if (ot->dest_add1 != IEXLIB_LL_PARM_NULL && ot->dest_add2 !=
           IEXLIB_LL_PARM_NULL)
          {
          if ((ret = dbfxp_put_subsubfield(out_tid, ot->dest, ot->dest_add1,
                                           ot->dest_add2, scale, dat)) !=
              DBENG_OK)
             {
             db_io_code_log(mname, "bad rc from dbfxp_put_subsubfield", ret);
             return(ret);
             }

          return(DBENG_OK);
          }

       if (ot->dest_add1 != IEXLIB_LL_PARM_NULL)
          {
          if ((ret = dbfxp_put_subfield(out_tid, ot->dest, ot->dest_add1,
                                        scale, dat)) != DBENG_OK)
             {
             db_io_code_log(mname, "bad rc from dbfxp_put_subfield", ret);
             return(ret);
             }

          return(DBENG_OK);
          }

       if ((ret = dbfxp_put(out_tid, ot->dest, scale, dat)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from dbfxp_put", ret);
          return(ret);
          }

       return(DBENG_OK);
    }

    static int iexlib_import_put_data(int out_tid, char *dat, struct iex_spec *ot)
    {
       /* Place data into a 'bbuuzzb' record. Function returns a
          'dbeng' code. */

       char mname[] = "iexlib_import_put_data";
       int ret;

       if (ot->dest == IEXLIB_LL_PARM_NULL)
          {
          db_io_code_log(mname, "out of range[ot->dest]", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (ot->dest_add1 != IEXLIB_LL_PARM_NULL && ot->dest_add2 !=
           IEXLIB_LL_PARM_NULL)
          {
          if ((ret = db_put_subsubfield(out_tid, ot->dest, ot->dest_add1,
                                        ot->dest_add2, dat)) != DBENG_OK)
             {
             db_io_code_log(mname, "bad rc from db_put_subsubfield", ret);
             return(ret);
             }

          return(DBENG_OK);
          }

       if (ot->dest_add1 != IEXLIB_LL_PARM_NULL)
          {
          if ((ret = db_put_subfield(out_tid, ot->dest, ot->dest_add1,
                                     dat)) != DBENG_OK)
             {
             db_io_code_log(mname, "bad rc from db_put_subfield", ret);
             return(ret);
             }

          return(DBENG_OK);
          }

       if ((ret = db_put_field(out_tid, ot->dest, dat)) != DBENG_OK)
          {
          db_io_code_log(mname, "bad rc from db_put_field", ret);
          return(ret);
          }

       return(DBENG_OK);
    }

    static int iexlib_import_conv_get_token(char *keywrd)
    {
       /* Get conversion keyword token. Function returns a numeric
          representation of the token. */

       int i;
       int token = IEX_CONV_TYPE_UNKNOWN;

       /* static array of conversion words */

       static char *convs[] = { "FXP", "TIME", "INT", "WINDDIR", "MONTH",
                                "PINT" };

       for(i = 0; i < IEX_CONV_IMAXTYPE; i++)
          if (!stricmp(keywrd, convs[i]))
             {
             token = i;
             break;
             }

       return(token);
    }

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