/* dbsrv - A database server based on the 'DBENG' (Bbuuzzb) engine.
   This program will take messages sent to it and process table/record
   data. Rick Smereka, Copyright (C) 1997-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

   Original QNX version. Feb/97, Rick Smereka

   Complete re-write for the new DBENG API. Dec/97,
   Rick Smereka

   Add management of the table 'is_table_locked' flag.
   Jan/98, Rick Smereka

   Re-compiled for new version of pack using 'qrename'.
   Added support for setting of the file position.
   Added save and restore state so that only one
   user table is actually open at one time.
   Nov/98, Rick Smereka

   Ported to 32bit Windows under CodeWarrior V4 using
   a TCP connection oriented iterative server.
   Dec/98, Rick Smereka

   Ported to HP-UX under GNU C V2.8.1.
   Jan/99, Rick Smereka

   Modified 'do_reply_int' and 'do_reply_log' to reply
   with integer value upon ok return or file data error.
   Added support for messages 'DBENG_SEND_GET_TMP_PATH'
   and 'DBENG_SEND_GET_ERROR_LOG'. Added function
   'srv_initialize' to start the local database API and
   read the 'dbeng' config file. Implemented a multi-
   platform logo. Feb/99, Rick Smereka

   Added 12 new commands that process configuration data.
   Mar/99, Rick Smereka

   Added 'dbeng' version ID string support through a
   'get' function. Apr/99, Rick Smereka

   Ported to Red Hat Linux 5.2, Jul/99, Rick Smereka

   Fixed bug in 'c_new_table' function where the check
   for a least two words was missing. Aug/99,
   Rick Smereka
   
   Modified to use the 'socloc' interface. Added all
   commom socket send codes. Removed requirement in
   function 'process_request' to have received at least
   two command words. This is required since the common
   send codes only send one parameter. Added command
   word number detection to each function that
   processes a database command. Added a command line
   parameter consisting of the TCP port number to listen.
   Program syntax now:
   
      dbsrv port
      
   Apr/2000, Rick Smereka
   
   Modified 'srv_initialize' to obtain the IP address of the
   local host to be passed to 'sloc_add'. Jul/2000,
   Rick Smereka

   Added support for new send code 'DBENG_SEND_GET_OPEN_TABLE_LIST'.
   Fixed bug in 'process_request' which would ignore a quote as the
   first character of a command parameter.
   Re-compiled for new database engine version. Jun/2001,
   Rick Smereka

   Modified for use by both sockets and QNX message passing IPC.
   Since the QNX message passing variant does not use a TCP port
   number, its syntax is:

      dbsrv

   Oct/2001, Rick Smereka

   Added session table and system catalog support.
   Nov/2001, Rick Smereka

   Added support for the new database commands 'DBENG_SEND_GET_NSUBFIELDS',
   'DBENG_SEND_GET_SUBFIELD_SIZE', 'DBENG_SEND_GET_SUBFIELD',
   'DBENG_SEND_PUT_SUBFIELD', 'DBENG_SEND_GET_NSUBSUBFIELDS',
   'DBENG_SEND_GET_SUBSUBFIELD_SIZE', 'DBENG_SEND_GET_SUBSUBFIELD'
   'DBENG_SEND_PUT_SUBSUBFIELD', 'DBENG_SEND_GET_REPLICATE_FLAG' and
   'DBENG_SEND_SET_REPLICATE_FLAG'. Jan/2002, Rick Smereka

   Added replication support. Feb/2002, Rick Smereka

   Added support for the send code 'DBENG_SEND_REPLICATE_UPDATE'.
   Mar/2002, Rick Smereka

   Coded to use the 'appinit' API. Added support for the send code
   'DBENG_SEND_DELETE_TABLE'. Added support for automatic field, 
   subfield and subsubfield append using the value zero. Functions 
   'c_put_field', 'c_put_subfield' and 'c_put_subsubfield' now allow 
   a zero value (in the field, subfield and subsubfield number parameter)
   to signify an append. Added support for the send code
   'DBENG_SEND_EXIST'. May/2002, Rick Smereka

   Changed 'main' to first turn the session table on and then
   flush all records from the session table. Added support for
   the send code 'DBENG_SEND_CLEAR_TABLE'. Jun/2002,
   Rick Smereka

   Registered application name by using the function
   'appinit_register_name'. Removed call to 'dbeng_session_flush_all'
   during initialization as this function is now automatically
   called when the session flag is set high. Jul/2002, Rick Smereka

   Ported to Debian Linux. Jan/2003, Rick Smereka

   Added support for the send codes 'DBENG_SEND_DELETE_FIELD',
   'DBENG_SEND_DELETE_SUBFIELD' and 'DBENG_SEND_DELETE_SUBSUBFIELD'.
   Mar/2003, Rick Smereka

   Modified for the updated 'socloc' API ('sloc.c').
   May/2003, Rick Smereka

   Modified for the updated 'sys_log' API ('sys_log.c').
   Changed to in accordance with the modifications in 'ipcsrv.c'.
   Added function 'term_app'. Moved all shutdown code to this
   function. Placed call to this function upon termination.
   Added support for the send codes 'DBENG_SEND_TRANS_NUM'
   and 'DBENG_SEND_CONNECT_NUM'. Modified for the updated
   'bbuuzzb' API. Jun/2003, Rick Smereka

   Changed function 'c_get_catalog_list' to obtain list of
   catalog entires from 'db_get_catalog_list'. Nov/2003,
   Rick Smereka

   Changed function 'c_count' to require only one input
   value and reply with both the active and deleted record
   counts. Changed function 'c_get_rec_count' to reply with
   both the active and deleted record counts. Feb/2004,
   Rick Smereka

   Added support for the send codes 'DBENG_SEND_GET_AUTOPACK'
   and 'DBENG_SEND_SET_AUTOPACK'. Added processing for the
   send code 'DBENG_SEND_SET_LOG'. Added global 'console_output'.
   Changed function 'main' to accept command line input for both
   TCP and QNX IPC methods. Changed function parameters for
   'parse_comline' to accept all command lines arguments.
   Changed all logging calls to use 'logman'.
   Rewrote function 'term_app'.
   Added command line switch 'q' to supress all console output.
   New command line syntax for TCP IPC method is:

      dbsrv [-q] port

   Command line syntax for QNX 4.x is:

      dbsrv [-q]

   Apr/2004, Rick Smereka

   Re-compile after changing the 'socloc' API. Changed function
   'c_config_get_log' to obtain the log file name from
   'db_config_get_log'. Jan/2005, Rick Smereka

   Fixed bug in function 'c_sort' that failed to release dynamically
   allocated memory causing a small memory leak. Re-compile after 
   modifications to low level TCP socket communication
   module (ipcomm.c). Feb/2006, Rick Smereka */

#include "stdhead.h"
#include "flsocket.h"                 /* standard IPC defines */
#include "appinit.h"                  /* application init API */
#ifdef IPC_TCP
#include "socloc.h"                   /* standard 'socloc' defines */
#include "sloc.h"                     /* 'socloc' API functions */
#endif
#include "dbmess.h"                   /* message structures and codes */
#include "dbeng.h"                    /* local engine low level */
#include "dblocal.h"                  /* local engine high level API */
#include "dbiocode.h"                 /* db engine io code translator */
#include "dbengcfg.h"                 /* low level config management */
#include "dblocfg.h"                  /* high level config management */
#include "dbengses.h"                 /* session table management */
#include "ipcsrv.h"                   /* IPC server routines */
#include "dbengcat.h"                 /* catalog management */
#ifdef IPC_TCP
#include "ip.h"                       /* IP library routines */
#include "dbengrep.h"                 /* replication management */
#endif

#define VERSION "1.22.02-2006.02.27"  /* version ID */
#define DBSRV_TERM_PASSWD "rdsWin32"  /* terminate server password */
#define APNAME "dbsrv"

/* function prototypes */

int main(int, char **);
int parse_comline(int, char **);
int srv_initialize(void);
int process_request(void);
int do_comm(int, char *);
void c_open(char *);
void c_close(char *);
void c_next(char *);
void c_top(char *);
void c_get_rec(char *);
void c_get_rec_size(char *);
void c_get_field_size(char *);
void c_get_subfield_size(char *);
void c_get_subsubfield_size(char *);
void c_get_field(char *);
void c_get_subfield(char *);
void c_get_subsubfield(char *);
void c_goto(char *);
void c_put_field(char *);
void c_put_subfield(char *);
void c_put_subsubfield(char *);
void c_write(char *);
void c_delete(char *);
void c_get_nfields(char *);
void c_get_nsubfields(char *);
void c_get_nsubsubfields(char *);
void c_get_rec_num(char *);
void c_get_delete_flag(char *);
void c_set_delete_flag(char *);
void c_count(char *);
void c_pack(char *);
void c_find(char *);
void c_find_field(char *);
void c_find_part(char *);
void c_find_field_part(char *);
void c_get_pos(char *);
void c_set_pos(char *);
void c_sort(char *);
void c_get_sort_mem(char *);
void c_set_sort_mem(char *);
void c_get_sort_open_bin(char *);
void c_set_sort_open_bin(char *);
void c_get_change_rec_flag(char *);
void c_set_change_rec_flag(char *);
void c_get_autopack(char *);
void c_set_autopack(char *);
void c_new(char *);
void c_get_rec_count(char *);
void c_get_enf_change_rec_flag(char *);
void c_set_enf_change_rec_flag(char *);
void c_get_is_table_locked(char *);
void c_set_is_table_locked(char *);
void c_new_table(char *);
void c_config_get_tmp_path(void);
void c_config_get_log(void);
void c_log_status(void);
void c_config_get_session(void);
void c_config_get_catalog(void);
void c_config_get_log_flag(void);
void c_config_get_session_flag(void);
void c_config_get_catalog_flag(void);
void c_config_get_replicate_flag(void);
void c_config_get_version(void);
void c_config_set_tmp_path(char *);
void c_config_set_session(char *);
void c_config_set_catalog(char *);
void c_config_set_log(char *);
void c_config_set_log_flag(char *);
void c_config_set_session_flag(char *);
void c_config_set_catalog_flag(char *);
void c_config_set_replicate_flag(char *);
void c_get_open_table_list(char *);
void c_replicate(char *);
void c_replicate_update(void);
void c_delete_table(char *);
void c_exist(char *);
void c_clear_table(char *);
void c_copy_table(char *);
void c_get_catalog_list(char *);
void c_delete_field(char *);
void c_delete_subfield(char *);
void c_delete_subsubfield(char *);
int c_terminate(char *);
void c_trans_num(void);
void c_connect_num(void);
int do_reply_int(int, int);
int do_reply_long(int, long);
int do_reply_code(int);
int do_reply_char(int, char *);
void term_app(void);
#ifdef IPC_TCP
void usage(void);
#endif

/* global data */

int console_output = TRUE; /* display log messages to console? */

#ifdef IPC_TCP
char server_host[128];     /* server host name */
int server_port = 0;       /* TCP port that server is using */

/* WinSock specific global data structure */

#ifdef OS_WIN32
WSADATA wsaData;           /* struct used by 'WSAStartup()' */
#endif
#else
// QNX transaction counter
long server_trans_num = 0L;
#endif

int main(int argc, char **argv)
{
   char mess[128];
   int isterm;

   /* indicate that we are initializing */

   if (!appinit_start(DBENG_SERVICE_NAME))
      {
      printf("%s:error creating 'appinit' lock file. Program abort\n",
             APNAME);
      return(0);
      }

   /* register application name */

   if (!appinit_register_name(APNAME))
      {
      printf("%s:error registering application name. Program abort\n",
             APNAME);
      (void)appinit_stop(DBENG_SERVICE_NAME);
      return(0);
      }
   
   /* check for 'socloc' (TCP) and 'sys_log' servers initializing */

#ifdef IPC_TCP
   if (!appinit_waitfor(SL_SERVICE_NAME, 5))
      {
      printf("%s:error waiting for 'socloc' to initialize. "
             "Program abort\n", APNAME);
      (void)appinit_stop(DBENG_SERVICE_NAME);
      return(0);
      }
#endif

   if (!appinit_waitfor(SYS_LOG_SERVICE_NAME, 1))
      {
      printf("%s:error waiting for 'sys_log' to initialize. "
             "Program abort\n", APNAME);
      (void)appinit_stop(DBENG_SERVICE_NAME);
      return(0);
      }

   /* check for command line parameters */
   
#ifdef IPC_TCP
   if (argc == 1)
      {
      (void)appinit_stop(DBENG_SERVICE_NAME);
      usage();
      return(0);
      }
#endif

   /* parse command line */
   
   if (!parse_comline(argc, argv))
      {
      (void)appinit_stop(DBENG_SERVICE_NAME);
      return(0);
      }

   // set console output

   logman_console(console_output);

   /* perform initialization of 'socloc' (TCP only), 'sys_log' and the
      'Bbuuzzb' engine */
      
   if (!srv_initialize())
      {
      (void)appinit_stop(DBENG_SERVICE_NAME);
      term_app();
      return(0);
      }
      
   /* build logo string based on platform */

#ifndef OS_UNIX
   /* non-Unix */

   logman("%s Database Server for %s Version %s", APNAME, 
          PLATFORM_STRING, VERSION);
#else
   /* Unix */

   logman("%s Database Server for %s Version %s", APNAME,
           SUB_PLATFORM_STRING, VERSION);
#endif

   logman_nf("By Rick Smereka, Copyright (c) 1997-2006");

#ifdef IPC_TCP
   logman("server on \"%s\" servicing TCP port %d (decimal)",
           server_host, server_port);
#endif
   logman_nf("database server started");
   logman("%s comes with ABSOLUTELY NO WARRANTY", APNAME);
   logman_nf("This is free software, and you are welcome to redistribute it");
   logman_nf("under certain conditions; see \"gpl.txt\" for information."); 
   
   /* turn off system log as this is used only for debugging */
   
   (void)db_config_set_log_flag(FALSE);

   /* turn on session table and system catalog by default */

   (void)db_config_set_session_flag(TRUE);
   (void)db_config_set_catalog_flag(TRUE);

   /* indicate that we have completed initialization */

   (void)appinit_stop(DBENG_SERVICE_NAME);
   
#ifdef IPC_TCP
   ipc_server_wait();
#else
   // QNX, process each connection (infinite loop)

   while(1)
      {
      isterm = process_request();
      server_trans_num++;

      if (isterm)
         break;
      }
#endif
                     
   term_app();
   return(0);
}

