/* DB - A command line for the database server/engine 'Bbuuzzb',
   Rick Smereka, Copyright (C) 1995-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 DOS version Dec/95, Rick Smereka

   Re-compiled for enhanced buffer I/O. Dec/96, Rick Smereka

   Re-compiled with new version of 'DBENG.C'. Jan/97, Rick Smereka

   Complete re-write for new high level API (dblocal).
   Jan/97, Rick Smereka

   Port to QNX V4.23a. Jan/97, Rick Smereka

   Add flexible compile for either single or multiuser.
   Feb/97, Rick Smereka

   Complete re-write for new API. Oct/97, Rick Smereka

   Port to 32bit Windows under CodeWarrior V4.
   Port to HP-UX under GNU C 2.8.1.
   Jan/99, Rick Smereka

   Modified 'c_open' to provide for situation where file
   data format is incorrect. Implemented a multi-
   platform logo. Added support for the 'new_table'
   command. Added function 'eng_initialize' to start the
   local database engine and report on the configuration
   settings. Feb/99, Rick Smereka

   Added 12 new commands to get and set configuration options.
   Apr/99, Rick Smereka

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

   Re-compiled after re-structuring the definition of the common
   send and repy codes. Moved 'include' of the header 'flsocket.h'
   inside the 'MULTIUSER' if statement. Modified to use the
   'socloc' API if in multiuser mode. Changed keyword connecting
   character from '_' to '.'. Added command 'version'. Added
   display of currently connected 'Bbuuzzb' server in multiuser
   mode. Apr/2000, Rick Smereka
   
   Re-compiled after adding the new 'clib' module 'ip.c'.
   Jul/2000, Rick Smereka

   Corrected some return codes and modified stated command syntax
   from old underscore word connector to new period word
   connector. Corrected bug in 'c_count' which ignored the table
   'process_deleted' flag when the 'all' option was not used.
   May/2001, Rick Smereka

   Added command 'get.open.table.list' and
   re-compiled for new database engine version. Jun/2001,
   Rick Smereka

   Modified for use with both sockets and QNX message passing IPC.
   Oct/2001, Rick Smereka

   Added support for the new commands 'DBCOM_GET_NSUBFIELDS',
   'DBCOM_GET_SUBFIELD_SIZE', 'DBCOM_GET_SUBFIELD', 'DBCOM_PUT_SUBFIELD',
   'DBCOM_GET_NSUBSUBFIELDS', 'DBCOM_GET_SUBSUBFIELD_SIZE',
   'DBCOM_GET_SUBSUBFIELD' and 'DBCOM_PUT_SUBSUBFIELD'. Re-wrote debug
   interface for system logging. Dec/2001, Rick Smereka

   Added support for the new commands 'DBCOM_CONFIG_GET_REPLICATE_FLAG'
   and 'DBCOM_CONFIG_SET_REPLICATE_FLAG'. Jan/2002, Rick Smereka

   Added support for the command 'DBCOM_REPLICATE_UPDATE'.
   Mar/2002, Rick Smereka

   Excluded include of 'flsocket.h' in the case of DOS.
   Apr/2002, Rick Smereka

   Added support for automatic field, subfield and subsubfield
   append using the value zero. Commands 'db.put.field',
   'db.put.subfield' and 'db.put.subsubfield' now allow a zero
   value (in the field, subfield and subsubfield number parameter)
   to signify an append. Added command 'DBCOM_EXIST'.
   May/2002, Rick Smereka

   Added command 'DBCOM_CLEAR_TABLE'. Changed call to 'sys_log_init'
   to include the application name. Jun/2002, Rick Smereka

   Added parameter to the 'DBCOM_GET_OPEN_TABLE_LIST' command.
   Added command 'DBCOM_GET_CATALOG_LIST'. Aug/2002, 
   Rick Smereka

   Ported to Debian Linux. Jan/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').
   Added commands 'DBCOM_TRANS_NUM' and 'DBCOM_CONNECT_NUM'.
   Modified for the updated 'bbuuzzb' API.
   Jun/2003, Rick Smereka

   Enabled catalog functions in both single user and
   multiuser (client/server) modes. Dec/2003,
   Rick Smereka

   Added support for the commands 'DBCOM_GET_AUTOPACK' and
   'DBCOM_SET_AUTOPACK'. Mar/2004, Rick Smereka

   Added support for the commands 'DBCOM_CONFIG_CLIENT_GET_LOG',
   'DBCOM_CONFIG_CLIENT_GET_LOG_FLAG',
   'DBCOM_CONFIG_CLIENT_SET_LOG' and 'DBCOM_CONFIG_CLIENT_SET_LOG_FLAG'.
   Added include of 'appinit.h' and call to 'appinit_register_name'
   from the 'main' function. Removed the 'DEBUG' define.
   Added define 'APNAME'. Recoded function 'term_app'. 
   Apr/2004, Rick Smereka

   Re-compile after changing the 'socloc' API. Added display messages
   to the the functions 'c_config_client_get_log',
   'c_config_client_get_log_flag', 'c_config_client_set_log' and
   'c_config_client_set_log_flag' to instruct user to the the 'non-client'
   commands instead. Jan/2005, Rick Smereka

   Re-compile after modifications to low level TCP socket communication
   module (ipcomm.c). Feb/2006, Rick Smereka
 
   Changed 'c_new_table' to only display the table tid if a table
   open was requested. Mar/2006, Rick Smereka */

#include "stdhead.h"
#ifndef OS_DOS
#include "flsocket.h"
#include "appinit.h"
#endif
#include "dbmess.h"
#include "dbiocode.h"
#include "dbcomm.h"
#ifdef IPC_TCP
#include "socloc.h"
#include "sloc.h"
#include "slconfig.h"
#include "sliocode.h"
#ifdef OS_WIN32
WSADATA wsaData;
#endif
#endif

/* high level database API changes depending
   on whether we are compiling for single user
   or multiuser */

#ifdef MULTIUSER
#include "dbcs.h"
#include "dbcscfg.h"
#else
#include "dbeng.h"
#include "dblocal.h"
#include "dbengcfg.h"
#include "dblocfg.h"
#endif

#define VERSION "1.43.02-2006.03.28"

#ifdef MULTIUSER
#define APNAME "dbm"
#else
#define APNAME "db"
#endif

int main(void);
int c_initialize(void);
int do_comm(char *);
int c_open(char *);
int c_close(char *);
int c_next(char *);
int c_top(char *);
int c_get_rec(char *);
int c_get_field(char *);
int c_get_subfield(char *);
int c_get_subsubfield(char *);
int c_goto(char *);
int c_count(char *);
int c_put_field(char *);
int c_put_subfield(char *);
int c_put_subsubfield(char *);
int c_write(char *);
int c_delete(char *);
int c_get_delete_flag(char *);
int c_set_delete_flag(char *);
int c_get_nfields(char *);
int c_get_nsubfields(char *);
int c_get_nsubsubfields(char *);
int c_get_rec_size(char *);
int c_get_field_size(char *);
int c_get_subfield_size(char *);
int c_get_subsubfield_size(char *);
int c_get_rec_num(char *);
int c_get_pos(char *);
int c_set_pos(char *);
int c_get_change_rec_flag(char *);
int c_set_change_rec_flag(char *);
int c_pack(char *);
int c_new(char *);
int c_find(char *);
int c_find_field(char *);
int c_find_part(char *);
int c_find_field_part(char *);
int c_get_rec_count(char *);
int c_get_enf_change_rec_flag(char *);
int c_set_enf_change_rec_flag(char *);
int c_get_is_table_locked(char *);
int c_set_is_table_locked(char *);
int c_new_table(char *);
int c_config_get_tmp_path(void);
int c_config_get_log(void);
int c_config_get_session(void);
int c_config_get_catalog(void);
int c_config_get_log_flag(void);
int c_config_get_session_flag(void);
int c_config_get_catalog_flag(void);
int c_config_get_replicate_flag(void);
int c_config_get_version(void);
int c_version(void);
int c_config_set_tmp_path(char *);
int c_config_set_log(char *);
int c_config_set_session(char *);
int c_config_set_catalog(char *);
int c_config_set_log_flag(char *);
int c_config_set_session_flag(char *);
int c_config_set_catalog_flag(char *);
int c_config_set_replicate_flag(char *);
int c_get_open_table_list(char *);
int c_delete_table(char *);
int c_exist(char *);
int c_clear_table(char *);
int c_copy_table(char *);
int c_get_catalog_list(char *);
int c_sort(char *);
int c_get_sort_mem(char *);
int c_set_sort_mem(char *);
int c_get_sort_open_bin(char *);
int c_set_sort_open_bin(char *);
int c_delete_field(char *);
int c_delete_subfield(char *);
int c_delete_subsubfield(char *);
int c_trans_num(void);
int c_connect_num(void);
int c_get_autopack(char *);
int c_set_autopack(char *);
int c_config_client_get_log(void);
int c_config_client_get_log_flag(void);
int c_config_client_set_log(char *);
int c_config_client_set_log_flag(char *);
int get_token(char *);
void term_app(void);

#ifdef IPC_TCP
int c_ipc_socloc_init(void);
#endif

int main(void)
{
   char *comm;
   int done = FALSE;
   int ret;

    /* allocate command line buffer */

   if ((comm = malloc(DBCOM_MAXCOMLINE + 1)) == NULL)
      {
      printf("%s:insufficient memory to run program\n", APNAME);
      return(0);
      }

   /* build logo string based on platform */

#ifndef MULTIUSER
#ifndef OS_UNIX
   /* single user non-Unix */

   sprintf(comm, "DB Single User for %s Version %s", PLATFORM_STRING,
           VERSION);
#else
   /* single user Unix */

   sprintf(comm, "DB Single User for %s Version %s", SUB_PLATFORM_STRING,
           VERSION);
#endif
#else
#ifndef OS_UNIX
   /* c/s non-Unix */

   sprintf(comm, "DBM Client/Server for %s Version %s", PLATFORM_STRING,
           VERSION);
#else
   /* c/s Unix */

   sprintf(comm, "DBM Client/Server for %s Version %s", SUB_PLATFORM_STRING,
           VERSION);
#endif
#endif

   printf("%s\n", comm);
   printf("By Rick Smereka, Copyright (c) 1995-2006\n");

#ifndef OS_DOS
   // register application name with 'appinit'

   if (!appinit_register_name(APNAME))
      {
      free(comm);
      printf("%s:fatal error registering app name with appinit\n", APNAME);
      return(0);
      }
#endif

   /* initialize local engine if we are running locally or
      startup the 'socloc' interface (TCP only) and connect to a
      Bbuuzzb database server if we are running in
      client/server mode */

   if (!c_initialize())
      {
      free(comm);
      term_app();
      return(0);
      }

   /* get and display 'Bbuuzzb' version */

   if ((ret = db_config_get_version(comm)) != DBENG_OK)
      {
      db_io_code_string(ret, comm);
      printf("%s:error getting 'Bbuuzzb' version,rc=%s\n", APNAME, comm);
      free(comm);
      term_app();
      return(0);
      }

   printf("based on version %s of 'Bbuuzzb'\n", comm);
   printf("%s comes with ABSOLUTELY NO WARRANTY\n", APNAME);
   printf("This is free software, and you are welcome to redistribute it\n");
   printf("under certain conditions; see 'gpl.txt' for information.\n");

   /* interpret loop */

   while(!done)
      {
      printf("%s> ", APNAME);
      get_rec(stdin, comm);

      if (!do_comm(comm))
         done = TRUE;
      }

   free(comm);
   term_app();
   printf("exit %s\n", APNAME);
   return(0);
}

#ifdef MULTIUSER
int c_initialize(void)
{
   /* Initialize socket communication, form connection to
      'socloc' server (TCP only), update the config list and connect
      to a 'Bbuuzzb' server. Function returns 'TRUE' upon
      success, 'FALSE' otherwise. */

   char mname[] = "c_initialize";
   char mes[128];
   int ret;

#ifdef IPC_TCP
   if (!c_ipc_socloc_init())
      return(FALSE);
#endif

   /* attempt to locate a 'Bbuuzzb' server and connect to it */

   if ((ret = db_initialize()) != DBENG_OK)
      {
      db_io_code_string(ret, mes);
      printf("%s:error connecting to the Bbuuzzb server,rc[%s]. "
             "Program abort\n", mname, mes);
      return(FALSE);
      }

   /* display current connected server host name and
      TCP port number */

#ifdef IPC_TCP
   (void)db_get_active(mes, &ret);
   printf("%s:connected to Bbuuzzb server %s on TCP port %d (decimal)\n",
          mname, mes, ret);
#endif

   /* get and display server version */

   (void)db_version(mes);
   printf("%s:Bbuuzzb server version is %s\n", mname, mes);
   return(TRUE);
}
#endif

#ifndef MULTIUSER
int c_initialize(void)
{
   /* Start the 'DBENG' local engine, read the config file
      and display the result settings. Function returns
      'TRUE' upon success, 'FALSE' otherwise. */

   char mname[] = "c_initialize";
   char *mes;
   int ret, flag;

   if ((mes = (char *)malloc(DBENG_PATH_LIMIT)) == (char *)NULL)
      {
      printf("%s:alloc fail[mes]. Program abort\n", mname);
      return(FALSE);
      }

   ret = db_initialize();

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

   switch(ret)
      {
      case DBENG_OK:
         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:fatal config error[%s]\n", mname, mes);
         printf("%s:terminating\n", mname);
         free(mes);
         return(FALSE);
         break;
      };

   (void)db_config_get_tmp_path(mes);
   printf("%s:tmp path is '%s'\n", mname, mes);
   (void)db_config_get_log(mes);
   printf("%s:log is '%s'\n", mname, mes);

   if ((ret = db_config_get_catalog(mes)) == DBENG_OK)
      printf("%s:catalog is '%s'\n", mname, mes);
   else
      printf("%s:catalog name not loaded\n", mname);

   (void)db_config_get_catalog_flag(&flag);

   if (flag_2_logic_string(flag, mes))
      printf("%s:catalog is %s\n", mname, mes);

   free(mes);
   return(TRUE);
}
#endif