int parse_comline(int c_count, char **c_parm)
{
   /* Parse the command line. Function returns 'TRUE' if no
      error was detected, 'FALSE' otherwise. */
      
   char mname[] = "parse_comline";
   int parms = 1, done = FALSE;

#ifdef IPC_QNX
   if (c_count == 1)
      return(TRUE);
#endif

   while(!done)
      {      
      if (c_parm[parms][0] == SWITCH_CHAR)      
         {
         switch(toupper(c_parm[parms][1]))
            {
            case 'Q':
               console_output = FALSE;
               parms++;
               break;
               
            default:
               printf("%s:unknown switch[%s], program abort\n",
                      mname, c_parm[parms]);
               return(FALSE);
            };
         }
#ifdef IPC_TCP
      else
         {
         if (!qatoi(c_parm[parms], &server_port))
            {
            printf("%s:server port is non-numeric, "
                   "program abort\n", mname);
            return(FALSE);
            }
            
         if (server_port <= 0)
            {
            printf("%s:server port is out of range, "
                   "program abort\n", mname);
            return(FALSE);
            }
            
         parms++;
         }
#endif
         
      if (parms >= c_count)
         done = TRUE;
      }

#ifdef IPC_TCP
   if (server_port == 0)
      {
      printf("%s:server port missing, program abort\n", mname);
      return(FALSE);
      }
#endif
            
   return(TRUE);
}

int srv_initialize(void)
{
   /* Start the 'DBENG' local engine, read the config file
      and display the result settings. */

   char mes[DBENG_PATH_LIMIT], mname[] = "srv_initialize";
   int ret;

   /* startup WinSock (if Windoze) */
   
#ifdef OS_WIN32
   if (WSAStartup(WINSOCK_VERSION, &wsaData))
      {
      printf("%s:unable to start WinSock, "
             "program abort\n", mname);      
      return(FALSE);
      }
#endif

   /* initialize the server on the IPC level, note that
      the hostname 'server_host' is returned to us (TCP only) */
      
#ifdef IPC_TCP
   if (!ipc_init(server_host, server_port))
#else
   if (!ipc_init(DBENG_SERVICE_NAME))
#endif
      {
      printf("%s:'ipc_init' initialization failure, "
                 "program abort\n", mname);
      return(FALSE);
      }

   /* initialize 'socloc' client API */
   
#ifdef IPC_TCP
   if ((ret = sloc_initialize()) != SL_OK)
      {
      sl_code_string(ret, mes);
      printf("%s:socloc init failure,rc[%s]\n", mname, mes);
      printf("%s:program abort\n", mname);
      return(FALSE);
      }

   /* get IP address of this machine */
   
   if (!ip_host2ip(server_host, mes))
      {
      printf("%s:unable to obtain IP address of this "
             "machine\n", mname);
      printf("%s:program abort\n", mname);
      return(FALSE);
      }
      
   /* register this server with 'socloc' */
   
   if ((ret = sloc_add(DBENG_SERVICE_NAME, server_host, server_port,
       mes)) != SL_OK)
      {
      sl_code_string(ret, mes);
      printf("%s:unable to register server with 'socloc'\n", mname);
      printf("%s:rc[%s], program abort\n", mname, mes);
      return(FALSE);
      }         
#endif

   /* initialize 'Bbuuzzb' engine */

   ret = db_initialize();

   /* interpret code from init which may be
      a fatal config error */

   switch(ret)
      {
      case DBENG_OK:
         if (console_output)
            printf("%s:read config file successfully\n", mname);

         break;

      case DBENG_CONFIG_UNABLE_TO_OPEN:
         printf("%s:config file not found, loaded defaults\n", mname);
         break;

      default:
         db_io_code_string(ret, mes);
         printf("%s:config error[%s]\n", mname, mes);         
         printf("%s:terminating\n", mname);
         (void)c_terminate(DBSRV_TERM_PASSWD);
         return(FALSE);
         break;
      };

   /* set log flag high which will start logging */
   
   if ((ret = db_config_set_log_flag(TRUE)) != DBENG_OK)
      {
      printf("%s:error starting logging,program abort\n", mname);
      (void)c_terminate(DBSRV_TERM_PASSWD);
      return(FALSE);
      }   

   (void)db_config_get_tmp_path(mes);
   logman("%s:tmp path is %s", mname, mes);

   (void)db_config_get_log(mes);
   logman("%s:log is %s", mname, mes);

   (void)db_config_get_session(mes);
   logman("%s:session table is %s", mname, mes);

   (void)db_config_get_catalog(mes);
   logman("%s:catalog is %s", mname, mes);
   
   (void)db_config_get_version(mes);
   logman("%s:based on version %s of \"Bbuuzzb\"", mname, mes);
   return(TRUE);
}

int process_request(void)
{
   /* Process a single request. Function returns 'FALSE' if
      termination signal was not encountered, 'TRUE'
      otherwise. */

   char mname[] = "proces_request";
   char *messbuf, tmp[128];
   int ret, nbytes, nwords, mestype, indx;

   logman("%s:enter", mname);
   
   if ((messbuf = (char *)malloc(DBENG_MAXRECFIELD)) == (char *)NULL)
      {
      logman("%s:alloc fail[messbuf]", mname);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return(FALSE);
      }
           
   memset(messbuf, 0, DBENG_MAXRECFIELD);
   
   // get the message from the client

#ifdef IPC_TCP
   if ((nbytes = ipc_recv_data(messbuf)) == 0)
#else
   if ((nbytes = ipc_recv_data(messbuf, DBENG_MAXRECFIELD)) == 0)
#endif
      {
      free(messbuf);
      logman("%s:connection closed by client", mname);
#ifdef IPC_TCP
      return(-1);
#else
      return(FALSE);
#endif
      }
   
   messbuf[nbytes] = EOS;
   nwords = command_words(messbuf);   
      
   // no command words, empty string
       
   if (!nwords)
      {
      logman("%s:command contains no words", mname);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(messbuf);
      return(FALSE);
      }
            
   // first command word must be a number

   if (!command_word(messbuf, tmp, 1))
      {      
      free(messbuf);
      logman("%s:error command code", mname);
      (void)do_reply_code(DBENG_INTERNAL_ERROR);
      return(FALSE);
      }
   
   if (!qatoi(tmp, &mestype))
      {
      logman("%s:command code is not numeric", mname);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(messbuf);
      return(FALSE);
      }      

   logman("%s:recv[%d],nwords[%d]", mname, mestype, nwords);
      
   /* if command contains more than one word, pass pointer
      to start of second word */
   
   if (nwords > 1)
      {
      indx = command_indxword(messbuf, 2);
   
      if (indx == -1)
         {
         free(messbuf);
         logman("%s:error getting index of second word", mname);
         (void)do_reply_code(DBENG_INTERNAL_ERROR);
         return(FALSE);
         }
      
      /* if the first char in the second word is a quote,
         'command_indxword' will skip over this, we need
         to backup one position */

      if (messbuf[indx - 1] == '\"' || messbuf[indx - 1] == '\'')
         indx--;

      ret = do_comm(mestype, &messbuf[indx]);
      }
   else
      ret = do_comm(mestype, (char *)NULL);
      
   free(messbuf);
   logman("%s:normal exit rc[%d]", mname, ret);
   return(ret);   
}
   
int do_comm(int mestype, char *slm)
{
   /* High level database command dispatcher. 
      Function returns 'TRUE' if a terminate
      request was encountered, 'FALSE'
      otherwise. */
   
   char mname[] = "do_comm";
   int ret, rc, session_flag, should_rs, tid;

   logman("%s:enter", mname);
   ret = FALSE;

   /* restore data from session table if appropriate */

   (void)db_config_get_session_flag(&session_flag);
   
   if (session_flag)
      if ((should_rs = dbeng_session_should_rs(mestype, slm, &tid)) == TRUE)
         if ((rc = dbeng_session_restore(tid)) != DBENG_OK)
            db_io_code_log(mname, "error restoring session", rc);

   switch(mestype)
      {
      case DBENG_SEND_OPEN:
         c_open(slm);
         break;

      case DBENG_SEND_CLOSE:
         c_close(slm);
         break;

      case DBENG_SEND_NEXT:
         c_next(slm);
         break;

      case DBENG_SEND_TOP:
         c_top(slm);
         break;

      case DBENG_SEND_GET_REC:
         c_get_rec(slm);
         break;

      case DBENG_SEND_GET_REC_SIZE:
         c_get_rec_size(slm);
         break;

      case DBENG_SEND_GET_FIELD_SIZE:
         c_get_field_size(slm);
         break;

      case DBENG_SEND_GET_FIELD:
         c_get_field(slm);
         break;

      case DBENG_SEND_GOTO:
         c_goto(slm);
         break;

      case DBENG_SEND_PUT_FIELD:
         c_put_field(slm);
         break;

      case DBENG_SEND_WRITE:
         c_write(slm);
         break;

      case DBENG_SEND_DELETE:
         c_delete(slm);
         break;

      case DBENG_SEND_GET_NFIELDS:
         c_get_nfields(slm);
         break;

      case DBENG_SEND_GET_REC_NUM:
         c_get_rec_num(slm);
         break;

      case DBENG_SEND_GET_DELETE_FLAG:
         c_get_delete_flag(slm);
         break;

      case DBENG_SEND_SET_DELETE_FLAG:
         c_set_delete_flag(slm);
         break;

      case DBENG_SEND_COUNT:
         c_count(slm);
         break;

      case DBENG_SEND_PACK:
         c_pack(slm);
         break;

      case DBENG_SEND_FIND:
         c_find(slm);
         break;

      case DBENG_SEND_FIND_FIELD:
         c_find_field(slm);
         break;

      case DBENG_SEND_FIND_PART:
         c_find_part(slm);
         break;

      case DBENG_SEND_FIND_FIELD_PART:
         c_find_field_part(slm);
         break;

      case DBENG_SEND_GET_POS:
         c_get_pos(slm);
         break;

      case DBENG_SEND_SET_POS:
         c_set_pos(slm);
         break;

      case DBENG_SEND_GET_CHANGE_REC_FLAG:
         c_get_change_rec_flag(slm);
         break;

      case DBENG_SEND_SET_CHANGE_REC_FLAG:
         c_set_change_rec_flag(slm);
         break;

      case DBENG_SEND_NEW:
         c_new(slm);
         break;

      case DBENG_SEND_GET_REC_COUNT:
         c_get_rec_count(slm);
         break;

      case DBENG_SEND_GET_ENF_CHANGE_REC_FLAG:
         c_get_enf_change_rec_flag(slm);
         break;

      case DBENG_SEND_SET_ENF_CHANGE_REC_FLAG:
         c_set_enf_change_rec_flag(slm);
         break;

      case DBENG_SEND_GET_IS_TABLE_LOCKED:
         c_get_is_table_locked(slm);
         break;

      case DBENG_SEND_SET_IS_TABLE_LOCKED:
         c_set_is_table_locked(slm);
         break;

      case DBENG_SEND_STATUS:
         (void)do_reply_code(DBENG_OK);
         break;

      case DBENG_SEND_NEW_TABLE:
         c_new_table(slm);
         break;
      
      case DBENG_SEND_GET_TMP_PATH:
         c_config_get_tmp_path();
         break;

      case DBENG_SEND_GET_LOG:
         c_config_get_log();
         break;

      case DBENG_SEND_GET_SESSION:
         c_config_get_session();
         break;

      case DBENG_SEND_GET_CATALOG:
         c_config_get_catalog();
         break;

      case DBENG_SEND_GET_LOG_FLAG:
         c_config_get_log_flag();
         break;
         
      case DBENG_SEND_GET_SESSION_FLAG:
         c_config_get_session_flag();
         break;
         
      case DBENG_SEND_GET_CATALOG_FLAG:
         c_config_get_catalog_flag();
         break;

      case DBENG_SEND_GET_REPLICATE_FLAG:
         c_config_get_replicate_flag();
         break;

      case DBENG_SEND_GET_DBENG_VERSION:
         /* get version of 'Bbuuzzb' engine */
         
         c_config_get_version();
         break;
                  
      case DBENG_SEND_SET_TMP_PATH:
         c_config_set_tmp_path(slm);
         break;

      case DBENG_SEND_SET_SESSION:
         c_config_set_session(slm);
         break;

      case DBENG_SEND_SET_CATALOG:
         c_config_set_catalog(slm);
         break;
         
      case DBENG_SEND_SET_LOG_FLAG:
         c_config_set_log_flag(slm);
         break;
         
      case DBENG_SEND_SET_SESSION_FLAG:
         c_config_set_session_flag(slm);
         break;
         
      case DBENG_SEND_SET_CATALOG_FLAG:
         c_config_set_catalog_flag(slm);
         break;
                     
      case DBENG_SEND_SET_REPLICATE_FLAG:
         c_config_set_replicate_flag(slm);
         break;

      case DBENG_SEND_TERM:
         ret = c_terminate(slm);
         break;

      case DBENG_SEND_LOG_OFF:
         /* common socket code, call config set log */
         
         c_config_set_log_flag("0");
         break;

      case DBENG_SEND_LOG_ON:
         /* common socket code, call config set log */
         
         c_config_set_log_flag("1");
         break;

      case DBENG_SEND_LOG_STATUS:
         c_log_status();
         break;

      case DBENG_SEND_SERVICE_NAME:
         (void)do_reply_char(DBENG_OK, DBENG_SERVICE_NAME);
         break;

      case DBENG_SEND_VERSION:
         /* reply with version of server */
         
         (void)do_reply_char(DBENG_OK, VERSION);
         break;

      case DBENG_SEND_GET_OPEN_TABLE_LIST:
         c_get_open_table_list(slm);
         break;

      case DBENG_SEND_GET_NSUBFIELDS:
         c_get_nsubfields(slm);
         break;

      case DBENG_SEND_GET_SUBFIELD_SIZE:
         c_get_subfield_size(slm);
         break;

      case DBENG_SEND_GET_SUBFIELD:
         c_get_subfield(slm);
         break;

      case DBENG_SEND_PUT_SUBFIELD:
         c_put_subfield(slm);
         break;

      case DBENG_SEND_GET_NSUBSUBFIELDS:
         c_get_nsubsubfields(slm);
         break;

      case DBENG_SEND_GET_SUBSUBFIELD_SIZE:
         c_get_subsubfield_size(slm);
         break;

      case DBENG_SEND_GET_SUBSUBFIELD:
         c_get_subsubfield(slm);
         break;

      case DBENG_SEND_PUT_SUBSUBFIELD:
         c_put_subsubfield(slm);
         break;

      case DBENG_SEND_REPLICATE:
         c_replicate(slm);
         break;

      case DBENG_SEND_REPLICATE_UPDATE:
         c_replicate_update();
         break;

      case DBENG_SEND_DELETE_TABLE:
         c_delete_table(slm);
         break;

      case DBENG_SEND_EXIST:
         c_exist(slm);
         break;

      case DBENG_SEND_CLEAR_TABLE:
         c_clear_table(slm);
         break;

      case DBENG_SEND_COPY_TABLE:
         c_copy_table(slm);
         break;

      case DBENG_SEND_GET_CATALOG_LIST:
         c_get_catalog_list(slm);
         break;

      case DBENG_SEND_SORT:
         c_sort(slm);
         break;

      case DBENG_SEND_GET_SORT_MEM:
         c_get_sort_mem(slm);
         break;

      case DBENG_SEND_SET_SORT_MEM:
         c_set_sort_mem(slm);
         break;

      case DBENG_SEND_GET_SORT_OPEN_BIN:
         c_get_sort_open_bin(slm);
         break;

      case DBENG_SEND_SET_SORT_OPEN_BIN:
         c_set_sort_open_bin(slm);
         break;

      case DBENG_SEND_DELETE_FIELD:
         c_delete_field(slm);
         break;

      case DBENG_SEND_DELETE_SUBFIELD:
         c_delete_subfield(slm);
         break;

      case DBENG_SEND_DELETE_SUBSUBFIELD:
         c_delete_subsubfield(slm);
         break;

      case DBENG_SEND_TRANS_NUM:
         c_trans_num();
         break;

      case DBENG_SEND_CONNECT_NUM:
         c_connect_num();
         break;

      case DBENG_SEND_GET_AUTOPACK:
         c_get_autopack(slm);
         break;

      case DBENG_SEND_SET_AUTOPACK:
         c_set_autopack(slm);
         break;

      case DBENG_SEND_SET_LOG:
         c_config_set_log(slm);
         break;

      default:
         (void)do_reply_code(DBENG_INVALID_FUNCTION);
         logman("%s:received unknown code[%d]", mname, mestype);
         break;
      };

   /* save session */

   if (session_flag && should_rs)
      if ((rc = dbeng_session_save(tid)) != DBENG_OK)
         db_io_code_log(mname, "error saving session", rc);

   logman("%s:exit %d", mname, ret);
   return(ret);
}

void c_open(char *comm)
{
   /* Open a table. The file name is expected on the command line.
      Function replies with the table 'tid' and 'DBENG_OK' upon
      success, an error code otherwise. Syntax:

         file_name */

   char mname[25], *fname;
   int tid = 0;
   int ret, driret;
  
   strcpy(mname, "c_open");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_INVALID_FILE_NAME);
      (void)do_reply_int(DBENG_INVALID_FILE_NAME, tid);
      return;
      }

   if ((fname = (char *)malloc(strlen(comm) + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[fname]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, tid);
      return;
      }

   if (!command_word(comm, fname, 1))
      {
      free(fname);
      db_io_code_log(mname, "bad rc from command_word[fname]",
                     DBENG_INTERNAL_ERROR);
      (void)do_reply_int(DBENG_INTERNAL_ERROR, tid);
      return;
      }

   ret = db_open(fname, &tid);
   free(fname);
   
   if ((driret = do_reply_int(ret, tid)) != DBENG_OK)
      {
      logman("c_open:bad ret from do_reply_int,rc[%d]", driret);
      return;
      }

   db_io_code_log(mname, "normal exit", ret);
}

void c_close(char *comm)
{
   /* Close a table. The table tid is expected on the command line.
      Function replies with a DBENG io code. Syntax:

         tid */

   char *tid_char;
   char mname[25];
   int tid;
   int len;
   int ret;

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

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);
   ret = db_close(tid);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_next(char *comm)
{
   /* Get the next record in a table. The table tid is expected on the
      command line. Function replies with a DBENG io code. Syntax:

         tid */

   char *tid_char;
   char mname[25];
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_next");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);
   ret = db_next(tid);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_top(char *comm)
{
   /* Goto the top of the table. The table tid is expected on the
      command line. Note that the record pointer is moved to the
      very top of the table and no current record exists. Function
      replies with a DBENG io code. Syntax:

         tid */

   char *tid_char;
   char mname[25];
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_top");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);
   ret = db_top(tid);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_rec(char *comm)
{
   /* Get the current record. Note that the file pointer position
      is not changed. Function replies with a DBENG io code. Syntax:
      
         tid */

   char *rdata;
   char *tid_char;
   char mname[25];
   int recsize;
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_get_rec");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_char(DBENG_NO_SUCH_TID, "");
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_char(DBENG_NO_SUCH_TID, "");
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_char(DBENG_NO_SUCH_TID, "");
      return;
      }

   free(tid_char);
   ret = db_get_rec_size(tid, &recsize);

   if (ret != DBENG_OK)
      {
      db_io_code_log(mname, "unable to get record size", ret);
      (void)do_reply_char(ret, "");
      return;
      }

   if ((rdata = malloc(recsize + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[rdata]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }
   
   ret = db_get_rec(tid, rdata);
   (void)do_reply_char(ret, rdata);
   free(rdata);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_rec_size(char *comm)
{
   /* Get the size (in bytes) of the current record. The table tid
      is expected on the command line. Function replies with a DBENG io
      code. Syntax:

         tid */

   char *tid_char;
   char mname[25];
   int rec_size;
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_get_rec_size");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   free(tid_char);
   ret = db_get_rec_size(tid, &rec_size);
   (void)do_reply_int(ret, rec_size);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_field_size(char *comm)
{
   /* Get the size (in bytes) of a specific field in the current
      record. The table tid is expected on the command line.
      Function replies with a DBENG io code. Syntax:

         tid field_number */

   char *tid_char;
   char *fnum_char;
   char mname[25];
   int fnum;
   int field_size;
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_get_field_size");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   len = strlen(comm);

   if (words(comm) < 2)
      {
      db_io_code_log(mname, "missing field number", DBENG_NO_SUCH_FIELD);
      (void)do_reply_int(DBENG_NO_SUCH_FIELD, 0);
      return;
      }

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   free(tid_char);

   if ((fnum_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[fnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, fnum_char, 2);
      
   if (!qatoi(fnum_char, &fnum))
      {
      db_io_code_log(mname, "non numeric field number", DBENG_NO_SUCH_FIELD);
      (void)do_reply_int(DBENG_NO_SUCH_FIELD, 0);
      free(fnum_char);
      return;
      }

   if (fnum <= 0)
      {
      db_io_code_log(mname, "field number out of range", DBENG_NO_SUCH_FIELD);
      (void)do_reply_int(DBENG_NO_SUCH_FIELD, 0);
      free(fnum_char);
      return;
      }

   free(fnum_char);
   ret = db_get_field_size(tid, fnum, &field_size);
   (void)do_reply_int(ret, field_size);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_subfield_size(char *comm)
{
   /* Get the size (in bytes) of a specific sub-field in a field
      The table tid is expected on the command line.
      Function replies with a DBENG io code. Syntax:

         tid field_number sub-field_number */

   char *tid_char, *fnum_char, *sfnum_char, mname[] = "c_get_subfield_size";
   int fnum, sfnum, sf_size, tid, len, ret;
  
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   len = strlen(comm);

   if (words(comm) < 2)
      {
      db_io_code_log(mname, "missing field number", DBENG_NO_SUCH_FIELD);
      (void)do_reply_int(DBENG_NO_SUCH_FIELD, 0);
      return;
      }

   if (words(comm) < 3)
      {
      db_io_code_log(mname, "missing sub-field number", DBENG_NO_SUCH_SUBFIELD);
      (void)do_reply_int(DBENG_NO_SUCH_SUBFIELD, 0);
      return;
      }

   if ((tid_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   free(tid_char);

   if ((fnum_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[fnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, fnum_char, 2);
      
   if (!qatoi(fnum_char, &fnum))
      {
      db_io_code_log(mname, "non numeric field number", DBENG_NO_SUCH_FIELD);
      (void)do_reply_int(DBENG_NO_SUCH_FIELD, 0);
      free(fnum_char);
      return;
      }

   if (fnum <= 0)
      {
      db_io_code_log(mname, "field number out of range", DBENG_NO_SUCH_FIELD);
      (void)do_reply_int(DBENG_NO_SUCH_FIELD, 0);
      free(fnum_char);
      return;
      }

   free(fnum_char);

   if ((sfnum_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[sfnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, sfnum_char, 3);
      
   if (!qatoi(sfnum_char, &sfnum))
      {
      db_io_code_log(mname, "non numeric sub-field number", 
                     DBENG_NO_SUCH_SUBFIELD);
      (void)do_reply_int(DBENG_NO_SUCH_SUBFIELD, 0);
      free(sfnum_char);
      return;
      }

   if (sfnum <= 0)
      {
      db_io_code_log(mname, "sub-field number out of range", 
                     DBENG_NO_SUCH_SUBFIELD);
      (void)do_reply_int(DBENG_NO_SUCH_SUBFIELD, 0);
      free(sfnum_char);
      return;
      }

   free(sfnum_char);
   ret = db_get_subfield_size(tid, fnum, sfnum, &sf_size);
   (void)do_reply_int(ret, sf_size);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_subsubfield_size(char *comm)
{
   /* Get the size (in bytes) of a specific sub-sub-field in a sub-field
      The table tid is expected on the command line.
      Function replies with a DBENG io code. Syntax:

         tid field_number sub-field_number sub-sub-field_number */

   char *tid_char, *fnum_char, *sfnum_char; 
   char *ssfnum_char, mname[] = "c_get_subsubfield_size";
   int nwords, fnum, sfnum, ssfnum, ssf_size, tid, len, ret;
  
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   len = strlen(comm);
   nwords = words(comm);

   if (nwords < 2)
      {
      db_io_code_log(mname, "missing field number", DBENG_NO_SUCH_FIELD);
      (void)do_reply_int(DBENG_NO_SUCH_FIELD, 0);
      return;
      }

   if (nwords < 3)
      {
      db_io_code_log(mname, "missing sub-field number", DBENG_NO_SUCH_SUBFIELD);
      (void)do_reply_int(DBENG_NO_SUCH_SUBFIELD, 0);
      return;
      }

   if (nwords < 4)
      {
      db_io_code_log(mname, "missing sub-sub-field number", 
                     DBENG_NO_SUCH_SUBSUBFIELD);
      (void)do_reply_int(DBENG_NO_SUCH_SUBSUBFIELD, 0);
      return;
      }

   if ((tid_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   free(tid_char);

   if ((fnum_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[fnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, fnum_char, 2);
      
   if (!qatoi(fnum_char, &fnum))
      {
      db_io_code_log(mname, "non numeric field number", DBENG_NO_SUCH_FIELD);
      (void)do_reply_int(DBENG_NO_SUCH_FIELD, 0);
      free(fnum_char);
      return;
      }

   if (fnum <= 0)
      {
      db_io_code_log(mname, "field number out of range", DBENG_NO_SUCH_FIELD);
      (void)do_reply_int(DBENG_NO_SUCH_FIELD, 0);
      free(fnum_char);
      return;
      }

   free(fnum_char);

   if ((sfnum_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[sfnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, sfnum_char, 3);
      
   if (!qatoi(sfnum_char, &sfnum))
      {
      db_io_code_log(mname, "non numeric sub-field number", 
                     DBENG_NO_SUCH_SUBFIELD);
      (void)do_reply_int(DBENG_NO_SUCH_SUBFIELD, 0);
      free(sfnum_char);
      return;
      }

   if (sfnum <= 0)
      {
      db_io_code_log(mname, "sub-field number out of range", 
                     DBENG_NO_SUCH_SUBFIELD);
      (void)do_reply_int(DBENG_NO_SUCH_SUBFIELD, 0);
      free(sfnum_char);
      return;
      }

   free(sfnum_char);

   if ((ssfnum_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[ssfnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, ssfnum_char, 4);
      
   if (!qatoi(ssfnum_char, &ssfnum))
      {
      db_io_code_log(mname, "non numeric sub-sub-field number", 
                     DBENG_NO_SUCH_SUBSUBFIELD);
      (void)do_reply_int(DBENG_NO_SUCH_SUBSUBFIELD, 0);
      free(ssfnum_char);
      return;
      }

   if (ssfnum <= 0)
      {
      db_io_code_log(mname, "sub-sub-field number out of range", 
                     DBENG_NO_SUCH_SUBSUBFIELD);
      (void)do_reply_int(DBENG_NO_SUCH_SUBSUBFIELD, 0);
      free(ssfnum_char);
      return;
      }

   free(ssfnum_char);
   ret = db_get_subsubfield_size(tid, fnum, sfnum, ssfnum, &ssf_size);
   (void)do_reply_int(ret, ssf_size);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_field(char *comm)
{
   /* Get a specific field in the current record. The table tid
      is expected on the command line. Function replies with a
      DBENG io code. Syntax:

         tid field_number */

   char *tid_char;
   char *fnum_char;
   char *field_out;
   char mname[25];
   int fnum;
   int field_size;
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_get_field");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_char(DBENG_NO_SUCH_TID, "");
      return;
      }

   len = strlen(comm);

   if (words(comm) < 2)
      {
      db_io_code_log(mname, "missing field number", DBENG_NO_SUCH_FIELD);
      (void)do_reply_char(DBENG_NO_SUCH_FIELD, "");
      return;
      }

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_char(DBENG_NO_SUCH_TID, "");
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_char(DBENG_NO_SUCH_TID, "");
      return;
      }

   free(tid_char);

   if ((fnum_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[fnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   (void)word(comm, fnum_char, 2);
      
   if (!qatoi(fnum_char, &fnum))
      {
      free(fnum_char);
      db_io_code_log(mname, "non numeric field number", DBENG_NO_SUCH_FIELD);
      (void)do_reply_char(DBENG_NO_SUCH_FIELD, "");
      return;
      }

   if (fnum <= 0)
      {
      free(fnum_char);
      db_io_code_log(mname, "field number out of range", DBENG_NO_SUCH_FIELD);
      (void)do_reply_char(DBENG_NO_SUCH_FIELD, "");
      return;
      }

   free(fnum_char);

   if ((ret = db_get_field_size(tid, fnum, &field_size)) != DBENG_OK)
      {
      db_io_code_log(mname, "error getting field size", ret);
      (void)do_reply_char(ret, "");
      return;
      }

   if ((field_out = malloc(field_size + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[field_out]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   ret = db_get_field(tid, fnum, field_out);
   (void)do_reply_char(ret, field_out);
   free(field_out);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_subfield(char *comm)
{
   /* Get a specific sub-field in a field. The table tid
      is expected on the command line. Function replies with a
      DBENG io code. Syntax:

         tid field_number sub-field_number */

   char *tid_char, *fnum_char, *sfnum_char, *subfield_out;
   char mname[] = "c_get_subfield";
   int tid, fnum, sfnum, sf_size, len, ret;
  
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_char(DBENG_NO_SUCH_TID, "");
      return;
      }

   len = strlen(comm);

   if (words(comm) < 2)
      {
      db_io_code_log(mname, "missing field number", DBENG_NO_SUCH_FIELD);
      (void)do_reply_char(DBENG_NO_SUCH_FIELD, "");
      return;
      }

   if (words(comm) < 3)
      {
      db_io_code_log(mname, "missing sub-field number", DBENG_NO_SUCH_SUBFIELD);      (void)do_reply_char(DBENG_NO_SUCH_SUBFIELD, "");
      return;
      }

   if ((tid_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_char(DBENG_NO_SUCH_TID, "");
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_char(DBENG_NO_SUCH_TID, "");
      return;
      }

   free(tid_char);

   if ((fnum_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[fnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   (void)word(comm, fnum_char, 2);
      
   if (!qatoi(fnum_char, &fnum))
      {
      free(fnum_char);
      db_io_code_log(mname, "non numeric field number", DBENG_NO_SUCH_FIELD);
      (void)do_reply_char(DBENG_NO_SUCH_FIELD, "");
      return;
      }

   if (fnum <= 0)
      {
      free(fnum_char);
      db_io_code_log(mname, "field number out of range", DBENG_NO_SUCH_FIELD);
      (void)do_reply_char(DBENG_NO_SUCH_FIELD, "");
      return;
      }

   free(fnum_char);

   if ((sfnum_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[sfnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   (void)word(comm, sfnum_char, 3);
      
   if (!qatoi(sfnum_char, &sfnum))
      {
      free(sfnum_char);
      db_io_code_log(mname, "non numeric sub-field number", 
                     DBENG_NO_SUCH_SUBFIELD); 
      (void)do_reply_char(DBENG_NO_SUCH_SUBFIELD, "");
      return;
      }

   if (sfnum <= 0)
      {
      free(sfnum_char);
      db_io_code_log(mname, "sub-field number out of range", 
                     DBENG_NO_SUCH_SUBFIELD); 
      (void)do_reply_char(DBENG_NO_SUCH_SUBFIELD, "");
      return;
      }

   free(sfnum_char);

   if ((ret = db_get_subfield_size(tid, fnum, sfnum, &sf_size)) != DBENG_OK)
      {
      db_io_code_log(mname, "error getting sub-field size", ret);
      (void)do_reply_char(ret, "");
      return;
      }

   if ((subfield_out = (char *)malloc(sf_size + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[subfield_out]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   ret = db_get_subfield(tid, fnum, sfnum, subfield_out);
   (void)do_reply_char(ret, subfield_out);
   free(subfield_out);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_subsubfield(char *comm)
{
   /* Get a specific sub-sub-field in a sub-field. The table tid
      is expected on the command line. Function replies with a
      DBENG io code. Syntax:

         tid field_number sub-field_number sub-sub-field_number */

   char *tid_char, *fnum_char, *sfnum_char, *ssfnum_char;
   char *subsubfield_out, mname[] = "c_get_subsubfield";
   int nwords, tid, fnum, sfnum, ssfnum, ssf_size, len, ret;
  
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_char(DBENG_NO_SUCH_TID, "");
      return;
      }

   len = strlen(comm);
   nwords = words(comm);

   if (nwords < 2)
      {
      db_io_code_log(mname, "missing field number", DBENG_NO_SUCH_FIELD);
      (void)do_reply_char(DBENG_NO_SUCH_FIELD, "");
      return;
      }

   if (nwords < 3)
      {
      db_io_code_log(mname, "missing sub-field number", DBENG_NO_SUCH_SUBFIELD);      (void)do_reply_char(DBENG_NO_SUCH_SUBFIELD, "");
      return;
      }

   if (nwords < 4)
      {
      db_io_code_log(mname, "missing sub-sub-field number", 
                     DBENG_NO_SUCH_SUBSUBFIELD);      
      (void)do_reply_char(DBENG_NO_SUCH_SUBSUBFIELD, "");
      return;
      }

   if ((tid_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_char(DBENG_NO_SUCH_TID, "");
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_char(DBENG_NO_SUCH_TID, "");
      return;
      }

   free(tid_char);

   if ((fnum_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[fnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   (void)word(comm, fnum_char, 2);
      
   if (!qatoi(fnum_char, &fnum))
      {
      free(fnum_char);
      db_io_code_log(mname, "non numeric field number", DBENG_NO_SUCH_FIELD);
      (void)do_reply_char(DBENG_NO_SUCH_FIELD, "");
      return;
      }

   if (fnum <= 0)
      {
      free(fnum_char);
      db_io_code_log(mname, "field number out of range", DBENG_NO_SUCH_FIELD);
      (void)do_reply_char(DBENG_NO_SUCH_FIELD, "");
      return;
      }

   free(fnum_char);

   if ((sfnum_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[sfnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   (void)word(comm, sfnum_char, 3);
      
   if (!qatoi(sfnum_char, &sfnum))
      {
      free(sfnum_char);
      db_io_code_log(mname, "non numeric sub-field number", 
                     DBENG_NO_SUCH_SUBFIELD); 
      (void)do_reply_char(DBENG_NO_SUCH_SUBFIELD, "");
      return;
      }

   if (sfnum <= 0)
      {
      free(sfnum_char);
      db_io_code_log(mname, "sub-field number out of range", 
                     DBENG_NO_SUCH_SUBFIELD); 
      (void)do_reply_char(DBENG_NO_SUCH_FIELD, "");
      return;
      }

   free(sfnum_char);

   if ((ssfnum_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[ssfnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   (void)word(comm, ssfnum_char, 4);
      
   if (!qatoi(ssfnum_char, &ssfnum))
      {
      free(ssfnum_char);
      db_io_code_log(mname, "non numeric sub-sub-field number", 
                     DBENG_NO_SUCH_SUBSUBFIELD); 
      (void)do_reply_char(DBENG_NO_SUCH_SUBSUBFIELD, "");
      return;
      }

   if (ssfnum <= 0)
      {
      free(ssfnum_char);
      db_io_code_log(mname, "sub-sub-field number out of range", 
                     DBENG_NO_SUCH_SUBSUBFIELD); 
      (void)do_reply_char(DBENG_NO_SUCH_SUBSUBFIELD, "");
      return;
      }

   free(ssfnum_char);

   if ((ret = db_get_subsubfield_size(tid, fnum, sfnum, ssfnum, 
        &ssf_size)) != DBENG_OK)
      {
      db_io_code_log(mname, "error getting sub-sub-field size", ret);
      (void)do_reply_char(ret, "");
      return;
      }

   if ((subsubfield_out = (char *)malloc(ssf_size + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[subsubfield_out]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   ret = db_get_subsubfield(tid, fnum, sfnum, ssfnum, subsubfield_out);
   (void)do_reply_char(ret, subsubfield_out);
   free(subsubfield_out);
   db_io_code_log(mname, "normal exit", ret);
}

void c_goto(char *comm)
{
   /* Goto a specific record in the table. The table tid is expected on
      the command line along with a record number. Function replies with
      a DBENG io code. Syntax:

         tid record_number */

   char *tid_char;
   char *rnum_char;
   char mname[25];
   long rnum;
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_goto");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);

   if (words(comm) < 2)
      {
      db_io_code_log(mname, "missing record number", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);

   if ((rnum_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[rnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, rnum_char, 2);
      
   if (!qatol(rnum_char, &rnum))
      {
      db_io_code_log(mname, "non numeric record number",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(rnum_char);
      return;
      }

   if (rnum <= 0L)
      {
      db_io_code_log(mname, "record number out of range",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(rnum_char);
      return;
      }

   free(rnum_char);
   ret = db_goto(tid, rnum);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_put_field(char *comm)
{
   /* Put data into a field. The tid, field number and field
      contents are expected on the command line. Function replies
      with a DBENG io code. Syntax:

      tid field_number 'field data'

      Note that if the field data contains spaces, it is assumed that
      the entire field contents will be surrounded by matching either
      single or double quotes. */

   char *tid_char;
   char *fnum_char;
   char *field_data;
   char mname[25];
   int nwords;
   int fnum;
   int tid;
   int len;
   int ret;

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

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);
   nwords = command_words(comm);

   if (nwords < 2)
      {
      db_io_code_log(mname, "missing field number", DBENG_NO_SUCH_FIELD);
      (void)do_reply_code(DBENG_NO_SUCH_FIELD);
      return;
      }

   if (nwords < 3)
      {
      db_io_code_log(mname, "missing field data", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);

   if ((fnum_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[fnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, fnum_char, 2);
      
   if (!qatoi(fnum_char, &fnum))
      {
      db_io_code_log(mname, "non numeric field number",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(fnum_char);
      return;
      }

   if (fnum < 0)
      {
      db_io_code_log(mname, "field number out of range",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(fnum_char);
      return;
      }

   free(fnum_char);

   if ((field_data = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[field_data]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, field_data, 3);
   ret = db_put_field(tid, fnum, field_data);
   free(field_data);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_put_subfield(char *comm)
{
   /* Put data into a sub-field. The tid, field number, sub-field
      number and field contents are expected on the command line. 
      Function replies with a DBENG io code. Syntax:

      tid field_number sub-field_number 'field data'

      Note that if the sub-field data contains spaces, it is assumed that
      the entire contents will be surrounded by matching either
      single or double quotes. */

   char *tid_char, *fnum_char, *sfnum_char, *sf_data;
   char mname[] = "c_put_subfield";
   int nwords, fnum, sfnum, tid, len, ret;

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

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);
   nwords = command_words(comm);

   if (nwords < 2)
      {
      db_io_code_log(mname, "missing field number", DBENG_NO_SUCH_FIELD);
      (void)do_reply_code(DBENG_NO_SUCH_FIELD);
      return;
      }

   if (nwords < 3)
      {
      db_io_code_log(mname, "missing sub-field number", 
                     DBENG_NO_SUCH_SUBFIELD);
      (void)do_reply_code(DBENG_NO_SUCH_SUBFIELD);
      return;
      }

   if (nwords < 4)
      {
      db_io_code_log(mname, "missing sub-field data", 
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if ((tid_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);

   if ((fnum_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[fnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, fnum_char, 2);
      
   if (!qatoi(fnum_char, &fnum))
      {
      db_io_code_log(mname, "non numeric field number",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(fnum_char);
      return;
      }

   if (fnum < 0)
      {
      db_io_code_log(mname, "field number out of range",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(fnum_char);
      return;
      }

   free(fnum_char);

   if ((sfnum_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[sfnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, sfnum_char, 3);
      
   if (!qatoi(sfnum_char, &sfnum))
      {
      db_io_code_log(mname, "non numeric sub-field number",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(sfnum_char);
      return;
      }

   if (sfnum < 0)
      {
      db_io_code_log(mname, "sub-field number out of range",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(sfnum_char);
      return;
      }

   free(sfnum_char);

   if ((sf_data = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[sf_data]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, sf_data, 4);
   ret = db_put_subfield(tid, fnum, sfnum, sf_data);
   free(sf_data);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_put_subsubfield(char *comm)
{
   /* Put data into a sub-sub-field. The tid, field number, sub-field
      number, sub-sub-field number and field contents are expected on the 
      command line. Function replies with a DBENG io code. Syntax:

      tid field_number sub-field_number sub-sub-field_number 'field data'

      Note that if the sub-sub-field data contains spaces, it is assumed that
      the entire contents will be surrounded by matching either
      single or double quotes. */

   char *tid_char, *fnum_char, *sfnum_char, *ssfnum_char, *ssf_data;
   char mname[] = "c_put_subsubfield";
   int nwords, fnum, sfnum, ssfnum, tid, len, ret;

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

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);
   nwords = command_words(comm);

   if (nwords < 2)
      {
      db_io_code_log(mname, "missing field number", DBENG_NO_SUCH_FIELD);
      (void)do_reply_code(DBENG_NO_SUCH_FIELD);
      return;
      }

   if (nwords < 3)
      {
      db_io_code_log(mname, "missing sub-field number", 
                     DBENG_NO_SUCH_SUBFIELD);
      (void)do_reply_code(DBENG_NO_SUCH_SUBFIELD);
      return;
      }

   if (nwords < 4)
      {
      db_io_code_log(mname, "missing sub-sub-field number", 
                     DBENG_NO_SUCH_SUBSUBFIELD);
      (void)do_reply_code(DBENG_NO_SUCH_SUBSUBFIELD);
      return;
      }

   if (nwords < 5)
      {
      db_io_code_log(mname, "missing sub-sub-field data", 
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if ((tid_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);

   if ((fnum_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[fnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, fnum_char, 2);
      
   if (!qatoi(fnum_char, &fnum))
      {
      db_io_code_log(mname, "non numeric field number",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(fnum_char);
      return;
      }

   if (fnum < 0)
      {
      db_io_code_log(mname, "field number out of range",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(fnum_char);
      return;
      }

   free(fnum_char);

   if ((sfnum_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[sfnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, sfnum_char, 3);
      
   if (!qatoi(sfnum_char, &sfnum))
      {
      db_io_code_log(mname, "non numeric sub-field number",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(sfnum_char);
      return;
      }

   if (sfnum < 0)
      {
      db_io_code_log(mname, "sub-field number out of range",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(sfnum_char);
      return;
      }

   free(sfnum_char);

   if ((ssfnum_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[ssfnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, ssfnum_char, 4);
      
   if (!qatoi(ssfnum_char, &ssfnum))
      {
      db_io_code_log(mname, "non numeric sub-sub-field number",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(ssfnum_char);
      return;
      }

   if (ssfnum < 0)
      {
      db_io_code_log(mname, "sub-sub-field number out of range",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(ssfnum_char);
      return;
      }

   free(ssfnum_char);

   if ((ssf_data = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[ssf_data]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, ssf_data, 5);
   ret = db_put_subsubfield(tid, fnum, sfnum, ssfnum, ssf_data);
   free(ssf_data);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_nfields(char *comm)
{
   /* Get the number of fields in the current record. The table tid
      is expected on the command line. Function replies with a DBENG
      io code. Syntax:

         tid */

   char *tid_char;
   char mname[25];
   int nfields;
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_get_nfields");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   free(tid_char);
   ret = db_get_nfields(tid, &nfields);
   (void)do_reply_int(ret, nfields);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_nsubfields(char *comm)
{
   /* Get the number of sub-fields in a field. The table tid is expected on
      the command line along with a field number. Function replies with
      a DBENG io code. Syntax:

         tid field_number */

   char *tid_char, *fnum_char, mname[] = "c_get_nsubfields";
   int tid, fnum, len, ret, nsubfields;
  
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   len = strlen(comm);

   if (words(comm) < 2)
      {
      db_io_code_log(mname, "missing field number", DBENG_INVALID_FUNCTION);
      (void)do_reply_int(DBENG_INVALID_FUNCTION, 0);
      return;
      }

   if ((tid_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   free(tid_char);

   if ((fnum_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[fnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, fnum_char, 2);
      
   if (!qatoi(fnum_char, &fnum))
      {
      db_io_code_log(mname, "non numeric field number",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_int(DBENG_INVALID_FUNCTION, 0);
      free(fnum_char);
      return;
      }

   if (fnum <= 0L)
      {
      db_io_code_log(mname, "field number out of range",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_int(DBENG_INVALID_FUNCTION, 0);
      free(fnum_char);
      return;
      }

   free(fnum_char);
   ret = db_get_nsubfields(tid, fnum, &nsubfields);
   (void)do_reply_int(ret, nsubfields);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_nsubsubfields(char *comm)
{
   /* Get the number of sub-sub-fields in a sub-field. The table tid is 
      expected on the command line along with a field number and
      sub-field number. Function replies with a DBENG io code. Syntax:

         tid field_number sub-field_number */

   char *tid_char, *fnum_char, *sfnum_char, mname[] = "c_get_nsubsubfields";
   int nwords, tid, fnum, sfnum, len, ret, nsubsubfields;
  
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   len = strlen(comm);
   nwords = words(comm);

   if (nwords < 2)
      {
      db_io_code_log(mname, "missing field number", DBENG_INVALID_FUNCTION);
      (void)do_reply_int(DBENG_INVALID_FUNCTION, 0);
      return;
      }

   if (nwords < 3)
      {
      db_io_code_log(mname, "missing sub-field number", DBENG_INVALID_FUNCTION);
      (void)do_reply_int(DBENG_INVALID_FUNCTION, 0);
      return;
      }

   if ((tid_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   free(tid_char);

   if ((fnum_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[fnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, fnum_char, 2);
      
   if (!qatoi(fnum_char, &fnum))
      {
      db_io_code_log(mname, "non numeric field number",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_int(DBENG_INVALID_FUNCTION, 0);
      free(fnum_char);
      return;
      }

   if (fnum <= 0L)
      {
      db_io_code_log(mname, "field number out of range",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_int(DBENG_INVALID_FUNCTION, 0);
      free(fnum_char);
      return;
      }

   free(fnum_char);

   if ((sfnum_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[sfnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, sfnum_char, 3);
      
   if (!qatoi(sfnum_char, &sfnum))
      {
      db_io_code_log(mname, "non numeric sub-field number",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_int(DBENG_INVALID_FUNCTION, 0);
      free(sfnum_char);
      return;
      }

   if (sfnum <= 0L)
      {
      db_io_code_log(mname, "sub-field number out of range",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_int(DBENG_INVALID_FUNCTION, 0);
      free(sfnum_char);
      return;
      }

   free(sfnum_char);
   ret = db_get_nsubsubfields(tid, fnum, sfnum, &nsubsubfields);
   (void)do_reply_int(ret, nsubsubfields);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_rec_num(char *comm)
{
   /* Get current record number. The table tid is expected on the command
      line. Function replies with a DBENG io code. Syntax:

         tid */

   char *tid_char;
   char mname[25];
   long rec_num;
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_get_rec_num");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_long(DBENG_NO_SUCH_TID, 0L);
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_long(DBENG_MEMORY_FAIL, 0L);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_long(DBENG_NO_SUCH_TID, 0L);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_long(DBENG_NO_SUCH_TID, 0L);
      return;
      }

   free(tid_char);
   ret = db_get_rec_num(tid, &rec_num);
   (void)do_reply_long(ret, rec_num);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_delete_flag(char *comm)
{
   /* Get the table 'process_deleted' flag. The table tid
      is expected on the command line. Function replies with a DBENG io
      code. Syntax:

         tid */

   char *tid_char;
   char mname[25];
   int flag_value;
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_get_delete_flag");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   free(tid_char);
   ret = db_get_delete_flag(tid, &flag_value);
   (void)do_reply_int(ret, flag_value);
   db_io_code_log(mname, "normal exit", ret);
}

void c_set_delete_flag(char *comm)
{
   /* Set the table 'process_deleted' flag. The table tid is expected on
      the command line along with the flag value. Function replies with
      a DBENG io code. Note that 'flag_value' must be '0' or '1'. Syntax:

         tid flag_value */

   char *tid_char;
   char *flag_char;
   char mname[25];
   int flag;
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_set_delete_flag");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);

   if (words(comm) < 2)
      {
      db_io_code_log(mname, "missing flag value", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);

   if ((flag_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[flag_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, flag_char, 2);
      
   if (!qatoi(flag_char, &flag))
      {
      db_io_code_log(mname, "non numeric flag value", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(flag_char);
      return;
      }

   if (flag != 0 && flag != 1)
      {
      db_io_code_log(mname, "flag value must be 0 or 1",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(flag_char);
      return;
      }

   free(flag_char);
   ret = db_set_delete_flag(tid, flag);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_count(char *comm)
{
   /* Physically count the number of records in a table. The table tid
      is expected on the command line. Function replies with a DBENG io
      code and two long int's (the active record count and the
      deleted record count. Syntax:

         tid */

   char *tid_char;
   char mname[] = "c_count", buf[128];
   long active_count, deleted_count;
   int tid;
   int len;
   int ret;
  
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_long(DBENG_NO_SUCH_TID, 0L);
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_long(DBENG_MEMORY_FAIL, 0L);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_long(DBENG_NO_SUCH_TID, 0L);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_long(DBENG_NO_SUCH_TID, 0L);
      return;
      }

   free(tid_char);
   ret = db_count(tid, &active_count, &deleted_count);
   sprintf(buf, "%ld %ld", active_count, deleted_count);
   (void)do_reply_char(ret, buf);
   db_io_code_log(mname, "normal exit", ret);
}

void c_write(char *comm)
{
   /* Write the current record. The table tid is expected on the
      command line. Function replies with a DBENG io code. Syntax:

         tid */

   char *tid_char;
   char mname[25];
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_write");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);
   ret = db_write(tid);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_delete(char *comm)
{
   /* Delete the current record. The table tid is expected on the
      command line. Function replies with a DBENG io code. Syntax:

         tid */

   char *tid_char;
   char mname[25];
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_delete");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);
   ret = db_delete(tid);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_pack(char *comm)
{
   /* Pack a table by removing all deleted records. The table tid is
      expected on the command line. Function replies with a DBENG io
      code. Syntax:

         tid */

   char *tid_char;
   char mname[25];
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_pack");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);
   ret = db_pack(tid);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_find(char *comm)
{
   /* Find matching field data. All whole fields will be searched. String
      comparison sensitivity is based on 'cs_flag' ('0' for case
      sensitivity, '1' for case insensitivity). Search will begin
      with current record and continue until a match is found or
      EOF. The tid, case sensitivity flag and search field data
      contents are expected on the command line. Function replies
      with a DBENG io code. Syntax:

      tid 'search field data' cs_flag

      Note that if the search field data contains spaces, it is assumed that
      the entire field contents will be surrounded by matching either
      single or double quotes. */

   char *tid_char;
   char *cs_char;
   char *field_data;
   char mname[25];
   int field_num;
   int nwords;
   int cs_flag;
   int tid;
   int len;
   int ret;

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

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   len = strlen(comm);
   nwords = command_words(comm);

   if (nwords < 2)
      {
      db_io_code_log(mname, "missing search data", DBENG_INVALID_FUNCTION);
      (void)do_reply_int(DBENG_INVALID_FUNCTION, 0);
      return;
      }

   if (nwords < 3)
      {
      db_io_code_log(mname, "missing case flag", DBENG_INVALID_FUNCTION);
      (void)do_reply_int(DBENG_INVALID_FUNCTION, 0);
      return;
      }

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)command_word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   free(tid_char);

   if ((cs_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[cs_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)command_word(comm, cs_char, 3);
      
   if (!qatoi(cs_char, &cs_flag))
      {
      db_io_code_log(mname, "non numeric case flag",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_int(DBENG_INVALID_FUNCTION, 0);
      free(cs_char);
      return;
      }

   if (cs_flag != TRUE && cs_flag != FALSE)
      {
      db_io_code_log(mname, "case flag must be 0 or 1",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_int(DBENG_INVALID_FUNCTION, 0);
      free(cs_char);
      return;
      }

   free(cs_char);

   if ((field_data = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[field_data]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)command_word(comm, field_data, 2);
   ret = db_find(tid, cs_flag, field_data, &field_num);
   free(field_data);
   (void)do_reply_int(ret, field_num);
   db_io_code_log(mname, "normal exit", ret);
}

void c_find_field(char *comm)
{
   /* Find matching field data. Only a specific whole field in
      each record will be searched. String comparison sensitivity
      is based on 'cs_flag' ('0' for case sensitivity, '1' for case
      insensitivity). Search will begin with current record and continue
      until a match is found or EOF. The tid, case sensitivity flag and
      search field data contents are expected on the command line.
      Function replies with a DBENG io code. Syntax:

      tid field_num 'search field data' cs_flag

      Note that if the search field data contains spaces, it is assumed that
      the entire field contents will be surrounded by matching either
      single or double quotes. */

   char *tid_char;
   char *cs_char;
   char *field_data;
   char *fnum_char;
   char mname[25];
   int fnum;
   int nwords;
   int cs_flag;
   int tid;
   int len;
   int ret;

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

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);
   nwords = command_words(comm);

   if (nwords < 2)
      {
      db_io_code_log(mname, "missing field number", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if (nwords < 3)
      {
      db_io_code_log(mname, "missing search data", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if (nwords < 4)
      {
      db_io_code_log(mname, "missing case flag", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }
 
   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);

   if ((fnum_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[fnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, fnum_char, 2);
      
   if (!qatoi(fnum_char, &fnum))
      {
      db_io_code_log(mname, "non numeric field number",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(fnum_char);
      return;
      }

   if (fnum <= 0)
      {
      db_io_code_log(mname, "out of range field number",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(fnum_char);
      return;
      }

   free(fnum_char);

   if ((cs_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[cs_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, cs_char, 4);
      
   if (!qatoi(cs_char, &cs_flag))
      {
      db_io_code_log(mname, "non numeric case flag",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(cs_char);
      return;
      }

   if (cs_flag != TRUE && cs_flag != FALSE)
      {
      db_io_code_log(mname, "case flag must be 0 or 1",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(cs_char);
      return;
      }

   free(cs_char);

   if ((field_data = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[field_data]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, field_data, 3);
   ret = db_find_field(tid, cs_flag, field_data, fnum);
   free(field_data);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_find_part(char *comm)
{
   /* Find matching field data. Any part of a field will match. String
      comparison sensitivity is based on 'cs_flag' ('0' for case
      sensitivity, '1' for case insensitivity). Search will begin
      with current record and continue until a match is found or
      EOF. The tid, case sensitivity flag and search field data
      contents are expected on the command line. Function replies
      with a DBENG io code. Syntax:

      tid 'search field data' cs_flag

      Note that if the search field data contains spaces, it is assumed that
      the entire field contents will be surrounded by matching either
      single or double quotes. */

   char *tid_char;
   char *cs_char;
   char *field_data;
   char mname[25];
   int field_num;
   int nwords;
   int cs_flag;
   int tid;
   int len;
   int ret;

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

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   len = strlen(comm);
   nwords = command_words(comm);

   if (nwords < 2)
      {
      db_io_code_log(mname, "missing search data", DBENG_INVALID_FUNCTION);
      (void)do_reply_int(DBENG_INVALID_FUNCTION, 0);
      return;
      }

   if (nwords < 3)
      {
      db_io_code_log(mname, "missing case flag", DBENG_INVALID_FUNCTION);
      (void)do_reply_int(DBENG_INVALID_FUNCTION, 0);
      return;
      }

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)command_word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   free(tid_char);

   if ((cs_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[cs_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)command_word(comm, cs_char, 3);
      
   if (!qatoi(cs_char, &cs_flag))
      {
      db_io_code_log(mname, "non numeric case flag",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_int(DBENG_INVALID_FUNCTION, 0);
      free(cs_char);
      return;
      }

   if (cs_flag != TRUE && cs_flag != FALSE)
      {
      db_io_code_log(mname, "case flag must be 0 or 1",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_int(DBENG_INVALID_FUNCTION, 0);
      free(cs_char);
      return;
      }

   free(cs_char);

   if ((field_data = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[field_data]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)command_word(comm, field_data, 2);
   ret = db_find_part(tid, cs_flag, field_data, &field_num);
   free(field_data);
   (void)do_reply_int(ret, field_num);
   db_io_code_log(mname, "normal exit", ret);
}

void c_find_field_part(char *comm)
{
   /* Find matching field data. Any part of the specific requested field in
      each record will match. String comparison sensitivity
      is based on 'cs_flag' ('0' for case sensitivity, '1' for case
      insensitivity). Search will begin with current record and continue
      until a match is found or EOF. The tid, case sensitivity flag and
      search field data contents are expected on the command line.
      Function replies with a DBENG io code. Syntax:

      tid field_num 'search field data' cs_flag

      Note that if the search field data contains spaces, it is assumed that
      the entire field contents will be surrounded by matching either
      single or double quotes. */

   char *tid_char;
   char *cs_char;
   char *field_data;
   char *fnum_char;
   char mname[25];
   int fnum;
   int nwords;
   int cs_flag;
   int tid;
   int len;
   int ret;

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

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);
   nwords = command_words(comm);

   if (nwords < 2)
      {
      db_io_code_log(mname, "missing field number", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if (nwords < 3)
      {
      db_io_code_log(mname, "missing search data", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if (nwords < 4)
      {
      db_io_code_log(mname, "missing case flag", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }
 
   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);

   if ((fnum_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[fnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, fnum_char, 2);
      
   if (!qatoi(fnum_char, &fnum))
      {
      db_io_code_log(mname, "non numeric field number",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(fnum_char);
      return;
      }

   if (fnum <= 0)
      {
      db_io_code_log(mname, "out of range field number",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(fnum_char);
      return;
      }

   free(fnum_char);

   if ((cs_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[cs_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, cs_char, 4);
      
   if (!qatoi(cs_char, &cs_flag))
      {
      db_io_code_log(mname, "non numeric case flag",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(cs_char);
      return;
      }

   if (cs_flag != TRUE && cs_flag != FALSE)
      {
      db_io_code_log(mname, "case flag must be 0 or 1",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(cs_char);
      return;
      }

   free(cs_char);

   if ((field_data = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[field_data]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, field_data, 3);
   ret = db_find_field_part(tid, cs_flag, field_data, fnum);
   free(field_data);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_pos(char *comm)
{
   /* Get the file pointer position of the current record. The table tid
      is expected on the command line. Function replies with a DBENG io
      code. Syntax:

         tid */

   char *tid_char;
   char mname[25];
   long pos;
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_get_pos");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_long(DBENG_NO_SUCH_TID, 0L);
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_long(DBENG_MEMORY_FAIL, 0L);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_long(DBENG_NO_SUCH_TID, 0L);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_long(DBENG_NO_SUCH_TID, 0L);
      return;
      }

   free(tid_char);
   ret = db_get_pos(tid, &pos);
   (void)do_reply_long(ret, pos);
   db_io_code_log(mname, "normal exit", ret);
}

void c_set_pos(char *comm)
{
   /* Set the the table 'orig_position'. 'fpos' must be zero or a positive
      integer. The table tid is expected on the command line.
      Function replies with a DBENG io code. Syntax:

         tid fpos */

   char *tid_char;
   char *fpos_char;
   char mname[25];
   long fpos;
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_set_pos");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);

   if (words(comm) < 2)
      {
      db_io_code_log(mname, "missing file position", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);

   if ((fpos_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[fpos_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, fpos_char, 2);
      
   if (!qatol(fpos_char, &fpos))
      {
      free(fpos_char);
      db_io_code_log(mname, "non numeric[fpos]", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if (fpos < 0L)
      {   
      free(fpos_char);
      db_io_code_log(mname, "out of range[fpos]", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   free(fpos_char);
   ret = db_set_pos(tid, fpos);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_sort(char *comm)
{
   /* Sort an already open table. Function replies with a DBENG code.
      code. Syntax:

         tid sort_specs

      See function 'dbeng_sort' in the module 'dbengsrt.c' for an
      explaination of the 'sort_specs'. */

   char *tid_char, *specs;
   char mname[] = "c_sort";
   long pos;
   int tid;
   int len;
   int ret;
  
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);

   if (words(comm) < 2)
      {
      db_io_code_log(mname, "missing sort spec(s)", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);

   if ((specs = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[spec_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, specs, 2);
   ret = db_sort(tid, specs);
   free(specs);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_sort_mem(char *comm)
{
   /* Get the allowable sort memory. The table tid
      is expected on the command line. Function replies with a DBENG io
      code. Syntax:

         tid */

   char *tid_char;
   char mname[] = "c_get_sort_mem";
   long mem;
   int tid;
   int len;
   int ret;
  
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_long(DBENG_NO_SUCH_TID, 0L);
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_long(DBENG_MEMORY_FAIL, 0L);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_long(DBENG_NO_SUCH_TID, 0L);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_long(DBENG_NO_SUCH_TID, 0L);
      return;
      }

   free(tid_char);
   ret = db_get_sort_max_mem(tid, &mem);
   (void)do_reply_long(ret, mem);
   db_io_code_log(mname, "normal exit", ret);
}

void c_set_sort_mem(char *comm)
{
   /* Set the the table 'sort_max_mem'. 'mem' must be a positive
      long integer. The table tid is expected on the command line.
      Function replies with a DBENG io code. Syntax:

         tid mem */

   char *tid_char;
   char *mem_char;
   char mname[] = "c_set_sort_mem";
   long mem;
   int tid;
   int len;
   int ret;
  
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);

   if (words(comm) < 2)
      {
      db_io_code_log(mname, "missing sort memory amount", 
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);

   if ((mem_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[mem_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, mem_char, 2);
      
   if (!qatol(mem_char, &mem))
      {
      free(mem_char);
      db_io_code_log(mname, "non numeric[mem]", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if (mem <= 0L)
      {   
      free(mem_char);
      db_io_code_log(mname, "out of range[mem]", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   free(mem_char);
   ret = db_set_sort_max_mem(tid, mem);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_sort_open_bin(char *comm)
{
   /* Get the allowable number of sort open bin tables. The table tid
      is expected on the command line. Function replies with a DBENG io
      code. Syntax:

         tid */

   char *tid_char;
   char mname[] = "c_get_sort_open_bin";
   int open_bin;
   int tid;
   int len;
   int ret;
  
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   free(tid_char);
   ret = db_get_sort_max_open_bin(tid, &open_bin);
   (void)do_reply_int(ret, open_bin);
   db_io_code_log(mname, "normal exit", ret);
}

void c_set_sort_open_bin(char *comm)
{
   /* Set the the table 'sort_max_open_bin'. 'open_bin' must be a positive
      integer. The table tid is expected on the command line.
      Function replies with a DBENG io code. Syntax:

         tid open_bin */

   char *tid_char;
   char *open_bin_char;
   char mname[] = "c_set_sort_open_bin";
   int open_bin;
   int tid;
   int len;
   int ret;
  
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);

   if (words(comm) < 2)
      {
      db_io_code_log(mname, "missing sort number of open bin tables", 
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);

   if ((open_bin_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[open_bin_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, open_bin_char, 2);
      
   if (!qatoi(open_bin_char, &open_bin))
      {
      free(open_bin_char);
      db_io_code_log(mname, "non numeric[open_bin]", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if (open_bin <= 0)
      {   
      free(open_bin_char);
      db_io_code_log(mname, "out of range[open_bin]", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   free(open_bin_char);
   ret = db_set_sort_max_open_bin(tid, open_bin);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_change_rec_flag(char *comm)
{
   /* Get the the table 'change_rec_flag'. The table tid
      is expected on the command line. Function replies with a DBENG io
      code. Syntax:

         tid */

   char *tid_char;
   char mname[25];
   int flag;
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_get_change_rec_flag");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   free(tid_char);
   ret = db_get_change_rec_flag(tid, &flag);
   (void)do_reply_int(ret, flag);
   db_io_code_log(mname, "normal exit", ret);
}

void c_set_change_rec_flag(char *comm)
{
   /* Set the the table 'change_rec_flag'. 'flag_value' must be either
      '0' or '1'. The table tid is expected on the command line.
      Function replies with a DBENG io code. Syntax:

         tid flag_value */

   char *tid_char;
   char *flag_char;
   char mname[25];
   int flag;
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_set_change_rec_flag");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);

   if (words(comm) < 2)
      {
      db_io_code_log(mname, "missing flag value", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);

   if ((flag_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[flag_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, flag_char, 2);
      
   if (!qatoi(flag_char, &flag))
      {
      free(flag_char);
      db_io_code_log(mname, "non numeric flag value", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if (flag != TRUE && flag != FALSE)
      {
      free(flag_char);
      db_io_code_log(mname, "flag value out of range", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   free(flag_char);
   ret = db_set_change_rec_flag(tid, flag);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_autopack(char *comm)
{
   /* Get the the table 'autopack' value. The table tid
      is expected on the command line. Function replies with a DBENG io
      code along with the value upon success. Syntax:

         tid */

   char *tid_char;
   char mname[] = "c_get_autopack";
   int pval;
   int tid;
   int len;
   int ret;
  
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   free(tid_char);
   ret = db_get_autopack(tid, &pval);
   (void)do_reply_int(ret, pval);
   db_io_code_log(mname, "normal exit", ret);
}

void c_set_autopack(char *comm)
{
   /* Set the the table 'autopack' value. 
      The table tid is expected on the command line.
      Function replies with a DBENG io code. Syntax:

         tid autopack_value */

   char *tid_char;
   char *autopack_char;
   char mname[] = "c_set_autopack";
   int pval;
   int tid;
   int len;
   int ret;
  
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);

   if (words(comm) < 2)
      {
      db_io_code_log(mname, "missing autopack value", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);

   if ((autopack_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[autopack_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, autopack_char, 2);
      
   if (!qatoi(autopack_char, &pval))
      {
      free(autopack_char);
      db_io_code_log(mname, "non numeric autopack value", 
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if (pval < 0)
      {
      free(autopack_char);
      db_io_code_log(mname, "autopack value out of range", 
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   free(autopack_char);
   ret = db_set_autopack(tid, pval);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_new(char *comm)
{
   /* Declare a new database record. The table tid is expected on
      the command line.Function replies with a DBENG io code. Syntax:

         tid */

   char *tid_char;
   char mname[25];
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_new");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);
   ret = db_new(tid);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_rec_count(char *comm)
{
   /* Get the current record count. Note that the records are not
      actually counted, the table record counts are returned. The table tid
      is expected on the command line. Function replies with a DBENG io
      code. Syntax:

         tid */

   char *tid_char;
   char mname[] = "c_get_rec_count", buf[128];
   long active_count, deleted_count;
   int tid;
   int len;
   int ret;
  
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_long(DBENG_NO_SUCH_TID, 0L);
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_long(DBENG_MEMORY_FAIL, 0L);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_long(DBENG_NO_SUCH_TID, 0L);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_long(DBENG_NO_SUCH_TID, 0L);
      return;
      }

   free(tid_char);
   ret = db_get_rec_count(tid, &active_count, &deleted_count);

   // reply with both the active and deleted record counts

   sprintf(buf, "%ld %ld", active_count, deleted_count);
   (void)do_reply_char(ret, buf);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_enf_change_rec_flag(char *comm)
{
   /* Get the the table 'enforce_change_rec_flag'. The table tid
      is expected on the command line. Function replies with a DBENG io
      code. Syntax:

         tid */

   char *tid_char;
   char mname[30];
   int flag;
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_get_enf_change_rec_flag");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   free(tid_char);
   ret = db_get_enf_change_rec_flag(tid, &flag);
   (void)do_reply_int(ret, flag);
   db_io_code_log(mname, "normal exit", ret);
}

void c_set_enf_change_rec_flag(char *comm)
{
   /* Set the the table 'enforce_change_rec_flag'. 'flag_value' must
      be either '0' or '1'. The table tid and flag value are expected
      on the command line. Function replies with a DBENG io code. Syntax:

         tid flag_value */

   char *tid_char;
   char *flag_char;
   char mname[30];
   int flag;
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_set_enf_change_rec_flag");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);

   if (words(comm) < 2)
      {
      db_io_code_log(mname, "missing flag value", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);

   if ((flag_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[flag_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, flag_char, 2);
      
   if (!qatoi(flag_char, &flag))
      {
      free(flag_char);
      db_io_code_log(mname, "non numeric flag value", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if (flag != TRUE && flag != FALSE)
      {
      free(flag_char);
      db_io_code_log(mname, "flag value out of range", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   free(flag_char);
   ret = db_set_enf_change_rec_flag(tid, flag);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_is_table_locked(char *comm)
{
   /* Get the the table 'is_table_locked' flag. The table tid
      is expected on the command line. Function replies with a DBENG io
      code. Syntax:

         tid */

   char *tid_char;
   char mname[25];
   int flag;
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_get_is_table_locked");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_int(DBENG_NO_SUCH_TID, 0);
      return;
      }

   free(tid_char);
   ret = db_get_is_table_locked(tid, &flag);
   (void)do_reply_int(ret, flag);
   db_io_code_log(mname, "normal exit", ret);
}

void c_set_is_table_locked(char *comm)
{
   /* Set the the table 'is_table_locked' flag. 'flag_value' must
      be either '0' or '1'. The table tid and flag value are expected
      on the command line. Function replies with a DBENG io code. Syntax:

         tid flag_value */

   char *tid_char;
   char *flag_char;
   char mname[25];
   int flag;
   int tid;
   int len;
   int ret;
  
   strcpy(mname, "c_set_is_table_locked");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);

   if (words(comm) < 2)
      {
      db_io_code_log(mname, "missing flag value", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);

   if ((flag_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[flag_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, flag_char, 2);
      
   if (!qatoi(flag_char, &flag))
      {
      free(flag_char);
      db_io_code_log(mname, "non numeric flag value", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if (flag != TRUE && flag != FALSE)
      {
      free(flag_char);
      db_io_code_log(mname, "flag value out of range", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   free(flag_char);
   ret = db_set_is_table_locked(tid, flag);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_new_table(char *comm)
{
   /* Create a new table. The file name is expected on the command line
      along with an 'open flag' which a positive number means open
      the table after creation. Function replies with 'DBENG_OK'
      with the open table TID (if requested) upon success,
      an engine i/o code otherwise. Syntax:

         file_name open_flag */

   char mname[25], *filename, *tid_char;
   int tid = 0;
   int ret, len, driret;
  
   strcpy(mname, "c_new_table");
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_INVALID_FILE_NAME);
      (void)do_reply_int(DBENG_INVALID_FILE_NAME, tid);
      return;
      }

   if (command_words(comm) < 2)
      {
      db_io_code_log(mname, "missing flag value", DBENG_INVALID_FUNCTION);
      (void)do_reply_int(DBENG_INVALID_FUNCTION, tid);
      return;
      }

   len = strlen(comm);

   if ((filename = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[filename]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }
      
   (void)command_word(comm, filename, 1);
   
   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      free(filename);
      return;
      }

   (void)command_word(comm, tid_char, 2);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      free(filename);
      db_io_code_log(mname, "non numeric tid flag", DBENG_INVALID_FUNCTION);
      (void)do_reply_int(DBENG_INVALID_FUNCTION, 0);
      return;
      }

   /* zero tid flag is ok and signifies no open after create */
   
   if (tid < 0)
      {
      free(tid_char);
      free(filename);
      db_io_code_log(mname, "tid out of range", DBENG_INVALID_FUNCTION);
      (void)do_reply_int(DBENG_INVALID_FUNCTION, 0);
      return;
      }

   free(tid_char);
   ret = db_new_table(filename, &tid);
   free(filename);
   
   if ((driret = do_reply_int(ret, tid)) != DBENG_OK)
      {
      logman("%s:bad ret from do_reply_int:rc=%d", mname, driret);
      return;
      }
            
   db_io_code_log(mname, "normal exit", ret);
}

void c_config_get_tmp_path(void)
{
   /* Get the engine temporary path. Function replies with a DBENG i/o
      code. Syntax:

      */

   char *tmp_path;
   char mname[25];
   int ret;
  
   strcpy(mname, "c_config_get_tmp_path");
   logman("%s:enter", mname);

   if ((tmp_path = (char *)malloc(DBENG_PATH_LIMIT)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tmp_path]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   ret = db_config_get_tmp_path(tmp_path);
   (void)do_reply_char(ret, tmp_path);
   free(tmp_path);
   db_io_code_log(mname, "normal exit", ret);
}

void c_config_get_log(void)
{
   /* Get the engine log file name. Function replies with a DBENG i/o
      code and the log file name upon success. Syntax:

      */

   char *slog;
   char mname[25];
   int ret;
  
   strcpy(mname, "c_config_get_log");
   logman("%s:enter", mname);

   if ((slog = (char *)malloc(DBENG_PATH_LIMIT)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[slog]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   if ((ret = db_config_get_log(slog)) != DBENG_OK)
      {
      free(slog);
      db_io_code_log(mname, "bad rc from db_config_get_log", ret);
      (void)do_reply_char(ret, "");
      return;
      }

   if (!strcmp(slog, SYS_LOG_SERVICE_NAME))
      sprintf(slog, "system logger(%s)", SYS_LOG_SERVICE_NAME);

   (void)do_reply_char(ret, slog);
   free(slog);
   db_io_code_log(mname, "normal exit", ret);
}

void c_log_status(void)
{
   /* Get the status of the log including the flag value and the
      log name. */
      
   char mname[] = "c_log_status";
   char *reply, *slog;
   int len, flag;
   
   logman("%s:enter", mname);
   (void)db_config_get_log_flag(&flag);

   if ((slog = (char *)malloc(DBENG_PATH_LIMIT)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[slog]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   (void)db_config_get_log(slog);
   len = strlen(slog);

   if ((reply = (char *)malloc(len + 3)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[reply]", DBENG_MEMORY_FAIL);
      free(slog);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   sprintf(reply, "%d %s", flag, slog);
   free(slog);
   (void)do_reply_char(DBENG_OK, reply);
   free(reply);
   db_io_code_log(mname, "normal exit", DBENG_OK);
}
   
void c_config_get_session(void)
{
   /* Get the engine session table path/file name. Function
      replies with a DBENG i/o code. Syntax:
      */

   char *ses_table;
   char mname[30];
   int ret;
  
   strcpy(mname, "c_config_get_session");
   logman("%s:enter", mname);

   if ((ses_table = (char *)malloc(DBENG_PATH_LIMIT)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[ses_table]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   ret = db_config_get_session(ses_table);   
   (void)do_reply_char(ret, ses_table);
   free(ses_table);
   db_io_code_log(mname, "normal exit", ret);
}

void c_config_get_catalog(void)
{
   /* Get the engine catalog path/file name. Function
      replies with a DBENG i/o code. Syntax:
      */

   char *cat;
   char mname[25];
   int ret;
  
   strcpy(mname, "c_config_get_catalog");
   logman("%s:enter", mname);

   if ((cat = (char *)malloc(DBENG_PATH_LIMIT)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[cat]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   ret = db_config_get_catalog(cat);   
   (void)do_reply_char(ret, cat);
   free(cat);
   db_io_code_log(mname, "normal exit", ret);
}

void c_config_get_log_flag(void)
{
   /* Get the engine log flag. Function replies with a
      'dbeng' i/o code */
      
   char mname[] = "c_config_get_log_flag";
   int ret, flag;
   
   logman("%s:enter", mname);
   ret = db_config_get_log_flag(&flag);
   (void)do_reply_int(ret, flag);
   db_io_code_log(mname, "normal exit", ret);
}

void c_config_get_session_flag(void)
{
   /* Get the engine session flag. Function replies with a
      'dbeng' i/o code */
      
   char mname[] = "c_config_get_session_flag";
   int ret, flag;
   
   logman("%s:enter", mname);
   ret = db_config_get_session_flag(&flag);
   (void)do_reply_int(ret, flag);
   db_io_code_log(mname, "normal exit", ret);
}

void c_config_get_catalog_flag(void)
{
   /* Get the engine catalog flag. Function replies with a
      'dbeng' i/o code */
      
   char mname[] = "c_config_get_catalog_flag";
   int ret, flag;
   
   logman("%s:enter", mname);
   ret = db_config_get_catalog_flag(&flag);
   (void)do_reply_int(ret, flag);
   db_io_code_log(mname, "normal exit", ret);
}

void c_config_get_replicate_flag(void)
{
   /* Get the engine replication flag. Function replies with a
      'dbeng' i/o code */
      
   char mname[] = "c_config_get_replicate_flag";
   int ret, flag;
   
   logman("%s:enter", mname);
   ret = db_config_get_replicate_flag(&flag);
   (void)do_reply_int(ret, flag);
   db_io_code_log(mname, "normal exit", ret);
}

void c_config_get_version(void)
{
   /* Get the 'dbeng' version ID string. Function replies
      with a 'dbeng' i/o code. */
   
   char *ver;
   char mname[] = "c_config_get_version";
   int ret;
  
   logman("%s:enter", mname);

   if ((ver = (char *)malloc(128)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[ver]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   ret = db_config_get_version(ver);   
   (void)do_reply_char(ret, ver);
   free(ver);
   db_io_code_log(mname, "normal exit", ret);
}

void c_config_set_tmp_path(char *comm)
{
   /* Set the current path for temporary files.
      Syntax:

         tmp_path */

   char mname[30];
   char *tmp_path;
   int ret, len;

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

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

   len = strlen(comm);

   if ((tmp_path = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tmp_path]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, tmp_path, 1);
   ret = db_config_set_tmp_path(tmp_path);
   free(tmp_path);
   (void)do_reply_code(ret);
   logman("%s:normal exit", mname);
}

void c_config_set_session(char *comm)
{
   /* Set the current system session table path/file.
      Syntax:

         session_table */

   char mname[35];
   char *session_table;
   int ret, len;

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

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

   len = strlen(comm);

   if ((session_table = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[session_table]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, session_table, 1);
   ret = db_config_set_session(session_table);
   free(session_table);
   (void)do_reply_code(ret);    
   logman("%s:normal exit", mname);
}

void c_config_set_catalog(char *comm)
{
   /* Set the current system catalog path/file.
      Syntax:

         catalog */

   char mname[30];
   char *cat;
   int ret, len;

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

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

   len = strlen(comm);

   if ((cat = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[cat]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, cat, 1);
   ret = db_config_set_catalog(cat);
   free(cat);
   (void)do_reply_code(ret);    
   logman("%s:normal exit", mname);
}

void c_config_set_log(char *comm)
{
   /* Set the current logging name
      Syntax:

         log_name */

   char mname[] = "c_config_set_log";
   char *lname;
   int ret, len;

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

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

   len = strlen(comm);

   if ((lname = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[lname]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, lname, 1);
   ret = db_config_set_log(lname);
   free(lname);
   (void)do_reply_code(ret);    
   logman("%s:normal exit", mname);
}

void c_config_set_log_flag(char *comm)
{
   /* Set the current log flag.
      Syntax:

         flag */

   char mname[] = "c_config_set_log_flag";
   char *flag_char;
   int ret, len, flag;

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

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

   len = strlen(comm);

   if ((flag_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[flag_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, flag_char, 1);
   
   if (!qatoi(flag_char, &flag))
      {
      free(flag_char);
      db_io_code_log(mname, "flag not numeric", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   free(flag_char);
         
   if (flag != TRUE && flag != FALSE)
      {
      db_io_code_log(mname, "flag not zero or one", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }
      
   ret = db_config_set_log_flag(flag);
   (void)do_reply_code(ret);    
   logman("%s:normal exit", mname);
}

void c_config_set_session_flag(char *comm)
{
   /* Set the current session flag.
      Syntax:

         flag */

   char mname[] = "c_config_set_session_flag";
   char *flag_char;
   int ret, len, flag;

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

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

   len = strlen(comm);

   if ((flag_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[flag_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, flag_char, 1);
   
   if (!qatoi(flag_char, &flag))
      {
      free(flag_char);
      db_io_code_log(mname, "flag not numeric", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   free(flag_char);
         
   if (flag != TRUE && flag != FALSE)
      {
      db_io_code_log(mname, "flag not zero or one", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }
      
   ret = db_config_set_session_flag(flag);
   (void)do_reply_code(ret);    
   logman("%s:normal exit", mname);
}

void c_config_set_catalog_flag(char *comm)
{
   /* Set the current catalog flag.
      Syntax:

         flag */

   char mname[] = "c_config_set_catalog_flag";
   char *flag_char;
   int ret, len, flag, rep_flag;

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

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

   len = strlen(comm);

   if ((flag_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[flag_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, flag_char, 1);
   
   if (!qatoi(flag_char, &flag))
      {
      free(flag_char);
      db_io_code_log(mname, "flag not numeric", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   free(flag_char);
         
   if (flag != TRUE && flag != FALSE)
      {
      db_io_code_log(mname, "flag not zero or one", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }
      
   ret = db_config_set_catalog_flag(flag);

#ifdef IPC_TCP
   /* force the replication flag down if the catalog
      has been turned off */

   (void)db_config_get_replicate_flag(&rep_flag);

   if (ret == DBENG_OK && !flag && rep_flag)
      {
      db_io_code_log(mname, "turning replication off also", DBENG_OK);
      c_config_set_replicate_flag("0");
      }
#endif

   (void)do_reply_code(ret);    
   logman("%s:normal exit", mname);
}

void c_config_set_replicate_flag(char *comm)
{
   /* Set the current replication flag. Valid for TCP
      IPC method only. Syntax:

         flag */

   char mname[] = "c_config_set_replicate_flag";
   char *flag_char;
   int ret, len, flag;

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

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

   len = strlen(comm);

   if ((flag_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[flag_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, flag_char, 1);
   
   if (!qatoi(flag_char, &flag))
      {
      free(flag_char);
      db_io_code_log(mname, "flag not numeric", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   free(flag_char);
         
   if (flag != TRUE && flag != FALSE)
      {
      db_io_code_log(mname, "flag not zero or one", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }
      
#ifdef IPC_TCP
   ret = db_config_set_replicate_flag(flag);

   /* initialize replication if flag is high */

   if (ret == DBENG_OK)
      if (flag)
         {
         if ((ret = dbengrep_init()) != DBENG_OK)
            {
            db_io_code_log(mname, "bad rc from dbengrep_init,forcing flag "
                          "down", ret);
            (void)db_config_set_replicate_flag(FALSE);
            }
         }
      else
         if ((ret = dbengrep_end()) != DBENG_OK)
            db_io_code_log(mname, "bad rc from dbengrep_end", ret);
#else
   db_io_code_log(mname, "TCP IPC method only", DBENG_FUNCTION_NOT_IMPLEMENTED);
   ret = DBENG_FUNCTION_NOT_IMPLEMENTED;
#endif

   (void)do_reply_code(ret);    
   logman("%s:normal exit", mname);
}

void c_get_open_table_list(char *comm)
{
   /* Get the list of open tables. Syntax:

         [pat]

      Where 'pat' is a string pattern acceptable to
      the 'pmatch' function consisting of physical
      file name pattern. Function replies with
      a list (delimited by 'DBENG_LIST_DELIM') of
      matching entries along with a 'DBENG'
      code. */
   
   char *list_out;
   char mname[] = "c_get_open_table_list";
   int ret;
  
   logman("%s:enter", mname);

   if ((list_out = (char *)malloc(DBENG_MAXRECFIELD)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[list_out]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   ret = db_get_open_table_list(comm, list_out);
   (void)do_reply_char(ret, list_out);
   free(list_out);
   db_io_code_log(mname, "normal exit", ret);
}

void c_replicate(char *comm)
{
   /* Process a received replication command. Command will only be
      processed if the replication flag is high. Applies
      to TCP IPC method only. */

   char mname[] = "c_replicate";
   int ret, rep_flag;

#ifdef IPC_TCP
   (void)db_config_get_replicate_flag(&rep_flag);

   if (rep_flag)
      {
      if ((ret = dbengrep_recv(comm)) != DBENG_OK)
         db_io_code_log(mname, "received replication command failed", ret);
      }
   else
      ret = DBENG_REPLICATION_NOT_ACTIVE;
#else
   db_io_code_log(mname, "TCP IPC method only", DBENG_FUNCTION_NOT_IMPLEMENTED);
   ret = DBENG_FUNCTION_NOT_IMPLEMENTED;
#endif

   (void)do_reply_code(ret);    
   logman("%s:normal exit", mname);
}

void c_replicate_update(void)
{
   /* Update all replication information. Command will only be
      processed if the replication flag is high. Applies
      to TCP IPC method only. */

   char mname[] = "c_replicate_update";
   int ret, rep_flag;

#ifdef IPC_TCP
   (void)db_config_get_replicate_flag(&rep_flag);

   if (rep_flag)
      {
      if ((ret = dbengrep_init()) != DBENG_OK)
         db_io_code_log(mname, "update failed", ret);
      }
   else
      ret = DBENG_REPLICATION_NOT_ACTIVE;
#else
   db_io_code_log(mname, "TCP IPC method only", DBENG_FUNCTION_NOT_IMPLEMENTED);
   ret = DBENG_FUNCTION_NOT_IMPLEMENTED;
#endif

   (void)do_reply_code(ret);    
   logman("%s:normal exit", mname);
}

void c_delete_table(char *comm)
{
   /* Delete a table. The file name is expected on the command line.
      Function replies with a 'dbeng' code. Syntax:

         file_name */

   char mname[] = "c_delete_table", *fname;
   int ret, driret;
  
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_INVALID_FILE_NAME);
      (void)do_reply_code(DBENG_INVALID_FILE_NAME);
      return;
      }

   if ((fname = (char *)malloc(strlen(comm) + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[fname]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   if (!command_word(comm, fname, 1))
      {
      free(fname);
      db_io_code_log(mname, "bad rc from command_word[fname]",
                     DBENG_INTERNAL_ERROR);
      (void)do_reply_code(DBENG_INTERNAL_ERROR);
      return;
      }

   ret = db_delete_table(fname);
   free(fname);
   
   if ((driret = do_reply_code(ret)) != DBENG_OK)
      {
      logman("%s:bad ret from do_reply_code,rc[%d]", driret);
      return;
      }

   db_io_code_log(mname, "normal exit", ret);
}

void c_exist(char *comm)
{
   /* Determine whether a table exists. Syntax:

         file_name */

   char mname[] = "c_exist", *filename;
   int exist_flag = FALSE;
   int ret, len, driret;
  
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_INVALID_FILE_NAME);
      (void)do_reply_int(DBENG_INVALID_FILE_NAME, exist_flag);
      return;
      }

   len = strlen(comm);

   if ((filename = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[filename]", DBENG_MEMORY_FAIL);
      (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
      return;
      }
      
   (void)command_word(comm, filename, 1);
   ret = db_exist(filename, &exist_flag);
   free(filename);
   
   if ((driret = do_reply_int(ret, exist_flag)) != DBENG_OK)
      {
      logman("%s:bad ret from do_reply_int:rc=%d", mname, driret);
      return;
      }
            
   db_io_code_log(mname, "normal exit", ret);
}

void c_clear_table(char *comm)
{
   /* Clear a table of all records. Syntax:

         file_name */

   char mname[] = "c_clear_table", *filename;
   int ret, len, driret;
  
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_INVALID_FILE_NAME);
      (void)do_reply_code(DBENG_INVALID_FILE_NAME);
      return;
      }

   len = strlen(comm);

   if ((filename = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[filename]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }
      
   (void)command_word(comm, filename, 1);
   ret = db_clear_table(filename);
   free(filename);
   
   if ((driret = do_reply_code(ret)) != DBENG_OK)
      {
      logman("%s:bad ret from do_reply_int:rc=%d", mname, driret);
      return;
      }
            
   db_io_code_log(mname, "normal exit", ret);
}

void c_copy_table(char *comm)
{
   /* Copy a table from source to destination. Both tables are
      expected to be open. Function replies with a DBENG io code. 
      Syntax:

         source_tid destination_tid */

   char *src_tid_char, *dest_tid_char;
   char mname[] = "c_copy_table";
   int src_tid, dest_tid;
   int len;
   int ret;
  
   logman("%s:enter", mname);

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);

   if (words(comm) < 2)
      {
      db_io_code_log(mname, "missing tid", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return;
      }

   if ((src_tid_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[src_tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, src_tid_char, 1);
      
   if (!qatoi(src_tid_char, &src_tid))
      {
      free(src_tid_char);
      db_io_code_log(mname, "non numeric source tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (src_tid <= 0)
      {
      free(src_tid_char);
      db_io_code_log(mname, "source tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(src_tid_char);

   if ((dest_tid_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      db_io_code_log(mname, "alloc fail[dest_tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)word(comm, dest_tid_char, 2);
      
   if (!qatoi(dest_tid_char, &dest_tid))
      {
      free(dest_tid_char);
      db_io_code_log(mname, "non numeric destination tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (dest_tid <= 0)
      {
      free(dest_tid_char);
      db_io_code_log(mname, "destination tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(dest_tid_char);
   logman("%s:before db_copy_table:src_tid=%d,dest_tid=%d", mname,
                 src_tid, dest_tid);
   ret = db_copy_table(src_tid, dest_tid);
   logman("%s:after db_copy_table", mname);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_get_catalog_list(char *comm)
{
   /* Get a list of catalog entries. Syntax:

         [pat]

      Where 'pat' is a string pattern acceptable to
      the 'pmatch' function consisting of logical
      table name pattern. Function replies with
      a list (delimited by 'DBENG_LIST_DELIM') of
      matching catalog entries along with a 'DBENG'
      code. */
   
   char *list_out;
   char mname[] = "c_get_catalog_list";
   int ret;
  
   logman("%s:enter", mname);

   if ((list_out = (char *)malloc(DBENG_MAXRECFIELD)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[list_out]", DBENG_MEMORY_FAIL);
      (void)do_reply_char(DBENG_MEMORY_FAIL, "");
      return;
      }

   ret = db_get_catalog_list(comm, list_out);
   (void)do_reply_char(ret, list_out);
   free(list_out);
   db_io_code_log(mname, "normal exit", ret);
}

void c_delete_field(char *comm)
{
   /* Completly delete a field. Note that the field numbers of all
      fields after the one being deleted will change. Function replies
      with a DBENG io code. Syntax:

      tid field_number */

   char *tid_char, *fnum_char, mname[] = "c_delete_field";
   int nwords, fnum, tid, len, ret;

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

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);
   nwords = words(comm);

   if (nwords < 2)
      {
      db_io_code_log(mname, "missing field number", DBENG_NO_SUCH_FIELD);
      (void)do_reply_code(DBENG_NO_SUCH_FIELD);
      return;
      }

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);

   if ((fnum_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[fnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, fnum_char, 2);
      
   if (!qatoi(fnum_char, &fnum))
      {
      db_io_code_log(mname, "non numeric field number",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(fnum_char);
      return;
      }

   if (fnum <= 0)
      {
      db_io_code_log(mname, "field number out of range",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(fnum_char);
      return;
      }

   free(fnum_char);
   ret = db_delete_field(tid, fnum);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_delete_subfield(char *comm)
{
   /* Completly delete a subfield within a field. Note that the subfield 
      numbers of all subfields after the one being deleted will change. 
      Function replies with a DBENG io code. Syntax:

      tid field_number subfield_number */

   char *tid_char, *fnum_char, *sfnum_char, mname[] = "c_delete_subfield";
   int nwords, fnum, sfnum, tid, len, ret;

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

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);
   nwords = words(comm);

   if (nwords < 2)
      {
      db_io_code_log(mname, "missing field number", DBENG_NO_SUCH_FIELD);
      (void)do_reply_code(DBENG_NO_SUCH_FIELD);
      return;
      }

   if (nwords < 3)
      {
      db_io_code_log(mname, "missing subfield number", DBENG_NO_SUCH_SUBFIELD);
      (void)do_reply_code(DBENG_NO_SUCH_SUBFIELD);
      return;
      }

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);

   if ((fnum_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[fnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, fnum_char, 2);
      
   if (!qatoi(fnum_char, &fnum))
      {
      db_io_code_log(mname, "non numeric field number",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(fnum_char);
      return;
      }

   if (fnum <= 0)
      {
      db_io_code_log(mname, "field number out of range",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(fnum_char);
      return;
      }

   free(fnum_char);

   if ((sfnum_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[sfnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, sfnum_char, 3);
      
   if (!qatoi(sfnum_char, &sfnum))
      {
      db_io_code_log(mname, "non numeric subfield number",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(sfnum_char);
      return;
      }

   if (sfnum <= 0)
      {
      db_io_code_log(mname, "subfield number out of range",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(sfnum_char);
      return;
      }

   free(sfnum_char);
   ret = db_delete_subfield(tid, fnum, sfnum);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

void c_delete_subsubfield(char *comm)
{
   /* Completly delete a subsubfield within a subfield. Note that the 
      subsubfield numbers of all subsubfields after the one being deleted 
      will change. Function replies with a DBENG io code. Syntax:

      tid field_number subfield_number subsubfield_number */

   char *tid_char, *fnum_char, *sfnum_char, *ssfnum_char;
   char mname[] = "c_delete_subsubfield";
   int nwords, fnum, sfnum, ssfnum, tid, len, ret;

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

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   len = strlen(comm);
   nwords = words(comm);

   if (nwords < 2)
      {
      db_io_code_log(mname, "missing field number", DBENG_NO_SUCH_FIELD);
      (void)do_reply_code(DBENG_NO_SUCH_FIELD);
      return;
      }

   if (nwords < 3)
      {
      db_io_code_log(mname, "missing subfield number", DBENG_NO_SUCH_SUBFIELD);
      (void)do_reply_code(DBENG_NO_SUCH_SUBFIELD);
      return;
      }

   if (nwords < 4)
      {
      db_io_code_log(mname, "missing subsubfield number", 
                     DBENG_NO_SUCH_SUBSUBFIELD);
      (void)do_reply_code(DBENG_NO_SUCH_SUBSUBFIELD);
      return;
      }

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, tid_char, 1);
      
   if (!qatoi(tid_char, &tid))
      {
      free(tid_char);
      db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   if (tid <= 0)
      {
      free(tid_char);
      db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
      (void)do_reply_code(DBENG_NO_SUCH_TID);
      return;
      }

   free(tid_char);

   if ((fnum_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[fnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, fnum_char, 2);
      
   if (!qatoi(fnum_char, &fnum))
      {
      db_io_code_log(mname, "non numeric field number",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(fnum_char);
      return;
      }

   if (fnum <= 0)
      {
      db_io_code_log(mname, "field number out of range",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(fnum_char);
      return;
      }

   free(fnum_char);

   if ((sfnum_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[sfnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, sfnum_char, 3);
      
   if (!qatoi(sfnum_char, &sfnum))
      {
      db_io_code_log(mname, "non numeric subfield number",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(sfnum_char);
      return;
      }

   if (sfnum <= 0)
      {
      db_io_code_log(mname, "subfield number out of range",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(sfnum_char);
      return;
      }

   free(sfnum_char);

   if ((ssfnum_char = malloc(len + 1)) == NULL)
      {
      db_io_code_log(mname, "alloc fail[ssfnum_char]", DBENG_MEMORY_FAIL);
      (void)do_reply_code(DBENG_MEMORY_FAIL);
      return;
      }

   (void)command_word(comm, ssfnum_char, 4);
      
   if (!qatoi(ssfnum_char, &ssfnum))
      {
      db_io_code_log(mname, "non numeric subsubfield number",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(ssfnum_char);
      return;
      }

   if (ssfnum <= 0)
      {
      db_io_code_log(mname, "subsubfield number out of range",
                     DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      free(ssfnum_char);
      return;
      }

   free(ssfnum_char);
   ret = db_delete_subsubfield(tid, fnum, sfnum, ssfnum);
   (void)do_reply_code(ret);
   db_io_code_log(mname, "normal exit", ret);
}

int c_terminate(char *comm)
{
   /* Terminate the server. Check the supplied password first.
      Syntax:
      
         password
         
      Function returns 'TRUE' if correct password was supplied,
      'FALSE' otherwise. */
      
   char mname[] = "c_terminate";
   char wrd[256];
   int ret;

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

   if (comm == (char *)NULL || !strlen(comm))
      {
      db_io_code_log(mname, "null or empty[comm]", DBENG_INVALID_FUNCTION);
      (void)do_reply_code(DBENG_INVALID_FUNCTION);
      return(FALSE);
      }
      
   if (!command_word(comm, wrd, 1))
      {
      (void)do_reply_code(DBENG_INTERNAL_ERROR);
      logman("%s:error getting password", mname);
      return(FALSE);
      }
         
   if (!strcmp(wrd, DBSRV_TERM_PASSWD))
      {            
      (void)do_reply_code(DBENG_OK);
      return(TRUE);
      }
            
   logman("%s:illegal terminate request", mname);
   (void)do_reply_code(DBENG_ACCESS_DENIED);
   return(FALSE);
}

void c_trans_num(void)
{
   /* Get the current transaction count. Syntax:
      
         DBENG_SEND_TRANS_NUM */
   
   char mname[] = "c_trans_num";
   long count;
   
   logman("%s:enter", mname);

#ifdef IPC_TCP
   count = ipc_trans_num();
#else
   count = server_trans_num;
#endif

   (void)do_reply_long(DBENG_OK, count);
   logman("%s:normal exit", mname);   
}

void c_connect_num(void)
{
   /* Get the current connection count. Syntax:
      
         DBENG_SEND_CONNECT_NUM */
   
   char mname[] = "c_connect_num";
   int count;

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

#ifdef IPC_TCP
   count = ipc_connect_num();
   (void)do_reply_int(DBENG_OK, count);
#else
   (void)do_reply_int(DBENG_FUNCTION_NOT_IMPLEMENTED, 0);
#endif

   logman("%s:normal exit", mname);   
}

/* IPC primatives */

int do_reply_int(int reply_code, int int_value)
{
   /* Send a reply to a request which returns an int in addition
      to the reply code. Function returns 'DBENG_OK' upon success,
      an error code otherwise. */

   char reply_char[50];
   int anint = 0;
   
   if (reply_code == DBENG_OK)
      anint = int_value;
      
   memset(reply_char, 0, 50);
   sprintf(reply_char, "%d %d", reply_code, anint);
   logman("do_reply_int:reply=%s,%d", reply_char,
                 strlen(reply_char));
   
   if (ipc_send_data(reply_char) == 0)
      return(DBENG_VC_ERROR);
      
   return(DBENG_OK);
}

int do_reply_long(int reply_code, long long_value)
{
   /* Send a reply to a request which returns a long in addition
      to the reply code. Function returns 'DBENG_OK' upon success,
      an error code otherwise. */

   char reply_char[50];
   int along = 0L;
   
   if (reply_code == DBENG_OK)
      along = long_value;
      
   memset(reply_char, 0, 50);
   sprintf(reply_char, "%d %ld", reply_code, along);
   logman("do_reply_long:reply=%s,%d", reply_char,
                 strlen(reply_char));
  
   if (ipc_send_data(reply_char) == 0)
      return(DBENG_VC_ERROR);
      
   return(DBENG_OK);
}

int do_reply_code(int reply_code)
{
   /* Send a reply to a request which returns the reply code. Function
      returns 'DBENG_OK' upon success, an error code otherwise. */

   char reply_char[50];
         
   memset(reply_char, 0, 50);
   sprintf(reply_char, "%d", reply_code);
   logman("do_reply_code:reply=%s,%d", reply_char,
                 strlen(reply_char));
   
   if (ipc_send_data(reply_char) == 0)
      return(DBENG_VC_ERROR);
      
   return(DBENG_OK);
}

int do_reply_char(int reply_code, char *char_value)
{
   /* Send a reply to a request that returns a string as well as
      the reply code. Function returns 'DBENG_OK' upon success, an
      error code otherwise. */

   char *reply_char;
   int len;
         
   if (char_value == (char *)NULL)
      return(DBENG_INVALID_FUNCTION);
   
   len = strlen(char_value);
   
   // alloc reply string, note that 'char_value' might be empty
   
   if ((reply_char = (char *)malloc(len + 10)) == (char *)NULL)
      return(DBENG_MEMORY_FAIL);
      
   memset(reply_char, 0, len + 10);
   sprintf(reply_char, "%d '%s'", reply_code, char_value);
   logman("do_reply_char:lreply=%d", strlen(reply_char));

   if (ipc_send_data(reply_char) == 0)
      {
      free(reply_char);
      return(DBENG_VC_ERROR);
      }
      
   free(reply_char);
   return(DBENG_OK);
}

void term_app(void)
{
   // Prepare to terminate the application. Shutdown all IPC API's.

   db_end();
   logman("term_app:server down");

#ifdef IPC_TCP
   (void)sloc_delete(server_port);
   sloc_term_api();
#ifdef OS_WIN32
   WSACleanup();
#endif
#else
   (void)ipc_close();
#endif

   (void)appinit_remove_name();
}

#ifdef IPC_TCP
void usage(void)
{
   /* Display program usage. */
   
   printf("usage:dbsrv [%cq] port\n", SWITCH_CHAR);
}
#endif