#ifdef IPC_TCP
int c_ipc_socloc_init(void)
{
   /* Initialize socket communication, form connection to
      'socloc' server (TCP only) and update the config list.
      Function returns 'TRUE' upon success, 'FALSE' otherwise. */

   char mname[] = "dbm:c_ipc_socloc_init";
   char *thelist, mes[128];
   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

   /* attempt to connect to a 'socloc' server */

   if ((ret = sloc_initialize()) != SL_OK)
      {
      sl_code_string(ret, mes);
      printf("%s:error initializing socloc interface,rc[%s]. "
            "Program abort\n", mname, mes);
      return(FALSE);
      }

   /* get config list from 'socloc' server and update
      the client list with it */

   if ((thelist = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
      {
      printf("%s:alloc fail[thelist]. Program abort\n", mname);
      return(FALSE);
      }

   if ((ret = sloc_config_get_list(thelist)) != SL_OK)
      {
      free(thelist);
      sl_code_string(ret, mes);
      printf("%s:error getting socloc config list,rc[%s]. "
             "Program abort\n", mname, mes);
      return(FALSE);
      }

   if ((ret = sl_config_put_list(thelist)) != SL_OK)
      {
      sl_code_string(ret, mes);
      printf("%s:error putting socloc config list,rc[%s]. ",
             "Program abort\n", mname, mes);
      free(thelist);
      return(FALSE);
      }

   free(thelist);
   return(TRUE);
}
#endif

int do_comm(char *comm)
{
   /* Perform database commands. */

   char *keywrd;                 /* command keyword */
   int token;                    /* keyword token */
   int nwords;                   /* number of words */
   int status;                   /* return status from operation */
   int len;                      /* length of command */

   len = strlen(comm);

   if (!len)
      {
      printf("empty command\n");
      return(TRUE);
      }

   /* allocate to max as this string is re-used for the return
      status string */

   if ((keywrd = malloc(DBCOM_MAXCOMLINE + 1)) == NULL)
      {
      printf("do_comm:memory fail 'keywrd'\n");
      return(TRUE);
      }

   if (!word(comm, keywrd, 1))
      {
      printf("do_comm:error while retreving keyword, line skipped\n");
      free(keywrd);
      return(TRUE);
      }

   nwords = words(comm);

   if ((token = get_token(keywrd)) == DBCOM_NOT_FOUND)
      {
      printf("do_comm:unknown keyword '%s'\n", keywrd);
      free(keywrd);
      return(TRUE);
      }

   /* process command */

   switch(token)
      {
      case DBCOM_OPEN:
         status = c_open(comm);
         break;

      case DBCOM_CLOSE:
         status = c_close(comm);
         break;

      case DBCOM_NEXT:
         status = c_next(comm);
         break;

      case DBCOM_TOP:
         status = c_top(comm);
         break;

      case DBCOM_GET_REC:
         status = c_get_rec(comm);
         break;

      case DBCOM_GET_FIELD:
         status = c_get_field(comm);
         break;

      case DBCOM_GOTO:
         status = c_goto(comm);
         break;

      case DBCOM_COUNT:
         status = c_count(comm);
         break;

      case DBCOM_PUT_FIELD:
         status = c_put_field(comm);
         break;

      case DBCOM_WRITE:
         status = c_write(comm);
         break;

      case DBCOM_DELETE:
         status = c_delete(comm);
         break;

      case DBCOM_GET_DELETE_FLAG:
         status = c_get_delete_flag(comm);
         break;

      case DBCOM_SET_DELETE_FLAG:
         status = c_set_delete_flag(comm);
         break;

      case DBCOM_GET_NFIELDS:
         status = c_get_nfields(comm);
         break;

      case DBCOM_GET_REC_SIZE:
         status = c_get_rec_size(comm);
         break;

      case DBCOM_GET_FIELD_SIZE:
         status = c_get_field_size(comm);
         break;

      case DBCOM_GET_REC_NUM:
         status = c_get_rec_num(comm);
         break;

      case DBCOM_GET_POS:
         status = c_get_pos(comm);
         break;

      case DBCOM_SET_POS:
         status = c_set_pos(comm);
         break;

      case DBCOM_GET_CHANGE_REC_FLAG:
         status = c_get_change_rec_flag(comm);
         break;

      case DBCOM_SET_CHANGE_REC_FLAG:
         status = c_set_change_rec_flag(comm);
         break;

      case DBCOM_PACK:
         status = c_pack(comm);
         break;

      case DBCOM_NEW:
         status = c_new(comm);
         break;

      case DBCOM_FIND:
         status = c_find(comm);
         break;

      case DBCOM_FIND_FIELD:
         status = c_find_field(comm);
         break;

      case DBCOM_FIND_PART:
         status = c_find_part(comm);
         break;

      case DBCOM_FIND_FIELD_PART:
         status = c_find_field_part(comm);
         break;

      case DBCOM_GET_REC_COUNT:
         status = c_get_rec_count(comm);
         break;

      case DBCOM_GET_ENF_CHANGE_REC_FLAG:
         status = c_get_enf_change_rec_flag(comm);
         break;

      case DBCOM_SET_ENF_CHANGE_REC_FLAG:
         status = c_set_enf_change_rec_flag(comm);
         break;

      case DBCOM_GET_IS_TABLE_LOCKED:
         status = c_get_is_table_locked(comm);
         break;

      case DBCOM_SET_IS_TABLE_LOCKED:
         status = c_set_is_table_locked(comm);
         break;

      case DBCOM_NEW_TABLE:
         status = c_new_table(comm);
         break;

      case DBCOM_CONFIG_GET_TMP_PATH:
         status = c_config_get_tmp_path();
         break;

      case DBCOM_CONFIG_GET_LOG:
         status = c_config_get_log();
         break;

      case DBCOM_CONFIG_GET_SESSION:
         status = c_config_get_session();
         break;

      case DBCOM_CONFIG_GET_CATALOG:
         status = c_config_get_catalog();
         break;

      case DBCOM_CONFIG_GET_LOG_FLAG:
         status = c_config_get_log_flag();
         break;

      case DBCOM_CONFIG_GET_SESSION_FLAG:
         status = c_config_get_session_flag();
         break;

      case DBCOM_CONFIG_GET_CATALOG_FLAG:
         status = c_config_get_catalog_flag();
         break;

      case DBCOM_CONFIG_GET_REPLICATE_FLAG:
         status = c_config_get_replicate_flag();
         break;

      case DBCOM_CONFIG_GET_VERSION:
         status = c_config_get_version();
         break;

      case DBCOM_CONFIG_SET_TMP_PATH:
         status = c_config_set_tmp_path(comm);
         break;

      case DBCOM_CONFIG_SET_LOG:
         status = c_config_set_log(comm);
         break;

      case DBCOM_CONFIG_SET_SESSION:
         status = c_config_set_session(comm);
         break;

      case DBCOM_CONFIG_SET_CATALOG:
         status = c_config_set_catalog(comm);
         break;

      case DBCOM_CONFIG_SET_LOG_FLAG:
         status = c_config_set_log_flag(comm);
         break;

      case DBCOM_CONFIG_SET_SESSION_FLAG:
         status = c_config_set_session_flag(comm);
         break;

      case DBCOM_CONFIG_SET_CATALOG_FLAG:
         status = c_config_set_catalog_flag(comm);
         break;

      case DBCOM_CONFIG_SET_REPLICATE_FLAG:
         status = c_config_set_replicate_flag(comm);
         break;

      case DBCOM_GET_OPEN_TABLE_LIST:
         status = c_get_open_table_list(comm);
         break;

      case DBCOM_GET_NSUBFIELDS:
         status = c_get_nsubfields(comm);
         break;

      case DBCOM_GET_SUBFIELD_SIZE:
         status = c_get_subfield_size(comm);
         break;

      case DBCOM_GET_SUBFIELD:
         status = c_get_subfield(comm);
         break;

      case DBCOM_PUT_SUBFIELD:
         status = c_put_subfield(comm);
         break;

      case DBCOM_GET_NSUBSUBFIELDS:
         status = c_get_nsubsubfields(comm);
         break;

      case DBCOM_GET_SUBSUBFIELD_SIZE:
         status = c_get_subsubfield_size(comm);
         break;

      case DBCOM_GET_SUBSUBFIELD:
         status = c_get_subsubfield(comm);
         break;

      case DBCOM_PUT_SUBSUBFIELD:
         status = c_put_subsubfield(comm);
         break;

      case DBCOM_REPLICATE_UPDATE:
#ifndef OS_DOS
         status = c_replicate_update();
         break;
#endif

      case DBCOM_DELETE_TABLE:
         status = c_delete_table(comm);
         break;
 
      case DBCOM_EXIST:
         status = c_exist(comm);
         break;

      case DBCOM_CLEAR_TABLE:
         status = c_clear_table(comm);
         break;

      case DBCOM_COPY_TABLE:
         status = c_copy_table(comm);
         break;

      case DBCOM_GET_CATALOG_LIST:
         status = c_get_catalog_list(comm);
         break;

      case DBCOM_SORT:
         status = c_sort(comm);
         break;

      case DBCOM_GET_SORT_MEM:
         status = c_get_sort_mem(comm);
         break;

      case DBCOM_SET_SORT_MEM:
         status = c_set_sort_mem(comm);
         break;

      case DBCOM_GET_SORT_OPEN_BIN:
         status = c_get_sort_open_bin(comm);
         break;

      case DBCOM_SET_SORT_OPEN_BIN:
         status = c_set_sort_open_bin(comm);
         break;

      case DBCOM_DELETE_FIELD:
         status = c_delete_field(comm);
         break;

      case DBCOM_DELETE_SUBFIELD:
         status = c_delete_subfield(comm);
         break;

      case DBCOM_DELETE_SUBSUBFIELD:
         status = c_delete_subsubfield(comm);
         break;

      case DBCOM_TRANS_NUM:
         status = c_trans_num();
         break;

      case DBCOM_CONNECT_NUM:
         status = c_connect_num();
         break;

      case DBCOM_GET_AUTOPACK:
         status = c_get_autopack(comm);
         break;

      case DBCOM_SET_AUTOPACK:
         status = c_set_autopack(comm);
         break;

      case DBCOM_CONFIG_CLIENT_GET_LOG:
         status = c_config_client_get_log();
         break;

      case DBCOM_CONFIG_CLIENT_GET_LOG_FLAG:
         status = c_config_client_get_log_flag();
         break;

      case DBCOM_CONFIG_CLIENT_SET_LOG:
         status = c_config_client_set_log(comm);
         break;

      case DBCOM_CONFIG_CLIENT_SET_LOG_FLAG:
         status = c_config_client_set_log_flag(comm);
         break;

      case DBCOM_VERSION:
         status = c_version();
         break;

      case DBCOM_OFF:
         return(FALSE);
         break;

      default:
        printf("function not yet implemented\n");
        free(keywrd);
        return(TRUE);
      };

   db_io_code_string(status, keywrd);
   printf("%s\n", keywrd);

   /* if a server failover has ocurred, display details of
      new connected server (TCP only) */

#ifdef MULTIUSER
#ifdef IPC_TCP
   if (status == DBENG_FAILOVER)
      {
      (void)db_get_active(keywrd, &status);
      printf("now connected to Bbuuzzb server %s on TCP port %d (decimal)\n",
             keywrd, status);
      }
#endif
#endif

   free(keywrd);
   return(TRUE);
}

int c_open(char *comm)
{
   /* Open a table. The file name is expected on the command line.
      Function returns the 'DBENG' status. Syntax:

         open file_name

      Note that the returned 'tid' is printed on the screen. */

   char *fname;
   int tid;
   int len;
   int ret;

   /* must be at least two words on command line */

   if (command_words(comm) < 2)
      {
      printf("c_open:missing file name\n");
      return(DBENG_INVALID_FILE_NAME);
      }

   len = strlen(comm);

   if ((fname = malloc(len + 1)) == NULL)
      {
      printf("c_open:unable to alloc 'fname'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, fname, 2);
   ret = db_open(fname, &tid);

   if (ret == DBENG_OK || ret == DBENG_FILE_DATA_ERROR)
      printf("tid is %d\n", tid);

   if (ret == DBENG_FILE_DATA_ERROR)
      printf("table is still open\n");

   free(fname);
   return(ret);
}

int c_close(char *comm)
{
   /* Close a table. Function returns the 'DBENG' status. Syntax:

         close tid */

   char *tid_char;
   int tid;
   int len;

   /* must be at least two words on command line */

   if (words(comm) < 2)
      {
      printf("c_close:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_close:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);    /* tid in char is second word */

   if (!qatoi(tid_char, &tid))
      {
      printf("c_close:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_close:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);
   return(db_close(tid));
}

int c_next(char *comm)
{
   /* Get next record in a table. Function returns the 'DBENG' status.
      Syntax:

         next tid */

   char *tid_char;
   int tid;
   int len;

   if (words(comm) < 2)
      {
      printf("c_next:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_next:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_next:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_next:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);
   return(db_next(tid));
}

int c_top(char *comm)
{
   /* Goto the top of the table. Note that file pointer is at the
      very top and no record is loaded. Function returns the 'DBENG'
      status. Syntax:

         top tid */

   char *tid_char;
   int tid;
   int len;

   if (words(comm) < 2)
      {
      printf("c_top:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_top:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_top:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_top:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);
   return(db_top(tid));
}

int c_get_rec(char *comm)
{
   /* Get and display the current record. Function returns the 'DBENG'
      status. Syntax:

         get.rec tid */

   char *tid_char;
   char *rec;
   int rec_size;
   int nfields;
   int tid;
   int len;
   int ret;

   if (words(comm) < 2)
      {
      printf("c_get_rec:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_get_rec:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_get_rec:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_get_rec:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((ret = db_get_rec_size(tid, &rec_size)) != DBENG_OK)
      return(ret);

   if ((rec = malloc(rec_size + 1)) == NULL)
      {
      printf("c_get_rec:alloc fail 'rec'\n");
      return(DBENG_MEMORY_FAIL);
      }

   ret = db_get_rec(tid, rec);

   if (ret == DBENG_OK)
      {
      if ((ret = db_get_nfields(tid, &nfields)) != DBENG_OK)
         {
         free(rec);
         return(ret);
         }

      printf("rec=%s,l=%d,nfields=%d\n", rec, strlen(rec), nfields);
      }

   free(rec);
   return(ret);
}

int c_get_field(char *comm)
{
   /* Get and display a field in the current record. Function returns
      the 'DBENG' status. Syntax:

         get.field tid field_num */

   char *tid_char;
   char *field_num_char;
   char *field;
   int field_size;
   int field_num;
   int nwords;
   int tid;
   int len;
   int ret;

   nwords = words(comm);

   if (nwords < 2)
      {
      printf("c_get_field:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("c_get_field:missing field number\n");
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_get_field:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_get_field:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_get_field:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((field_num_char = malloc(len + 1)) == NULL)
      {
      printf("c_get_field:alloc fail 'field_num_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, field_num_char, 3);

   if (!qatoi(field_num_char, &field_num))
      {
      printf("c_get_field:non numeric field number\n");
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (field_num <= 0)
      {
      printf("c_get_field:invalid field number\n");
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(field_num_char);

   if ((ret = db_get_field_size(tid, field_num, &field_size)) != DBENG_OK)
      return(ret);

   if (!field_size)
      {
      printf("c_get_field:null field\n");
      return(DBENG_OK);
      }

   if ((field = malloc(field_size + 1)) == NULL)
      {
      printf("c_get_field:alloc fail 'field'\n");
      return(DBENG_MEMORY_FAIL);
      }

   ret = db_get_field(tid, field_num, field);

   if (ret == DBENG_OK)
      printf("field=%s,l=%d\n", field, strlen(field));

   free(field);
   return(ret);
}

int c_get_subfield(char *comm)
{
   /* Get and display a subfield in the current record. Function returns
      the 'DBENG' status. Syntax:

         get.subfield tid field_num subfield_num */

   char *tid_char, *field_num_char, *subfield, mname[] = "c_get_subfield";
   char *subfield_num_char;
   int subfield_size, field_num, subfield_num, nwords, tid, len, ret;

   nwords = words(comm);

   if (nwords < 2)
      {
      printf("%s:missing tid\n", mname);
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("%s:missing field number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   if (nwords < 4)
      {
      printf("%s:missing sub-field number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("%s:unable to alloc 'tid_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("%s:non numeric tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("%s:invalid tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((field_num_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'field_num_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, field_num_char, 3);

   if (!qatoi(field_num_char, &field_num))
      {
      printf("%s:non numeric field number\n", mname);
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (field_num <= 0)
      {
      printf("%s:invalid field number\n", mname);
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(field_num_char);

   if ((subfield_num_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'subfield_num_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, subfield_num_char, 4);

   if (!qatoi(subfield_num_char, &subfield_num))
      {
      printf("%s:non numeric subfield number\n", mname);
      free(subfield_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (subfield_num <= 0)
      {
      printf("%s:invalid subfield number\n", mname);
      free(subfield_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(subfield_num_char);

   if ((ret = db_get_subfield_size(tid, field_num, subfield_num, 
                                   &subfield_size)) != DBENG_OK)
      return(ret);

   if (!subfield_size)
      {
      printf("c_get_field:empty subfield\n");
      return(DBENG_OK);
      }

   if ((subfield = (char *)malloc(subfield_size + 1)) == (char *)NULL)
      {
      printf("%s:alloc fail 'field'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   ret = db_get_subfield(tid, field_num, subfield_num, subfield);

   if (ret == DBENG_OK)
      printf("subfield=%s,l=%d\n", subfield, strlen(subfield));

   free(subfield);
   return(ret);
}

int c_get_subsubfield(char *comm)
{
   /* Get and display a subsubfield in the current record. Function returns
      the 'DBENG' status. Syntax:

         get.subsubfield tid field_num subfield_num subsubfield_num */

   char *tid_char, *field_num_char, mname[] = "c_get_subsubfield";
   char *subfield_num_char, *subsubfield_num_char, *subsubfield;
   int subsubfield_size, field_num, subfield_num; 
   int subsubfield_num, nwords, tid, len, ret;

   nwords = words(comm);

   if (nwords < 2)
      {
      printf("%s:missing tid\n", mname);
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("%s:missing field number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   if (nwords < 4)
      {
      printf("%s:missing subfield number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   if (nwords < 5)
      {
      printf("%s:missing subsubfield number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("%s:unable to alloc 'tid_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("%s:non numeric tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("%s:invalid tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((field_num_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'field_num_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, field_num_char, 3);

   if (!qatoi(field_num_char, &field_num))
      {
      printf("%s:non numeric field number\n", mname);
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (field_num <= 0)
      {
      printf("%s:invalid field number\n", mname);
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(field_num_char);

   if ((subfield_num_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'subfield_num_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, subfield_num_char, 4);

   if (!qatoi(subfield_num_char, &subfield_num))
      {
      printf("%s:non numeric subfield number\n", mname);
      free(subfield_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (subfield_num <= 0)
      {
      printf("%s:invalid subfield number\n", mname);
      free(subfield_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(subfield_num_char);

   if ((subsubfield_num_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'subsubfield_num_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, subsubfield_num_char, 5);

   if (!qatoi(subsubfield_num_char, &subsubfield_num))
      {
      printf("%s:non numeric subsubfield number\n", mname);
      free(subsubfield_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (subsubfield_num <= 0)
      {
      printf("%s:invalid subsubfield number\n", mname);
      free(subsubfield_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(subsubfield_num_char);

   if ((ret = db_get_subsubfield_size(tid, field_num, subfield_num, 
                                      subsubfield_num, &subsubfield_size)) 
        != DBENG_OK)
      return(ret);

   if (!subsubfield_size)
      {
      printf("c_get_field:empty subsubfield\n");
      return(DBENG_OK);
      }

   if ((subsubfield = (char *)malloc(subsubfield_size + 1)) == (char *)NULL)
      {
      printf("%s:alloc fail 'subsubfield'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   ret = db_get_subsubfield(tid, field_num, subfield_num, 
                            subsubfield_num, subsubfield);

   if (ret == DBENG_OK)
      printf("subsubfield=%s,l=%d\n", subsubfield, strlen(subsubfield));

   free(subsubfield);
   return(ret);
}

int c_goto(char *comm)
{
   /* Goto a specific record. Function returns the 'DBENG' status. Syntax:

         goto tid rec_num */

   char *tid_char;
   char *rec_num_char;
   long rec_num;
   int nwords;
   int tid;
   int len;
   int ret;

   nwords = words(comm);

   if (nwords < 2)
      {
      printf("c_goto:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("c_goto:missing record number\n");
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_goto:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_goto:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_goto:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((rec_num_char = malloc(len + 1)) == NULL)
      {
      printf("c_goto:alloc fail 'rec_num_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, rec_num_char, 3);

   if (!qatol(rec_num_char, &rec_num))
      {
      printf("c_goto:non numeric record number\n");
      free(rec_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (rec_num <= 0L)
      {
      printf("c_goto:invalid record number\n");
      free(rec_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   ret = db_goto(tid, rec_num);
   free(rec_num_char);
   return(ret);
}

int c_count(char *comm)
{
   /* Count records in a table. Function returns the 'DBENG' status. Syntax:

         count tid

      The number of active and deleted records will be displayed. */

   char *tid_char;
   long active_count, deleted_count;
   int nwords;
   int tid;
   int len;
   int ret;

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

   if (nwords < 2)
      {
      printf("c_count:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_count:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_count:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_count:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

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

   if (ret == DBENG_OK)
      printf("c_count:counted %ld active and %ld deleted record(s)\n", 
             active_count, deleted_count);

   return(ret);
}

int c_put_field(char *comm)
{
   /* Put a field into the record. Function returns the 'DBENG' status.
      Syntax:

         put.field tid field_num field_data

      Note that if the field data contains spaces, you must quote the
      data. */

   char *tid_char;
   char *field_num_char;
   char *field_data;
   int field_num;
   int nwords;
   int tid;
   int len;
   int ret;

   nwords = command_words(comm);

   if (nwords < 2)
      {
      printf("c_put_field:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("c_put_field:missing field number\n");
      return(DBENG_INVALID_FUNCTION);
      }

   if (nwords < 4)
      {
      printf("c_put_field:missing field data\n");
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_put_field:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_put_field:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_put_field:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((field_num_char = malloc(len + 1)) == NULL)
      {
      printf("c_put_field:alloc fail 'field_num_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, field_num_char, 3);

   if (!qatoi(field_num_char, &field_num))
      {
      printf("c_put_field:non numeric field number\n");
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (field_num < 0)
      {
      printf("c_put_field:invalid field number\n");
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(field_num_char);

   if ((field_data = malloc(len + 1)) == NULL)
      {
      printf("c_put_field:alloc fail 'field_data'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, field_data, 4);
   ret = db_put_field(tid, field_num, field_data);
   free(field_data);
   return(ret);
}

int c_put_subfield(char *comm)
{
   /* Put a subfield into the field. Function returns the 'DBENG' status.
      Syntax:

         put.subfield tid field_num subfield_num 'data1 data 2...'

      Note that if the subfield data contains spaces, you must quote the
      data. */

   char *tid_char, *field_num_char, *subfield_num_char, *subfield_data;
   char mname[] = "c_put_subfield";
   int field_num, subfield_num, nwords, tid, len, ret;

   nwords = command_words(comm);

   if (nwords < 2)
      {
      printf("%s:missing tid\n", mname);
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("%s:missing field number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   if (nwords < 4)
      {
      printf("%s:missing subfield number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   if (nwords < 5)
      {
      printf("%s:missing subfield data\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("%s:unable to alloc 'tid_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("%s:non numeric tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("%s:invalid tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((field_num_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'field_num_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, field_num_char, 3);

   if (!qatoi(field_num_char, &field_num))
      {
      printf("%s:non numeric field number\n", mname);
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (field_num < 0)
      {
      printf("%s:invalid field number\n", mname);
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(field_num_char);

   if ((subfield_num_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'subfield_num_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, subfield_num_char, 4);

   if (!qatoi(subfield_num_char, &subfield_num))
      {
      printf("%s:non numeric sub-field number\n", mname);
      free(subfield_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (subfield_num < 0)
      {
      printf("%s:invalid sub-field number\n", mname);
      free(subfield_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(subfield_num_char);

   if ((subfield_data = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'subfield_data'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, subfield_data, 5);
   ret = db_put_subfield(tid, field_num, subfield_num, subfield_data);
   free(subfield_data);
   return(ret);
}

int c_put_subsubfield(char *comm)
{
   /* Put a subsubfield into the field. Function returns the 'DBENG' status.
      Syntax:

         put.subfield tid field_num subfield_num subsubfield_num 'd1 d2...'

      Note that if the data contains spaces, you must quote the
      data. */

   char *tid_char, *field_num_char, *subfield_num_char, *subsubfield_data;
   char mname[] = "c_put_subsubfield", *subsubfield_num_char;
   int field_num, subfield_num, subsubfield_num, nwords, tid, len, ret;

   nwords = command_words(comm);

   if (nwords < 2)
      {
      printf("%s:missing tid\n", mname);
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("%s:missing field number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   if (nwords < 4)
      {
      printf("%s:missing subfield number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   if (nwords < 5)
      {
      printf("%s:missing subsubfield number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   if (nwords < 6)
      {
      printf("%s:missing subsubfield data\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("%s:unable to alloc 'tid_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("%s:non numeric tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("%s:invalid tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((field_num_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'field_num_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, field_num_char, 3);

   if (!qatoi(field_num_char, &field_num))
      {
      printf("%s:non numeric field number\n", mname);
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (field_num < 0)
      {
      printf("%s:invalid field number\n", mname);
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(field_num_char);

   if ((subfield_num_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'subfield_num_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, subfield_num_char, 4);

   if (!qatoi(subfield_num_char, &subfield_num))
      {
      printf("%s:non numeric subfield number\n", mname);
      free(subfield_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (subfield_num < 0)
      {
      printf("%s:invalid subfield number\n", mname);
      free(subfield_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(subfield_num_char);

   if ((subsubfield_num_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'subsubfield_num_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, subsubfield_num_char, 5);

   if (!qatoi(subsubfield_num_char, &subsubfield_num))
      {
      printf("%s:non numeric subsubfield number\n", mname);
      free(subsubfield_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (subsubfield_num < 0)
      {
      printf("%s:invalid subsubfield number\n", mname);
      free(subsubfield_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(subsubfield_num_char);

   if ((subsubfield_data = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'subsubfield_data'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, subsubfield_data, 6);
   ret = db_put_subsubfield(tid, field_num, subfield_num, subsubfield_num,
                            subsubfield_data);
   free(subsubfield_data);
   return(ret);
}

int c_write(char *comm)
{
   /* Write the current record to the table. Function returns the 'DBENG'
      status. Syntax:

         write tid */

   char *tid_char;
   int tid;
   int len;

   if (words(comm) < 2)
      {
      printf("c_write:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_write:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_write:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_write:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);
   return(db_write(tid));
}

int c_delete(char *comm)
{
   /* Delete the current record. Function returns the 'DBENG'
      status. Syntax:

         delete tid */

   char *tid_char;
   int tid;
   int len;

   if (words(comm) < 2)
      {
      printf("c_delete:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_delete:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_delete:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_delete:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);
   return(db_delete(tid));
}

int c_get_delete_flag(char *comm)
{
   /* Get the current tables' 'process_deleted' flag. Function returns
      the 'DBENG' status. Flag value is displayed on the screen upon
      success. Syntax:

         get.delete.flag tid */

   char *tid_char;
   int tid;
   int len;
   int ret;
   int flag;

   if (words(comm) < 2)
      {
      printf("c_get_delete_flag:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_get_delete_flag:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_get_delete_flag:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_get_delete_flag:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);
   ret = db_get_delete_flag(tid, &flag);

   if (ret == DBENG_OK)
      printf("c_get_delete_flag:'process_deleted' is %d\n", flag);

   return(ret);
}

int c_set_delete_flag(char *comm)
{
   /* Set the current tables' 'process_deleted' flag. Function returns
      the 'DBENG' status. Note that 'flag_value' must be '0' or '1'.
      Syntax:

         set.delete.flag tid flag_value */

   char *tid_char;
   char *flag_char;
   int delete_flag;
   int nwords;
   int tid;
   int len;
   int ret;

   nwords = words(comm);

   if (nwords < 2)
      {
      printf("c_set_delete_flag:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("c_set_delete_flag:missing flag value\n");
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_set_delete_flag:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_set_delete_flag:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_set_delete_flag:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((flag_char = malloc(len + 1)) == NULL)
      {
      printf("c_set_delete_flag:alloc fail 'flag_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, flag_char, 3);

   if (!qatoi(flag_char, &delete_flag))
      {
      printf("c_set_delete_flag:non numeric flag value, must be '0' or '1'\n");
      free(flag_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (delete_flag < 0 || delete_flag > 1)
      {
      printf("c_set_delete_flag:invalid flag value, must be '0' or '1'\n");
      free(flag_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(flag_char);
   ret = db_set_delete_flag(tid, delete_flag);
   return(ret);
}

int c_get_nfields(char *comm)
{
   /* Get the number of fields in the current record. Function returns
      the 'DBENG' status. The number of fields is displayed on the screen
      upon success. Syntax:

         get.nfields tid */

   char *tid_char;
   int tid;
   int len;
   int ret;
   int nfields;

   if (words(comm) < 2)
      {
      printf("c_get_nfields:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_get_nfields:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_get_nfields:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_get_nfields:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);
   ret = db_get_nfields(tid, &nfields);

   if (ret == DBENG_OK)
      printf("c_get_nfields:nfields is %d\n", nfields);

   return(ret);
}

int c_get_nsubfields(char *comm)
{
   /* Get the number of subfields in a field. Function returns
      the 'DBENG' status. The number of subfields is displayed 
      on the screen upon success. Syntax:

         get.nsubfields tid field_num */

   char *tid_char, *field_num_char, mname[] = "c_get_nsubfields";
   int tid, len, ret;
   int nwords, nsubfields, field_num;

   nwords = words(comm);

   if (nwords < 2)
      {
      printf("%s:missing tid\n", mname);
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("%s:missing field number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("%s:unable to alloc 'tid_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("%s:non numeric tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("%s:invalid tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((field_num_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'field_num_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, field_num_char, 3);

   if (!qatoi(field_num_char, &field_num))
      {
      printf("%s:non numeric field number\n", mname);
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (field_num <= 0)
      {
      printf("%s:invalid field number\n", mname);
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(field_num_char);
   ret = db_get_nsubfields(tid, field_num, &nsubfields);

   if (ret == DBENG_OK)
      printf("%s:nsubfields is %d\n", mname, nsubfields);

   return(ret);
}

int c_get_nsubsubfields(char *comm)
{
   /* Get the number of subsubfields in a subfield. Function returns
      the 'DBENG' status. The number of subsubfields is displayed 
      on the screen upon success. Syntax:

         get.nsubsubfields tid field_num subfield_num */

   char *tid_char, *field_num_char, *subfield_num_char;
   char mname[] = "c_get_nsubsubfields";
   int tid, len, ret;
   int nwords, nsubsubfields, field_num, subfield_num;

   nwords = words(comm);

   if (nwords < 2)
      {
      printf("%s:missing tid\n", mname);
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("%s:missing field number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   if (nwords < 4)
      {
      printf("%s:missing subfield number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("%s:unable to alloc 'tid_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("%s:non numeric tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("%s:invalid tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((field_num_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'field_num_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, field_num_char, 3);

   if (!qatoi(field_num_char, &field_num))
      {
      printf("%s:non numeric field number\n", mname);
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (field_num <= 0)
      {
      printf("%s:invalid field number\n", mname);
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(field_num_char);

   if ((subfield_num_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'sub_field_num_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, subfield_num_char, 4);

   if (!qatoi(subfield_num_char, &subfield_num))
      {
      printf("%s:non numeric subfield number\n", mname);
      free(subfield_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (subfield_num <= 0)
      {
      printf("%s:invalid subfield number\n", mname);
      free(subfield_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(subfield_num_char);
   ret = db_get_nsubsubfields(tid, field_num, subfield_num, &nsubsubfields);

   if (ret == DBENG_OK)
      printf("%s:nsubsubfields is %d\n", mname, nsubsubfields);

   return(ret);
}

int c_get_rec_size(char *comm)
{
   /* Get the size of the current record. Function returns
      the 'DBENG' status. The record size is displayed on the screen
      upon success. Syntax:

         get.rec.size tid */

   char *tid_char;
   int tid;
   int len;
   int ret;
   int rec_size;

   if (words(comm) < 2)
      {
      printf("c_get_rec_size:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_get_rec_size:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_get_rec_size:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_get_rec_size:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

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

   if (ret == DBENG_OK)
      printf("c_get_rec_size:record size is %d bytes\n", rec_size);

   return(ret);
}

int c_get_field_size(char *comm)
{
   /* Get and display a field size in the current record. Function returns
      the 'DBENG' status. Syntax:

         get.field.size tid field_num */

   char *tid_char;
   char *field_num_char;
   int field_size;
   int field_num;
   int nwords;
   int tid;
   int len;
   int ret;

   nwords = words(comm);

   if (nwords < 2)
      {
      printf("c_get_field_size:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("get_get_field_size:missing field number\n");
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_get_field_size:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_get_field_size:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_get_field_size:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((field_num_char = malloc(len + 1)) == NULL)
      {
      printf("c_get_field_size:alloc fail 'field_num_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, field_num_char, 3);

   if (!qatoi(field_num_char, &field_num))
      {
      printf("c_get_field_size:non numeric field number\n");
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (field_num <= 0)
      {
      printf("c_get_field_size:invalid field number\n");
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(field_num_char);
   ret = db_get_field_size(tid, field_num, &field_size);

   if (ret == DBENG_OK)
      printf("c_get_field_size:field[%d] size=%d\n", field_num, field_size);

   return(ret);
}

int c_get_subfield_size(char *comm)
{
   /* Get the size of a subfield in a field. Function returns
      the 'DBENG' status. The subfield size is displayed 
      on the screen upon success. Syntax:

         get.subfield.size tid field_num subfield_num */

   char *tid_char, *field_num_char, mname[] = "c_get_subfield_size";
   char *subfield_num_char;
   int tid, len, ret;
   int nwords, subfield_size, field_num, subfield_num;

   nwords = words(comm);

   if (nwords < 2)
      {
      printf("%s:missing tid\n", mname);
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("%s:missing field number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   if (nwords < 4)
      {
      printf("%s:missing subfield number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("%s:unable to alloc 'tid_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("%s:non numeric tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("%s:invalid tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((field_num_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'field_num_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, field_num_char, 3);

   if (!qatoi(field_num_char, &field_num))
      {
      printf("%s:non numeric field number\n", mname);
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (field_num <= 0)
      {
      printf("%s:invalid field number\n", mname);
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(field_num_char);

   if ((subfield_num_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'subfield_num_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, subfield_num_char, 4);

   if (!qatoi(subfield_num_char, &subfield_num))
      {
      printf("%s:non numeric subfield number\n", mname);
      free(subfield_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (subfield_num <= 0)
      {
      printf("%s:invalid subfield number\n", mname);
      free(subfield_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(subfield_num_char);
   ret = db_get_subfield_size(tid, field_num, subfield_num, &subfield_size);

   if (ret == DBENG_OK)
      printf("%s:subfield size is %d\n", mname, subfield_size);

   return(ret);
}

int c_get_subsubfield_size(char *comm)
{
   /* Get the size of a subsubfield in a subfield. Function returns
      the 'DBENG' status. The subsubfield size is displayed 
      on the screen upon success. Syntax:

         get.subsubfield.size tid field_num subfield_num subsubfield_num */

   char *tid_char, *field_num_char, mname[] = "c_get_subsubfield_size";
   char *subfield_num_char, *subsubfield_num_char;
   int tid, len, ret;
   int nwords, subsubfield_size, field_num, subfield_num, subsubfield_num;

   nwords = words(comm);

   if (nwords < 2)
      {
      printf("%s:missing tid\n", mname);
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("%s:missing field number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   if (nwords < 4)
      {
      printf("%s:missing subfield number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   if (nwords < 5)
      {
      printf("%s:missing subsubfield number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("%s:unable to alloc 'tid_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("%s:non numeric tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("%s:invalid tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((field_num_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'field_num_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, field_num_char, 3);

   if (!qatoi(field_num_char, &field_num))
      {
      printf("%s:non numeric field number\n", mname);
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (field_num <= 0)
      {
      printf("%s:invalid field number\n", mname);
      free(field_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(field_num_char);

   if ((subfield_num_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'subfield_num_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, subfield_num_char, 4);

   if (!qatoi(subfield_num_char, &subfield_num))
      {
      printf("%s:non numeric subfield number\n", mname);
      free(subfield_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (subfield_num <= 0)
      {
      printf("%s:invalid subfield number\n", mname);
      free(subfield_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(subfield_num_char);

   if ((subsubfield_num_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'subsubfield_num_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, subfield_num_char, 5);

   if (!qatoi(subsubfield_num_char, &subsubfield_num))
      {
      printf("%s:non numeric subsubfield number\n", mname);
      free(subsubfield_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (subsubfield_num <= 0)
      {
      printf("%s:invalid subsubfield number\n", mname);
      free(subsubfield_num_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(subsubfield_num_char);
   ret = db_get_subsubfield_size(tid, field_num, subfield_num, subsubfield_num,
                                 &subsubfield_size);

   if (ret == DBENG_OK)
      printf("%s:subsubfield size is %d\n", mname, subsubfield_size);

   return(ret);
}

int c_get_rec_num(char *comm)
{
   /* Get the current record number. Function returns
      the 'DBENG' status. The current record number is displayed on the screen
      upon success. Syntax:

         get.rec.num tid */

   char *tid_char;
   long rec_num;
   int tid;
   int len;
   int ret;

   if (words(comm) < 2)
      {
      printf("c_get_rec_num:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_get_rec_num:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_get_rec_num:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_get_rec_num:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);
   ret = db_get_rec_num(tid, &rec_num);

   if (ret == DBENG_OK)
      printf("c_get_rec_num:record number is %ld\n", rec_num);

   return(ret);
}

int c_get_pos(char *comm)
{
   /* Get the current file position from the beginning. Function returns
      the 'DBENG' status. The file position is displayed on the screen
      upon success. Syntax:

         get.pos tid */

   char *tid_char;
   long pos;
   int tid;
   int len;
   int ret;

   if (words(comm) < 2)
      {
      printf("c_get_pos:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_get_pos:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_get_pos:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_get_pos:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);
   ret = db_get_pos(tid, &pos);

   if (ret == DBENG_OK)
      printf("c_get_pos:file position is %ld\n", pos);

   return(ret);
}

int c_set_pos(char *comm)
{
   /* Set the table file position. Function returns the 'DBENG' status.
      Syntax:

         set.pos tid filepos */

   char *tid_char;
   char *file_pos_char;
   long file_pos;
   int nwords;
   int tid;
   int len;
   int ret;

   nwords = command_words(comm);

   if (nwords < 2)
      {
      printf("c_set_pos:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("c_set_pos:missing file position\n");
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_set_pos:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_set_pos:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_set_pos:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((file_pos_char = malloc(len + 1)) == NULL)
      {
      printf("c_set_pos:alloc fail 'file_pos_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, file_pos_char, 3);

   if (!qatol(file_pos_char, &file_pos))
      {
      printf("c_set_pos:non numeric file position\n");
      free(file_pos_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (file_pos < 0L)
      {
      printf("c_set_pos:invalid file position\n");
      free(file_pos_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(file_pos_char);
   ret = db_set_pos(tid, file_pos);
   return(ret);
}

int c_get_change_rec_flag(char *comm)
{
   /* Get the current value of 'change_rec_flag'. Function returns
      the 'DBENG' status. The flag value is displayed on the screen
      upon success. Syntax:

         get.change.rec.flag tid */

   char *tid_char;
   int change_rec_flag;
   int tid;
   int len;
   int ret;

   if (words(comm) < 2)
      {
      printf("c_get_change_rec_flag:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_get_change_rec_flag:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_get_change_rec_flag:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_get_change_rec_flag:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);
   ret = db_get_change_rec_flag(tid, &change_rec_flag);

   if (ret == DBENG_OK)
      printf("c_get_change_rec_flag:flag is %d\n", change_rec_flag);

   return(ret);
}

int c_set_change_rec_flag(char *comm)
{
   /* Set the current tables' 'change_rec_flag'. Function returns
      the 'DBENG' status. Note that 'flag_value' must be '0' or '1'.
      Syntax:

         set.change.rec.flag tid flag_value */

   char *tid_char;
   char *flag_char;
   int delete_flag;
   int nwords;
   int tid;
   int len;
   int ret;

   nwords = words(comm);

   if (nwords < 2)
      {
      printf("c_set_change_rec_flag:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("c_set_change_rec_flag:missing flag value\n");
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_set_change_rec_flag:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_set_change_rec_flag:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_set_change_rec_flag:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((flag_char = malloc(len + 1)) == NULL)
      {
      printf("c_set_change_rec_flag:alloc fail 'flag_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, flag_char, 3);

   if (!qatoi(flag_char, &delete_flag))
      {
      printf("c_set_change_rec_flag:non numeric flag value, must be '0' "
             "or '1'\n");
      free(flag_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (delete_flag < 0 || delete_flag > 1)
      {
      printf("c_set_change_rec_flag:invalid flag value, must be '0' or '1'\n");
      free(flag_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(flag_char);
   ret = db_set_change_rec_flag(tid, delete_flag);
   return(ret);
}

int c_pack(char *comm)
{
   /* Pack a table. Function returns the 'DBENG' status. Syntax:

         pack tid */

   char *tid_char;
   int tid;
   int len;

   if (words(comm) < 2)
      {
      printf("c_pack:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_pack:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_pack:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_pack:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);
   return(db_pack(tid));
}

int c_new(char *comm)
{
   /* Declare/start a new record. Function returns the 'DBENG' status.
      Syntax:

         new tid */

   char *tid_char;
   int tid;
   int len;

   if (words(comm) < 2)
      {
      printf("c_new:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_new:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_new:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_new:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);
   return(db_new(tid));
}

int c_find(char *comm)
{
   /* Find field. All whole fields will be searched from (and including)
      the current record. String comparison is case insensitive unless
      a 'case_flag' is supplied ('1' for insensitive, '0' for sensitive).
      Function returns the 'DBENG' status. Syntax:

         find tid 'string' [case_flag] */

   char *tid_char;
   char *flag_char;
   char *findstr;
   int case_flag = TRUE;
   int field_num;
   int nwords;
   int tid;
   int len;
   int ret;

   nwords = command_words(comm);

   if (nwords < 2)
      {
      printf("c_find:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("c_find:missing search string\n");
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_find:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_find:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_find:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if (nwords > 3)
      {
      /* get the case flag */

      if ((flag_char = malloc(len + 1)) == NULL)
         {
         printf("c_find:alloc fail 'flag_char'\n");
         return(DBENG_MEMORY_FAIL);
         }

      (void)command_word(comm, flag_char, 4);

      if (!qatoi(flag_char, &case_flag))
         {
         printf("c_find:non numeric flag value, must be '0' or '1'\n");
         free(flag_char);
         return(DBENG_INVALID_FUNCTION);
         }

      if (case_flag < 0 || case_flag > 1)
         {
         printf("c_find:invalid flag value, must be '0' or '1'\n");
         free(flag_char);
         return(DBENG_INVALID_FUNCTION);
         }

      free(flag_char);
      }

   if ((findstr = malloc(len + 1)) == NULL)
      {
      printf("c_find:unable to alloc 'findstr'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, findstr, 3);
   ret = db_find(tid, case_flag, findstr, &field_num);
   free(findstr);

   if (ret == DBENG_OK)
      printf("c_find:match found in field %d\n", field_num);

   return(ret);
}

int c_find_field(char *comm)
{
   /* Find field. A single whole field will be searched from (and including)
      the current record. String comparison is case insensitive unless
      a 'case_flag' is supplied ('1' for insensitive, '0' for sensitive).
      Function returns the 'DBENG' status. Syntax:

         find.field tid field_num 'string' [case_flag] */

   char *tid_char;
   char *fnum_char;
   char *flag_char;
   char *findstr;
   int case_flag = TRUE;
   int field_num;
   int nwords;
   int tid;
   int len;
   int ret;

   nwords = command_words(comm);

   if (nwords < 2)
      {
      printf("c_find_field:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("c_find_field:missing field number\n");
      return(DBENG_INVALID_FUNCTION);
      }

   if (nwords < 4)
      {
      printf("c_find_field:missing search string\n");
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_find_field:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_find_field:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_find_field:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((fnum_char = malloc(len + 1)) == NULL)
      {
      printf("c_find_field:unable to alloc 'fnum_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, fnum_char, 3);

   if (!qatoi(fnum_char, &field_num))
      {
      printf("c_find_field:non numeric field number\n");
      free(fnum_char);
      return(DBENG_NO_SUCH_FIELD);
      }

   if (field_num <= 0)
      {
      printf("c_find_field:invalid field number\n");
      free(fnum_char);
      return(DBENG_NO_SUCH_FIELD);
      }

   free(fnum_char);

   if (nwords > 4)
      {
      /* get the case flag */

      if ((flag_char = malloc(len + 1)) == NULL)
         {
         printf("c_find_field:alloc fail 'flag_char'\n");
         return(DBENG_MEMORY_FAIL);
         }

      (void)command_word(comm, flag_char, 5);

      if (!qatoi(flag_char, &case_flag))
         {
         printf("c_find_field:non numeric flag value, must be '0' or '1'\n");
         free(flag_char);
         return(DBENG_INVALID_FUNCTION);
         }

      if (case_flag < 0 || case_flag > 1)
         {
         printf("c_find_field:invalid flag value, must be '0' or '1'\n");
         free(flag_char);
         return(DBENG_INVALID_FUNCTION);
         }

      free(flag_char);
      }

   if ((findstr = malloc(len + 1)) == NULL)
      {
      printf("c_find_field:unable to alloc 'findstr'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, findstr, 4);
   ret = db_find_field(tid, case_flag, findstr, field_num);
   free(findstr);

   if (ret == DBENG_OK)
      printf("c_find_field:match found\n");

   return(ret);
}

int c_find_part(char *comm)
{
   /* Find field. Any part of all fields will be searched from (and including)
      the current record. String comparison is case insensitive unless
      a 'case_flag' is supplied ('1' for insensitive, '0' for sensitive).
      Function returns the 'DBENG' status. Syntax:

         find.part tid 'string' [case_flag] */

   char *tid_char;
   char *flag_char;
   char *findstr;
   int case_flag = TRUE;
   int field_num;
   int nwords;
   int tid;
   int len;
   int ret;

   nwords = command_words(comm);

   if (nwords < 2)
      {
      printf("c_find_part:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("c_find_part:missing search string\n");
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_find_part:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_find_part:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_find_part:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if (nwords > 3)
      {
      /* get the case flag */

      if ((flag_char = malloc(len + 1)) == NULL)
         {
         printf("c_find_part:alloc fail 'flag_char'\n");
         return(DBENG_MEMORY_FAIL);
         }

      (void)command_word(comm, flag_char, 4);

      if (!qatoi(flag_char, &case_flag))
         {
         printf("c_find_part:non numeric flag value, must be '0' or '1'\n");
         free(flag_char);
         return(DBENG_INVALID_FUNCTION);
         }

      if (case_flag < 0 || case_flag > 1)
         {
         printf("c_find_part:invalid flag value, must be '0' or '1'\n");
         free(flag_char);
         return(DBENG_INVALID_FUNCTION);
         }

      free(flag_char);
      }

   if ((findstr = malloc(len + 1)) == NULL)
      {
      printf("c_find_part:unable to alloc 'findstr'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, findstr, 3);
   ret = db_find_part(tid, case_flag, findstr, &field_num);
   free(findstr);

   if (ret == DBENG_OK)
      printf("c_find_part:match found in field %d\n", field_num);

   return(ret);
}

int c_find_field_part(char *comm)
{
   /* Find field. Any part of a single field will be searched from (and
      including) the current record. String comparison is case insensitive
      unless a 'case_flag' is supplied ('1' for insensitive, '0' for
      sensitive). Function returns the 'DBENG' status. Syntax:

         find.field.part tid field_num 'string' [case_flag] */

   char *tid_char;
   char *fnum_char;
   char *flag_char;
   char *findstr;
   int case_flag = TRUE;
   int field_num;
   int nwords;
   int tid;
   int len;
   int ret;

   nwords = command_words(comm);

   if (nwords < 2)
      {
      printf("c_find_field_part:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("c_find_field_part:missing field number\n");
      return(DBENG_INVALID_FUNCTION);
      }

   if (nwords < 4)
      {
      printf("c_find_field_part:missing search string\n");
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_find_field_part:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_find_field_part:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_find_field_part:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((fnum_char = malloc(len + 1)) == NULL)
      {
      printf("c_find_field_part:unable to alloc 'fnum_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, fnum_char, 3);

   if (!qatoi(fnum_char, &field_num))
      {
      printf("c_find_field_part:non numeric field number\n");
      free(fnum_char);
      return(DBENG_NO_SUCH_FIELD);
      }

   if (field_num <= 0)
      {
      printf("c_find_field_part:invalid field number\n");
      free(fnum_char);
      return(DBENG_NO_SUCH_FIELD);
      }

   free(fnum_char);

   if (nwords > 4)
      {
      /* get the case flag */

      if ((flag_char = malloc(len + 1)) == NULL)
         {
         printf("c_find_field_part:alloc fail 'flag_char'\n");
         return(DBENG_MEMORY_FAIL);
         }

      (void)command_word(comm, flag_char, 5);

      if (!qatoi(flag_char, &case_flag))
         {
         printf("c_find_field_part:non numeric flag value, must be '0'"
                " or '1'\n");
         free(flag_char);
         return(DBENG_INVALID_FUNCTION);
         }

      if (case_flag < 0 || case_flag > 1)
         {
         printf("c_find_field_part:invalid flag value, must be '0' or '1'\n");
         free(flag_char);
         return(DBENG_INVALID_FUNCTION);
         }

      free(flag_char);
      }

   if ((findstr = malloc(len + 1)) == NULL)
      {
      printf("c_find_field_part:unable to alloc 'findstr'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, findstr, 4);
   ret = db_find_field_part(tid, case_flag, findstr, field_num);
   free(findstr);

   if (ret == DBENG_OK)
      printf("c_find_field_part:match found\n");

   return(ret);
}

int c_get_rec_count(char *comm)
{
   /* Get the current record count. Note that records are not counted.
      Function returns the 'DBENG' status. The number of records is 
      displayed on the screen upon success. Syntax:

         get.rec.count tid */

   char *tid_char;
   long active_count, deleted_count;
   int tid;
   int len;
   int ret;

   if (words(comm) < 2)
      {
      printf("c_get_rec_count:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_get_rec_count:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_get_rec_count:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_get_rec_count:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

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

   if (ret == DBENG_OK)
      printf("c_get_rec_count:table contains %ld active and %ld deleted"
             " record(s)\n", active_count, deleted_count);

   return(ret);
}

int c_get_enf_change_rec_flag(char *comm)
{
   /* Get the table 'enf_change_rec_flag'. Function returns
      the 'DBENG' status. The flag value is displayed on the screen
      upon success. Syntax:

         get.enf.change.rec.flag tid */

   char *tid_char;
   int flag;
   int tid;
   int len;
   int ret;

   if (words(comm) < 2)
      {
      printf("c_get_enf_change_rec_flag:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_get_enf_change_rec_flag:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_get_enf_change_rec_flag:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_get_enf_change_rec_flag:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);
   ret = db_get_enf_change_rec_flag(tid, &flag);

   if (ret == DBENG_OK)
      printf("c_get_enf_change_rec_flag:flag is %d\n", flag);

   return(ret);
}

int c_set_enf_change_rec_flag(char *comm)
{
   /* Set the table 'enf_change_rec_flag'. 'flag_value' must be
      '0' or '1'. Function returns the 'DBENG' status. Syntax:

         set.enf.change.rec.flag tid flag_value */

   char *tid_char;
   char *flag_char;
   int flag;
   int tid;
   int len;
   int nwords;

   nwords = words(comm);

   if (nwords < 2)
      {
      printf("c_set_enf_change_rec_flag:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("c_set_enf_change_rec_flag:missing flag value\n");
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_set_enf_change_rec_flag:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_set_enf_change_rec_flag:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_set_enf_change_rec_flag:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((flag_char = malloc(len + 1)) == NULL)
      {
      printf("c_set_enf_change_rec_flag:alloc fail 'flag_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, flag_char, 3);

   if (!qatoi(flag_char, &flag))
      {
      printf("c_set_end_change_rec_flag:non numeric flag value, must be '0'"
             " or '1'\n");
      free(flag_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (flag < 0 || flag > 1)
      {
      printf("c_set_enf_change_rec_flag:invalid flag value, must be '0' or"
             " '1'\n");
      free(flag_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(flag_char);
   return(db_set_enf_change_rec_flag(tid, flag));
}

int c_get_is_table_locked(char *comm)
{
   /* Get the table 'is_table_locked' flag. Function returns
      the 'DBENG' status. The flag value is displayed on the screen
      upon success. Syntax:

         get.is.table.locked tid */

   char *tid_char;
   int flag;
   int tid;
   int len;
   int ret;

   if (words(comm) < 2)
      {
      printf("c_get_is_table_locked:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_get_is_table_locked:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_get_is_table_locked:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_get_is_table_locked:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);
   ret = db_get_is_table_locked(tid, &flag);

   if (ret == DBENG_OK)
      printf("c_get_is_table_locked:flag is %d\n", flag);

   return(ret);
}

int c_set_is_table_locked(char *comm)
{
   /* Set the table 'is_table_locked' flag. 'flag_value' must be
      '0' or '1'. Function returns the 'DBENG' status. Syntax:

         set.is.table.locked tid flag_value */

   char *tid_char;
   char *flag_char;
   int flag;
   int tid;
   int len;
   int nwords;

   nwords = words(comm);

   if (nwords < 2)
      {
      printf("c_set_is_table_locked:missing tid\n");
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("c_set_is_table_locked:missing flag value\n");
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_set_is_table_locked:unable to alloc 'tid_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_set_is_table_locked:non numeric tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("c_set_is_table_locked:invalid tid\n");
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((flag_char = malloc(len + 1)) == NULL)
      {
      printf("c_set_is_table_locked:alloc fail 'flag_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, flag_char, 3);

   if (!qatoi(flag_char, &flag))
      {
      printf("c_set_is_table_locked:non numeric flag value, must be '0'"
             " or '1'\n");
      free(flag_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (flag < 0 || flag > 1)
      {
      printf("c_set_is_table_locked:invalid flag value, must be '0' or"
             " '1'\n");
      free(flag_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(flag_char);
   return(db_set_is_table_locked(tid, flag));
}

int c_new_table(char *comm)
{
   /* Create a new table. The file name is expected on the command line.
      If 'tid_flag' is a positive number, the table will be opened.
      Function returns the 'DBENG' status. Syntax:

         new.table file_name tid_flag

      Note that the returned 'tid' is printed on the screen. */

   char *fname, *tid_char;
   int nwords, tid, len, ret, should_open;

   nwords = command_words(comm);

   /* must be at least three words on command line */

   if (nwords < 2)
      {
      printf("c_new_table:missing file name\n");
      return(DBENG_INVALID_FILE_NAME);
      }

   if (nwords < 3)
      {
      printf("c_new_table:missing tid flag\n");
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((fname = malloc(len + 1)) == NULL)
      {
      printf("c_new_table:unable to alloc 'fname'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, fname, 2);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("c_new_table:unable to alloc 'tid_char'\n");
      free(fname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, tid_char, 3);

   if (!qatoi(tid_char, &tid))
      {
      printf("c_new_table:non numeric tid flag\n");
      free(fname);
      free(tid_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(tid_char);
   should_open = (tid > 0) ? TRUE : FALSE;
      
   ret = db_new_table(fname, &tid);

   if (ret == DBENG_OK && should_open)
      printf("tid is %d\n", tid);

   free(fname);
   return(ret);
}

int c_config_get_tmp_path(void)
{
   /* Display the current temporary file path.
      Syntax:

         config.get.tmp.path

      Function returns 'DBENG_OK' upon success,
      an engine i/o code otherwise. */

   int ret;
   char tmp_path[DBENG_PATH_LIMIT];

   ret = db_config_get_tmp_path(tmp_path);

   if (ret == DBENG_OK)
      printf("path for temp files is '%s'\n", tmp_path);

   return(ret);
}

int c_config_get_log(void)
{
   /* Display the current log name/destination.
      Syntax:

         config.get.log

      Function returns 'DBENG_OK' upon success,
      an engine i/o code otherwise. */

   int ret;
   char slog[DBENG_PATH_LIMIT];

   ret = db_config_get_log(slog);

   if (ret == DBENG_OK)
      printf("log is '%s'\n", slog);

   return(ret);
}

int c_config_get_session(void)
{
   /* Get the current path/file for the system session
      table. Note that the session table is only used
      in multiuser mode. Syntax:

         config.get.session

      Function returns 'DBENG_OK' upon success, an engine
      i/o code otherwise. */

#ifdef MULTIUSER
   char ses_table[DBENG_PATH_LIMIT];
   int ret;

   ret = db_config_get_session(ses_table);

   if (ret == DBENG_OK)
      printf("system session table is '%s'\n", ses_table);

   return(ret);
#else
   printf("session table is only active in multiuser mode\n");
   return(DBENG_OK);
#endif
}

int c_config_get_catalog(void)
{
   /* Get the current path/file for the system catalog.
      Syntax:

         config.get.catalog

      Function returns 'DBENG_OK' upon success, an engine
      i/o code otherwise. */

   char cat[DBENG_PATH_LIMIT];
   int ret;

   ret = db_config_get_catalog(cat);

   if (ret == DBENG_OK)
      printf("catalog is '%s'\n", cat);

   return(ret);
}

int c_config_get_log_flag(void)
{
   /* Get the log flag. Syntax:

         config.get.log.flag

      Function returns 'DBENG_OK' upon success, an engine
      i/o code otherwise. */

   char flag_ch[4];
   int flag;
   int ret;

   ret = db_config_get_log_flag(&flag);

   if (ret == DBENG_OK)
      if (flag_2_logic_string(flag, flag_ch))
         printf("logging is %s\n", flag_ch);

   return(ret);
}

int c_config_get_session_flag(void)
{
   /* Get the engine session table flag. Syntax:

         config.get.session.flag

      Function returns 'DBENG_OK' upon success, an engine
      i/o code otherwise. */

   char flag_ch[4];
   int flag;
   int ret;

   ret = db_config_get_session_flag(&flag);

   if (ret == DBENG_OK)
      if (flag_2_logic_string(flag, flag_ch))
         printf("session table is %s\n", flag_ch);

   return(ret);
}

int c_config_get_catalog_flag(void)
{
   /* Get the engine catalog flag. Syntax:

         config.get.catalog.flag

      Function returns 'DBENG_OK' upon success, an engine
      i/o code otherwise. */

   char flag_ch[4];
   int flag;
   int ret;

   ret = db_config_get_catalog_flag(&flag);

   if (ret == DBENG_OK)
      if (flag_2_logic_string(flag, flag_ch))
         printf("catalog is %s\n", flag_ch);

   return(ret);
}

int c_config_get_replicate_flag(void)
{
   /* Get the engine replication flag. Syntax:

         config.get.replicate.flag

      Function returns 'DBENG_OK' upon success, an engine
      i/o code otherwise. */

   char flag_ch[4];
   int flag;
   int ret;

   ret = db_config_get_replicate_flag(&flag);

   if (ret == DBENG_OK)
      if (flag_2_logic_string(flag, flag_ch))
         printf("replication is %s\n", flag_ch);

   return(ret);
}

int c_config_get_version(void)
{
   /* Get the current 'dbeng' version ID string.
      Syntax:

         config.get.version

      Function returns 'DBENG_OK' upon success, an engine
      i/o code otherwise. */

   char ver[128];
   int ret;

   ret = db_config_get_version(ver);

   if (ret == DBENG_OK)
      printf("current 'Bbuuzzb' database engine version is %s\n", ver);

   return(ret);
}

int c_version(void)
{
   /* Get the current client and server (if in multiuser mode)
      version string.
      Syntax:

         version

      Function returns 'DBENG_OK' upon success, an engine
      i/o code otherwise. */

   char ver[128];
   int ret;

   printf("current client version is %s\n", VERSION);

#ifdef MULTIUSER
   ret = db_version(ver);

   if (ret == DBENG_OK)
      printf("current 'Bbuuzzb' server version is %s\n", ver);
#else
   ret = DBENG_OK;
#endif

   return(ret);
}

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

         config.set.tmp.path tmp_path

      Function returns 'DBENG_OK' upon success, an
      engine i/o code otherwise. */

   char *path;
   int len;
   int ret;

   if (command_words(comm) < 2)
      {
      printf("c_config_set_tmp_path:missing path\n");
      return(DBENG_INVALID_FILE_NAME);
      }

   len = strlen(comm);

   if ((path = (char *)malloc(len + 1)) == NULL)
      {
      printf("c_config_set_tmp_path:unable to alloc 'path'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, path, 2);
   ret = db_config_set_tmp_path(path);
   free(path);
   return(ret);
}

int c_config_set_log(char *comm)
{
   /* Set the current log destination.
      Syntax:

         config.set.log log_name

      Function returns 'DBENG_OK' upon success, an
      engine i/o code otherwise. */

   char *slog;
   int len;
   int ret;

   if (command_words(comm) < 2)
      {
      printf("c_config_set_log:missing log destination\n");
      return(DBENG_INVALID_FILE_NAME);
      }

   len = strlen(comm);

   if ((slog = (char *)malloc(len + 1)) == NULL)
      {
      printf("c_config_set_log:unable to alloc 'slog'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, slog, 2);
   ret = db_config_set_log(slog);
   free(slog);
   return(ret);
}

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

         config.set.session session_table

      Function returns 'DBENG_OK' upon success, an
      engine i/o code otherwise. */

   char *ses_table;
   int len;
   int ret;

   if (command_words(comm) < 2)
      {
      printf("c_config_set_session_table:missing path/file\n");
      return(DBENG_INVALID_FILE_NAME);
      }

   len = strlen(comm);

   if ((ses_table = (char *)malloc(len + 1)) == NULL)
      {
      printf("c_config_set_session_table:unable to alloc 'ses_table'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, ses_table, 2);
   ret = db_config_set_session(ses_table);
   free(ses_table);
   return(ret);
}

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

         config.set.catalog catalog

      Function returns 'DBENG_OK' upon success, an
      engine i/o code otherwise. */

   char *cat;
   int len;
   int ret;

   if (command_words(comm) < 2)
      {
      printf("c_config_set_catalog:missing path/file\n");
      return(DBENG_INVALID_FILE_NAME);
      }

   len = strlen(comm);

   if ((cat = (char *)malloc(len + 1)) == NULL)
      {
      printf("c_config_set_catalog:unable to alloc 'cat'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, cat, 2);
   ret = db_config_set_catalog(cat);
   free(cat);
   return(ret);
}

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

         config.set.log.flag flag

      The function 'logic_string_2_flag' is used to validate
      'flag' so value of 'flag' must be acceptable to the
      function. Function returns 'DBENG_OK' upon success, an
      engine i/o code otherwise. */

   char *flag_char;
   int len, flag;
   int ret;

   /* must be at least two words on command line */

   if (words(comm) < 2)
      {
      printf("c_config_set_log_flag:missing flag\n");
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((flag_char = (char *)malloc(len + 1)) == NULL)
      {
      printf("c_config_set_log_flag:unable to alloc 'flag_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, flag_char, 2);

   /* validate input flag */

   if (!logic_string_2_flag(flag_char, &flag))
      {
      printf("c_config_set_log_flag:flag is invalid\n");
      return(DBENG_INVALID_FUNCTION);
      }

   free(flag_char);
   ret = db_config_set_log_flag(flag);
   return(ret);
}

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

         config.set.session.flag flag

      The function 'logic_string_2_flag' is used to validate
      'flag' so value of 'flag' must be acceptable to the
      function. Function returns 'DBENG_OK' upon success, an
      engine i/o code otherwise. */

   char *flag_char;
   int len, flag;
   int ret;

   /* must be at least two words on command line */

   if (words(comm) < 2)
      {
      printf("c_config_set_session_flag:missing flag\n");
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((flag_char = (char *)malloc(len + 1)) == NULL)
      {
      printf("c_config_set_session_flag:unable to alloc 'flag_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, flag_char, 2);

   /* validate input flag */

   if (!logic_string_2_flag(flag_char, &flag))
      {
      printf("c_config_set_session_flag:flag is invalid\n");
      return(DBENG_INVALID_FUNCTION);
      }

   free(flag_char);
   ret = db_config_set_session_flag(flag);
   return(ret);
}

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

         config.set.catalog.flag flag

      The function 'logic_string_2_flag' is used to validate
      'flag' so value of 'flag' must be acceptable to the
      function. Function returns 'DBENG_OK' upon success, an
      engine i/o code otherwise. */

   char *flag_char;
   int len, flag;
   int ret;

   /* must be at least two words on command line */

   if (words(comm) < 2)
      {
      printf("c_config_set_catalog_flag:missing flag\n");
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((flag_char = (char *)malloc(len + 1)) == NULL)
      {
      printf("c_config_set_catalog_flag:unable to alloc 'flag_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, flag_char, 2);

   /* validate input flag */

   if (!logic_string_2_flag(flag_char, &flag))
      {
      printf("c_config_set_catalog_flag:flag is invalid\n");
      return(DBENG_INVALID_FUNCTION);
      }

   free(flag_char);
   ret = db_config_set_catalog_flag(flag);
   return(ret);
}

int c_config_set_replicate_flag(char *comm)
{
   /* Set the current replication flag.
      Syntax:

         config.set.replicate.flag flag

     The function 'logic_string_2_flag' is used to validate
      'flag' so value of 'flag' must be acceptable to the
      function. Function returns 'DBENG_OK' upon success, an
      engine i/o code otherwise. */

   char *flag_char;
   int len, flag;
   int ret;

   /* must be at least two words on command line */

   if (words(comm) < 2)
      {
      printf("c_config_set_replicate_flag:missing flag\n");
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((flag_char = (char *)malloc(len + 1)) == NULL)
      {
      printf("c_config_set_replicate_flag:unable to alloc 'flag_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, flag_char, 2);

   /* validate input flag */

   if (!logic_string_2_flag(flag_char, &flag))
      {
      printf("c_config_set_replicate_flag:flag is invalid\n");
      return(DBENG_INVALID_FUNCTION);
      }

   free(flag_char);
   ret = db_config_set_replicate_flag(flag);
   return(ret);
}

int c_get_open_table_list(char *comm)
{
   /* Get and display a list of open tables. Function
      returns a 'dbeng' code. Syntax:

         get.open.table.list [pat]

      Where 'pat' is an optional pattern acceptable to
      the 'pmatch' function. The pattern will be matched
      with the physical file name. */

   char *tlist, *anentry, *pat;
   char mname[] = "c_get_open_table_list";
   int ret, nwords, i, is_pat;

   if ((tlist = (char *)malloc(DBENG_MAXRECFIELD)) == NULL)
      {
      printf("%s:alloc fail[tlist]\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   nwords = command_words(comm);
   pat = (char *)NULL;

   if (nwords > 1)
      {
      is_pat = TRUE;

      if ((pat = (char *)malloc(strlen(comm) + 1)) == (char *)NULL)
         {
         printf("%s:alloc fail[pat]\n", mname);
         return(DBENG_MEMORY_FAIL);
         }
      
      (void)command_word(comm, pat, 2);
      }
   else
      is_pat = FALSE;

   if ((ret = db_get_open_table_list(pat, tlist)) != DBENG_OK)
      {
      free(tlist);

      if (is_pat)
         free(pat);

      return(ret);
      }

   if (is_pat)
      free(pat);

   nwords = ll_words(tlist, DBENG_LIST_DELIM);

   if (!nwords)
      {
      printf("%s:list empty\n", mname);
      free(tlist);
      return(ret);
      }

   if ((anentry = initstring(tlist)) == NULL)
      {
      printf("%s:alloc fail[anentry]\n", mname);
      free(tlist);
      return(DBENG_MEMORY_FAIL);
      }

   printf("list of open tables\n");

   for(i = 1; i <= nwords; i++)
      {
      if (!ll_word(tlist, anentry, i, DBENG_LIST_DELIM))
         {
         printf("%s:error getting list entry[%d]\n", mname, i);
         free(tlist);
         free(anentry);
         return(DBENG_INTERNAL_ERROR);
         }

      printf("table[%d]=%s\n", i, anentry);
      }

   free(tlist);
   free(anentry);
   return(DBENG_OK);
}

int c_replicate_update(void)
{
   /* Update all replication details. Applies to TCP IPC
      method only. Syntax:

         replicate.update

      Function returns 'DBENG_OK' upon success, an engine
      i/o code otherwise. */

#ifdef MULTIUSER
#ifdef IPC_TCP
   int ret;

   ret = db_replicate_update();
   return(ret);
#else
   printf("replication applies to TCP IPC method only\n");
   return(DBENG_ACCESS_DENIED);
#endif
#else
   printf("replication is only active in multi-user mode\n");
   return(DBENG_OK);
#endif
}

int c_delete_table(char *comm)
{
   /* Delete a table. The file name (or table name) is expected on the 
      command line. Function returns the 'DBENG' status. Syntax:

         delete.table file_name */

   char mname[] = "c_delete_table", *fname;
   int tid;
   int len;
   int ret;

   /* must be at least two words on command line */

   if (command_words(comm) < 2)
      {
      printf("%s:missing file name\n", mname);
      return(DBENG_INVALID_FILE_NAME);
      }

   len = strlen(comm);

   if ((fname = malloc(len + 1)) == NULL)
      {
      printf("%s:unable to alloc 'fname'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, fname, 2);
   ret = db_delete_table(fname);
   free(fname);
   return(ret);
}

int c_exist(char *comm)
{
   /* Test for the existance of a table. Function returns the 
      'DBENG' status. Syntax:

         exist tname */

   char mname[] = "c_exist", *fname;
   int tid, exist_flag;
   int len;
   int ret;

   /* must be at least two words on command line */

   if (command_words(comm) < 2)
      {
      printf("%s:missing file name\n", mname);
      return(DBENG_INVALID_FILE_NAME);
      }

   len = strlen(comm);

   if ((fname = malloc(len + 1)) == NULL)
      {
      printf("%s:unable to alloc 'fname'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, fname, 2);
   ret = db_exist(fname, &exist_flag);
   free(fname);

   if (ret == DBENG_OK)
      if (exist_flag)
         printf("%s:table does exist\n", mname);
      else
         printf("%s:table does not exist\n", mname);

   return(ret);
}

int c_clear_table(char *comm)
{
   /* Clear a table of all records. Function returns the 
      'DBENG' status. Syntax:

         clear.table tname */

   char mname[] = "c_clear_table", *fname;
   int tid;
   int len;
   int ret;

   /* must be at least two words on command line */

   if (command_words(comm) < 2)
      {
      printf("%s:missing file name\n", mname);
      return(DBENG_INVALID_FILE_NAME);
      }

   len = strlen(comm);

   if ((fname = malloc(len + 1)) == NULL)
      {
      printf("%s:unable to alloc 'fname'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, fname, 2);
   ret = db_clear_table(fname);
   free(fname);
   return(ret);
}

int c_copy_table(char *comm)
{
   /* Copy a table from source to destination. Both tables are
      expected to be open. Syntax:

         copy.table source_tid destination_tid */

   char mname[] = "c_copy_table", *src_tid_char, *dest_tid_char;
   int nwords, src_tid, dest_tid;
   int len;
   int ret;

   nwords = words(comm);

   /* must be at least three words on command line */

   if (nwords < 2)
      {
      printf("%s:missing source table tid\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   if (nwords < 3)
      {
      printf("%s:missing destination table tid\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((src_tid_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      printf("%s:alloc fail[src_tid_char]\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, src_tid_char, 2);

   if (!qatoi(src_tid_char, &src_tid))
      {
      printf("%s:non numeric source table tid\n", mname);
      free(src_tid_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(src_tid_char);

   if ((dest_tid_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      printf("%s:alloc fail[dest_tid_char]\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, dest_tid_char, 3);

   if (!qatoi(dest_tid_char, &dest_tid))
      {
      printf("%s:non numeric destination table tid\n", mname);
      free(dest_tid_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(dest_tid_char);
   ret = db_copy_table(src_tid, dest_tid);
   return(ret);
}

int c_get_catalog_list(char *comm)
{
   /* Get and display a list of catalog entires. Function
      returns a 'dbeng' code. Syntax:

         get.catalog.list [pat]

      Where 'pat' is an optional pattern acceptable to
      the 'pmatch' function. The pattern will be matched
      with the logical table name. */

   char *tlist, *anentry, *pat;
   char mname[] = "c_get_catalog_list";
   int ret, nwords, i, is_pat;

   if ((tlist = (char *)malloc(DBENG_MAXRECFIELD)) == NULL)
      {
      printf("%s:alloc fail[tlist]\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   nwords = command_words(comm);
   pat = (char *)NULL;

   if (nwords > 1)
      {
      is_pat = TRUE;

      if ((pat = (char *)malloc(strlen(comm) + 1)) == (char *)NULL)
         {
         printf("%s:alloc fail[pat]\n", mname);
         return(DBENG_MEMORY_FAIL);
         }
      
      (void)command_word(comm, pat, 2);
      }
   else
      is_pat = FALSE;

   if ((ret = db_get_catalog_list(pat, tlist)) != DBENG_OK)
      {
      free(tlist);

      if (is_pat)
         free(pat);

      return(ret);
      }

   if (is_pat)
      free(pat);

   nwords = ll_words(tlist, DBENG_LIST_DELIM);

   if (!nwords)
      {
      printf("%s:list empty\n", mname);
      free(tlist);
      return(ret);
      }

   if ((anentry = initstring(tlist)) == NULL)
      {
      printf("%s:alloc fail[anentry]\n", mname);
      free(tlist);
      return(DBENG_MEMORY_FAIL);
      }

   printf("list of catalog entries\n");

   for(i = 1; i <= nwords; i++)
      {
      if (!ll_word(tlist, anentry, i, DBENG_LIST_DELIM))
         {
         printf("%s:error getting list entry[%d]\n", mname, i);
         free(tlist);
         free(anentry);
         return(DBENG_INTERNAL_ERROR);
         }

      printf("table[%d]=%s\n", i, anentry);
      }

   free(tlist);
   free(anentry);
   return(DBENG_OK);
}

int c_sort(char *comm)
{
   /* Sort a table. Syntax:

         sort tid specs */

   char mname[] = "c_sort", *tid_char, *specs;
   int nwords, tid;
   int len;
   int ret;

   nwords = words(comm);

   /* must be at least three words on command line */

   if (nwords < 2)
      {
      printf("%s:missing table tid\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   if (nwords < 3)
      {
      printf("%s:missing sort specification(s)\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = (char *)malloc(len + 1)) == (char *)NULL)
      {
      printf("%s:alloc fail[tid_char]\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("%s:non numeric table tid\n", mname);
      free(tid_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(tid_char);

   if ((specs = (char *)malloc(len + 1)) == (char *)NULL)
      {
      printf("%s:alloc fail[specs]\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, specs, 3);
   ret = db_sort(tid, specs);
   free(specs);
   return(ret);
}

int c_get_sort_mem(char *comm)
{
   /* Get the current allowable max sort memory. Function returns
      the 'DBENG' status. The amount is displayed on the screen
      upon success. Syntax:

         get.sort.mem tid */

   char mname[] = "c_get_sort_mem";
   char *tid_char;
   long mem;
   int tid;
   int len;
   int ret;

   if (words(comm) < 2)
      {
      printf("%s:missing tid\n", mname);
      return(DBENG_NO_SUCH_TID);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("%s:unable to alloc 'tid_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("%s:non numeric tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("%s:invalid tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);
   ret = db_get_sort_max_mem(tid, &mem);

   if (ret == DBENG_OK)
      printf("%s:allowable sort memory is %ld bytes\n", mname, mem);

   return(ret);
}

int c_set_sort_mem(char *comm)
{
   /* Set the allowable sort memory. Function returns the 'DBENG' status.
      Syntax:

         set.sort.mem tid mem */

   char mname[] = "c_set_sort_mem";
   char *tid_char;
   char *mem_char;
   long mem;
   int nwords;
   int tid;
   int len;
   int ret;

   nwords = command_words(comm);

   if (nwords < 2)
      {
      printf("%s:missing tid\n", mname);
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("%s:missing sort memory\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("%s:unable to alloc 'tid_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("%s:non numeric tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("%s:invalid tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((mem_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'mem_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, mem_char, 3);

   if (!qatol(mem_char, &mem))
      {
      printf("%s:non numeric memory amount\n", mname);
      free(mem_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (mem < 0L)
      {
      printf("%s:invalid amount of memory\n", mname);
      free(mem_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(mem_char);
   ret = db_set_sort_max_mem(tid, mem);
   return(ret);
}

int c_get_sort_open_bin(char *comm)
{
   /* Get the current allowable sort open bin tables. Function returns
      the 'DBENG' status. The amount is displayed on the screen
      upon success. Syntax:

         get.sort.open.bin tid */

   char mname[] = "c_get_sort_open_bin";
   char *tid_char;
   int open_bin;
   int tid;
   int len;
   int ret;

   if (words(comm) < 2)
      {
      printf("%s:missing tid\n", mname);
      return(DBENG_NO_SUCH_TID);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("%s:unable to alloc 'tid_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("%s:non numeric tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("%s:invalid tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);
   ret = db_get_sort_max_open_bin(tid, &open_bin);

   if (ret == DBENG_OK)
      printf("%s:allowable sort open bin tables is %d\n", mname, open_bin);

   return(ret);
}

int c_set_sort_open_bin(char *comm)
{
   /* Set the allowable number of sort open bin tables. Function returns 
      the 'DBENG' status. Syntax:

         set.sort.open.bin tid open_bin */

   char mname[] = "c_set_sort_open_bin";
   char *tid_char;
   char *open_bin_char;
   int open_bin;
   int nwords;
   int tid;
   int len;
   int ret;

   nwords = command_words(comm);

   if (nwords < 2)
      {
      printf("%s:missing tid\n", mname);
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("%s:missing sort open bin\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("%s:unable to alloc 'tid_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("%s:non numeric tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("%s:invalid tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((open_bin_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail 'open_bin_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, open_bin_char, 3);

   if (!qatoi(open_bin_char, &open_bin))
      {
      printf("%s:non numeric number of bin tables\n", mname);
      free(open_bin_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (open_bin <= 0)
      {
      printf("%s:invalid number of open bin tables\n", mname);
      free(open_bin_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(open_bin_char);
   ret = db_set_sort_max_open_bin(tid, open_bin);
   return(ret);
}

int c_delete_field(char *comm)
{
   /* Delete a field from the current record. Function returns
      the 'DBENG' status. Syntax:

         delete.field tid fnum */

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

   nwords = command_words(comm);

   if (nwords < 2)
      {
      printf("%s:missing tid\n", mname);
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("%s:missing field number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("%s:unable to alloc 'tid_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("%s:non numeric tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("%s:invalid tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((fnum_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail[fnum_char]\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, fnum_char, 3);

   if (!qatoi(fnum_char, &fnum))
      {
      printf("%s:non numeric field number\n", mname);
      free(fnum_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (fnum <= 0)
      {
      printf("%s:invalid field number\n", mname);
      free(fnum_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(fnum_char);
   ret = db_delete_field(tid, fnum);
   return(ret);
}

int c_delete_subfield(char *comm)
{
   /* Delete a subfield from the current record. Function returns
      the 'DBENG' status. Syntax:

         delete.subfield tid fnum sfnum */

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

   nwords = command_words(comm);

   if (nwords < 2)
      {
      printf("%s:missing tid\n", mname);
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("%s:missing field number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   if (nwords < 4)
      {
      printf("%s:missing subfield number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("%s:unable to alloc 'tid_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("%s:non numeric tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("%s:invalid tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((fnum_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail[fnum_char]\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, fnum_char, 3);

   if (!qatoi(fnum_char, &fnum))
      {
      printf("%s:non numeric field number\n", mname);
      free(fnum_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (fnum <= 0)
      {
      printf("%s:invalid field number\n", mname);
      free(fnum_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(fnum_char);

   if ((sfnum_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail[sfnum_char]\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, sfnum_char, 4);

   if (!qatoi(sfnum_char, &sfnum))
      {
      printf("%s:non numeric subfield number\n", mname);
      free(sfnum_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (sfnum <= 0)
      {
      printf("%s:invalid subfield number\n", mname);
      free(sfnum_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(sfnum_char);
   ret = db_delete_subfield(tid, fnum, sfnum);
   return(ret);
}

int c_delete_subsubfield(char *comm)
{
   /* Delete a subsubfield from the current record. Function returns
      the 'DBENG' status. Syntax:

         delete.subsubfield tid fnum sfnum ssfnum */

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

   nwords = command_words(comm);

   if (nwords < 2)
      {
      printf("%s:missing tid\n", mname);
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("%s:missing field number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   if (nwords < 4)
      {
      printf("%s:missing subfield number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   if (nwords < 5)
      {
      printf("%s:missing subsubfield number\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("%s:unable to alloc 'tid_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("%s:non numeric tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("%s:invalid tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((fnum_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail[fnum_char]\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, fnum_char, 3);

   if (!qatoi(fnum_char, &fnum))
      {
      printf("%s:non numeric field number\n", mname);
      free(fnum_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (fnum <= 0)
      {
      printf("%s:invalid field number\n", mname);
      free(fnum_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(fnum_char);

   if ((sfnum_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail[sfnum_char]\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, sfnum_char, 4);

   if (!qatoi(sfnum_char, &sfnum))
      {
      printf("%s:non numeric subfield number\n", mname);
      free(sfnum_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (sfnum <= 0)
      {
      printf("%s:invalid subfield number\n", mname);
      free(sfnum_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(sfnum_char);

   if ((ssfnum_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail[ssfnum_char]\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, ssfnum_char, 5);

   if (!qatoi(ssfnum_char, &ssfnum))
      {
      printf("%s:non numeric subsubfield number\n", mname);
      free(ssfnum_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (ssfnum <= 0)
      {
      printf("%s:invalid subsubfield number\n", mname);
      free(ssfnum_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(ssfnum_char);
   ret = db_delete_subsubfield(tid, fnum, sfnum, ssfnum);
   return(ret);
}

int c_trans_num(void)
{
   /* Get the server current transaction count. Syntax:

         trans.num

      Function returns 'DBENG_OK' upon success, an engine
      i/o code otherwise. */

   int ret;

#ifdef MULTIUSER
   long trans_num;

   ret = db_trans_num(&trans_num);

   if (ret == DBENG_OK)
      printf("server transaction count is %ld\n", trans_num);
#else
   printf("transaction count is active only in multiuser mode\n");
   ret = DBENG_FUNCTION_NOT_IMPLEMENTED;
#endif

   return(ret);
}

int c_connect_num(void)
{
   /* Get the server current connection count. Syntax:

         connect.num

      Function returns 'DBENG_OK' upon success, an engine
      i/o code otherwise. */

   int ret;

#ifdef MULTIUSER
   int connect_num;

   ret = db_connect_num(&connect_num);

   if (ret == DBENG_OK)
      printf("server connection count is %d\n", connect_num);
#else
   printf("connection count is active only in multiuser mode\n");
   ret = DBENG_FUNCTION_NOT_IMPLEMENTED;
#endif

   return(ret);
}

int c_get_autopack(char *comm)
{
   /* Get the current value of 'autopack'. Function returns
      the 'DBENG' status. The value is displayed on the screen
      upon success. Syntax:

         get.autopack tid */

   char mname[] = "c_get_autopack";
   char *tid_char;
   int pval;
   int tid;
   int len;
   int ret;

   if (words(comm) < 2)
      {
      printf("%s:missing tid\n", mname);
      return(DBENG_NO_SUCH_TID);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("%s:unable to alloc 'tid_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("%s:non numeric tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("%s:invalid tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);
   ret = db_get_autopack(tid, &pval);

   if (ret == DBENG_OK)
      printf("%s:autopack threshold is %d\n", mname, pval);

   return(ret);
}

int c_set_autopack(char *comm)
{
   /* Set the current tables' 'autopack' value. Function returns
      the 'DBENG' status.
      Syntax:

         set.autopack tid autopack_value */

   char mname[] = "c_set_autopack";
   char *tid_char;
   char *pval_char;
   int pval;
   int nwords;
   int tid;
   int len;
   int ret;

   nwords = words(comm);

   if (nwords < 2)
      {
      printf("%s:missing tid\n", mname);
      return(DBENG_NO_SUCH_TID);
      }

   if (nwords < 3)
      {
      printf("%s:missing autopack value\n", mname);
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((tid_char = malloc(len + 1)) == NULL)
      {
      printf("%s:unable to alloc 'tid_char'\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, tid_char, 2);

   if (!qatoi(tid_char, &tid))
      {
      printf("%s:non numeric tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   if (tid <= 0)
      {
      printf("%s:invalid tid\n", mname);
      free(tid_char);
      return(DBENG_NO_SUCH_TID);
      }

   free(tid_char);

   if ((pval_char = malloc(len + 1)) == NULL)
      {
      printf("%s:alloc fail[pval_char]\n", mname);
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, pval_char, 3);

   if (!qatoi(pval_char, &pval))
      {
      printf("%s:non numeric autopack threshold\n", mname);
      free(pval_char);
      return(DBENG_INVALID_FUNCTION);
      }

   if (pval < 0)
      {
      printf("%s:out of range autopack threshold\n", mname);
      free(pval_char);
      return(DBENG_INVALID_FUNCTION);
      }

   free(pval_char);
   ret = db_set_autopack(tid, pval);
   return(ret);
}

int c_config_client_get_log(void)
{
   /* Display the current client log name.
      Multiuser only. Syntax:

         config.client.get.log

      Function returns 'DBENG_OK' upon success,
      an engine i/o code otherwise. */

#ifdef MULTIUSER
   int ret;
   char slog[DBENG_PATH_LIMIT];

   ret = db_config_client_get_log(slog);

   if (ret == DBENG_OK)
      if (strlen(slog))
         printf("client log is '%s'\n", slog);
      else
         printf("no client log currently defined\n");

   return(ret);
#else
   printf("only valid in multiuser mode\n");
   printf("use 'config.get.log' instead\n");
   return(DBENG_INVALID_FUNCTION);
#endif
}

int c_config_client_get_log_flag(void)
{
   /* Get the client log flag. Multiuser only. Syntax:

         config.client.get.log.flag

      Function returns 'DBENG_OK' upon success, an engine
      i/o code otherwise. */

#ifdef MULTIUSER
   char flag_ch[4];
   int flag;
   int ret;

   ret = db_config_client_get_log_flag(&flag);

   if (ret == DBENG_OK)
      if (flag_2_logic_string(flag, flag_ch))
         printf("client logging is %s\n", flag_ch);

   return(ret);
#else
   printf("only valid in multiuser mode\n");
   printf("use 'config.get.log.flag' instead\n");
   return(DBENG_INVALID_FUNCTION);
#endif
}

int c_config_client_set_log(char *comm)
{
   /* Set the current client log name. Multiuser only.
      Syntax:

         config.client.set.log log_name

      Function returns 'DBENG_OK' upon success, an
      engine i/o code otherwise. */

#ifdef MULTIUSER
   char *slog;
   int len;
   int ret;

   if (command_words(comm) < 2)
      {
      printf("c_config_set_log:missing log name\n");
      return(DBENG_INVALID_FILE_NAME);
      }

   len = strlen(comm);

   if ((slog = (char *)malloc(len + 1)) == NULL)
      {
      printf("c_config_set_log:unable to alloc 'slog'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)command_word(comm, slog, 2);
   ret = db_config_client_set_log(slog);
   free(slog);
   return(ret);
#else
   printf("only valid in multiuser mode\n");
   printf("use 'config.set.log' instead\n");
   return(DBENG_INVALID_FUNCTION);
#endif
}

int c_config_client_set_log_flag(char *comm)
{
   /* Set the current client log flag. Multiuser only.
      Syntax:

         config.client.set.log.flag flag

      Function returns 'DBENG_OK' upon success, an
      engine i/o code otherwise. */

#ifdef MULTIUSER
   char *flag_char;
   int len, flag;
   int ret;

   /* must be at least two words on command line */

   if (words(comm) < 2)
      {
      printf("c_config_set_log_flag:missing flag\n");
      return(DBENG_INVALID_FUNCTION);
      }

   len = strlen(comm);

   if ((flag_char = (char *)malloc(len + 1)) == NULL)
      {
      printf("c_config_set_log_flag:unable to alloc 'flag_char'\n");
      return(DBENG_MEMORY_FAIL);
      }

   (void)word(comm, flag_char, 2);

   /* validate input flag */

   if (!logic_string_2_flag(flag_char, &flag))
      {
      printf("c_config_set_log_flag:flag is invalid\n");
      return(DBENG_INVALID_FUNCTION);
      }

   free(flag_char);
   ret = db_config_client_set_log_flag(flag);
   return(ret);
#else
   printf("only valid in multiuser mode\n");
   printf("use 'config.set.log.flag' instead\n");
   return(DBENG_INVALID_FUNCTION);
#endif
}

int get_token(char *keywrd)
{
   /* Get keyword token. */

   int i;
   int token = DBCOM_NOT_FOUND;

   /* static array of command words, notice the dummy zero position */

   static char *coms[] = { " ", "OPEN", "CLOSE", "NEXT", "TOP", "GET.REC",
                           "GET.FIELD", "GOTO", "COUNT", "PUT.FIELD", "WRITE",
                           "DELETE", "GET.DELETE.FLAG", "SET.DELETE.FLAG",
                           "GET.NFIELDS", "GET.REC.SIZE", "GET.FIELD.SIZE",
                           "GET.REC.NUM", "GET.POS", "SET.POS",
                           "GET.CHANGE.REC.FLAG", "SET.CHANGE.REC.FLAG",
                           "PACK", "NEW", "FIND", "FIND.FIELD", "FIND.PART",
                           "FIND.FIELD.PART", "GET.REC.COUNT",
                           "GET.ENF.CHANGE.REC.FLAG",
                           "SET.ENF.CHANGE.REC.FLAG",
                           "GET.IS.TABLE.LOCKED", "SET.IS.TABLE.LOCKED",
                           "NEW.TABLE", "CONFIG.GET.TMP.PATH",
                           "CONFIG.GET.LOG", "CONFIG.GET.SESSION",
                           "CONFIG.GET.CATALOG", "CONFIG.GET.LOG.FLAG",
                           "CONFIG.GET.SESSION.FLAG",
                           "CONFIG.GET.CATALOG.FLAG", "CONFIG.GET.VERSION",
                           "CONFIG.SET.TMP.PATH",
                           "CONFIG.SET.LOG", "CONFIG.SET.SESSION",
                           "CONFIG.SET.CATALOG", "CONFIG.SET.LOG.FLAG",
                           "CONFIG.SET.SESSION.FLAG",
                           "CONFIG.SET.CATALOG.FLAG", "VERSION",
                           "GET.OPEN.TABLE.LIST", "GET.NSUBFIELDS",
                           "GET.SUBFIELD.SIZE", "GET.SUBFIELD",
                           "PUT.SUBFIELD", "GET.NSUBSUBFIELDS",
                           "GET.SUBSUBFIELD.SIZE", "GET.SUBSUBFIELD",
                           "PUT.SUBSUBFIELD", "CONFIG.GET.REPLICATE.FLAG",
                           "CONFIG.SET.REPLICATE.FLAG", "REPLICATE.UPDATE",
                           "DELETE.TABLE", "EXIST", "CLEAR.TABLE",
                           "COPY.TABLE", "GET.CATALOG.LIST", "SORT",
                           "GET.SORT.MEM", "SET.SORT.MEM", "GET.SORT.OPEN.BIN",
                           "SET.SORT.OPEN.BIN", "DELETE.FIELD",
                           "DELETE.SUBFIELD", "DELETE.SUBSUBFIELD",
                           "TRANS.NUM", "CONNECT.NUM", "GET.AUTOPACK",
                           "SET.AUTOPACK", "CONFIG.CLIENT.GET.LOG",
                           "CONFIG.CLIENT.GET.LOG.FLAG",
                           "CONFIG.CLIENT.SET.LOG",
                           "CONFIG.CLIENT.SET.LOG.FLAG" };

   /* check for 'OFF' keyword separately */

   if (!stricmp(keywrd, "OFF"))
      return(DBCOM_OFF);

   for(i = 1; i <= DBCOM_MAXCOM; i++)
      if (!stricmp(keywrd, coms[i]))
         {
         token = i;
         break;
         }

   return(token);
}

void term_app(void)
{
   // Prepare to terminate the application. Shutdown all IPC API's.

   db_end();

   if (logman_is_active())
      logman_end();

#ifdef IPC_TCP
   if (sloc_is_init())
      sloc_term_api();

#ifdef OS_WIN32
   WSACleanup();
#endif
#endif
   
#ifndef OS_DOS
   (void)appinit_remove_name();
#endif
}
