## root/source/dbsrv.c

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

## DEFINITIONS

This source file includes following definitions.

1. main
2. parse_comline
3. srv_initialize
4. process_request
5. do_comm
6. c_open
7. c_close
8. c_next
9. c_top
10. c_get_rec
11. c_get_rec_size
12. c_get_field_size
13. c_get_subfield_size
14. c_get_subsubfield_size
15. c_get_field
16. c_get_subfield
17. c_get_subsubfield
18. c_goto
19. c_put_field
20. c_put_subfield
21. c_put_subsubfield
22. c_get_nfields
23. c_get_nsubfields
24. c_get_nsubsubfields
25. c_get_rec_num
26. c_get_delete_flag
27. c_set_delete_flag
28. c_count
29. c_write
30. c_delete
31. c_pack
32. c_find
33. c_find_field
34. c_find_part
35. c_find_field_part
36. c_get_pos
37. c_set_pos
38. c_sort
39. c_get_sort_mem
40. c_set_sort_mem
41. c_get_sort_open_bin
42. c_set_sort_open_bin
43. c_get_change_rec_flag
44. c_set_change_rec_flag
45. c_get_autopack
46. c_set_autopack
47. c_new
48. c_get_rec_count
49. c_get_enf_change_rec_flag
50. c_set_enf_change_rec_flag
51. c_get_is_table_locked
52. c_set_is_table_locked
53. c_new_table
54. c_config_get_tmp_path
55. c_config_get_log
56. c_log_status
57. c_config_get_session
58. c_config_get_catalog
59. c_config_get_log_flag
60. c_config_get_session_flag
61. c_config_get_catalog_flag
62. c_config_get_replicate_flag
63. c_config_get_version
64. c_config_set_tmp_path
65. c_config_set_session
66. c_config_set_catalog
67. c_config_set_log
68. c_config_set_log_flag
69. c_config_set_session_flag
70. c_config_set_catalog_flag
71. c_config_set_replicate_flag
72. c_get_open_table_list
73. c_replicate
74. c_replicate_update
75. c_delete_table
76. c_exist
77. c_clear_table
78. c_copy_table
79. c_get_catalog_list
80. c_delete_field
81. c_delete_subfield
82. c_delete_subsubfield
83. c_terminate
84. c_trans_num
85. c_connect_num
86. do_reply_int
87. do_reply_long
88. do_reply_code
89. do_reply_char
90. term_app
91. usage

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

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

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

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

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

       Original QNX version. Feb/97, Rick Smereka

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

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

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

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

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

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

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

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

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

       Fixed bug in 'c_new_table' function where the check
       for a least two words was missing. Aug/99,
       Rick Smereka

       Modified to use the 'socloc' interface. Added all
       commom socket send codes. Removed requirement in
       function 'process_request' to have received at least
       two command words. This is required since the common
       send codes only send one parameter. Added command
       word number detection to each function that
       processes a database command. Added a command line
       parameter consisting of the TCP port number to listen.
       Program syntax now:

          dbsrv port

       Apr/2000, Rick Smereka

       Modified 'srv_initialize' to obtain the IP address of the
       local host to be passed to 'sloc_add'. Jul/2000,
       Rick Smereka

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

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

          dbsrv

       Oct/2001, Rick Smereka

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

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

       Added replication support. Feb/2002, Rick Smereka

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

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

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

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

       Ported to Debian Linux. Jan/2003, Rick Smereka

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

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

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

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

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

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

          dbsrv [-q] port

       Command line syntax for QNX 4.x is:

          dbsrv [-q]

       Apr/2004, Rick Smereka

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

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

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

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

    /* function prototypes */

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

    /* global data */

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

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

    /* WinSock specific global data structure */

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

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

       /* indicate that we are initializing */

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

       /* register application name */

       if (!appinit_register_name(APNAME))
          {
          printf("%s:error registering application name. Program abort\n",
                 APNAME);
          (void)appinit_stop(DBENG_SERVICE_NAME);
          return(0);
          }

       /* check for 'socloc' (TCP) and 'sys_log' servers initializing */

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

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

       /* check for command line parameters */

    #ifdef IPC_TCP
       if (argc == 1)
          {
          (void)appinit_stop(DBENG_SERVICE_NAME);
          usage();
          return(0);
          }
    #endif

       /* parse command line */

       if (!parse_comline(argc, argv))
          {
          (void)appinit_stop(DBENG_SERVICE_NAME);
          return(0);
          }

       // set console output

       logman_console(console_output);

       /* perform initialization of 'socloc' (TCP only), 'sys_log' and the
          'Bbuuzzb' engine */

       if (!srv_initialize())
          {
          (void)appinit_stop(DBENG_SERVICE_NAME);
          term_app();
          return(0);
          }

       /* build logo string based on platform */

    #ifndef OS_UNIX
       /* non-Unix */

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

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

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

    #ifdef IPC_TCP
       logman("server on \"%s\" servicing TCP port %d (decimal)",
               server_host, server_port);
    #endif
       logman_nf("database server started");
       logman("%s comes with ABSOLUTELY NO WARRANTY", APNAME);
       logman_nf("This is free software, and you are welcome to redistribute it");
       logman_nf("under certain conditions; see \"gpl.txt\" for information.");

       /* turn off system log as this is used only for debugging */

       (void)db_config_set_log_flag(FALSE);

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

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

       /* indicate that we have completed initialization */

       (void)appinit_stop(DBENG_SERVICE_NAME);

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

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

          if (isterm)
             break;
          }
    #endif

       term_app();
       return(0);
    }

    int parse_comline(int c_count, char **c_parm)
    {
       /* Parse the command line. Function returns 'TRUE' if no
          error was detected, 'FALSE' otherwise. */

       char mname[] = "parse_comline";
       int parms = 1, done = FALSE;

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

       while(!done)
          {
          if (c_parm[parms][0] == SWITCH_CHAR)
             {
             switch(toupper(c_parm[parms][1]))
                {
                case 'Q':
                   console_output = FALSE;
                   parms++;
                   break;

                default:
                   printf("%s:unknown switch[%s], program abort\n",
                          mname, c_parm[parms]);
                   return(FALSE);
                };
             }
    #ifdef IPC_TCP
          else
             {
             if (!qatoi(c_parm[parms], &server_port))
                {
                printf("%s:server port is non-numeric, "
                       "program abort\n", mname);
                return(FALSE);
                }

             if (server_port <= 0)
                {
                printf("%s:server port is out of range, "
                       "program abort\n", mname);
                return(FALSE);
                }

             parms++;
             }
    #endif

          if (parms >= c_count)
             done = TRUE;
          }

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

       return(TRUE);
    }

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

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

       /* startup WinSock (if Windoze) */

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

       /* initialize the server on the IPC level, note that
          the hostname 'server_host' is returned to us (TCP only) */

    #ifdef IPC_TCP
       if (!ipc_init(server_host, server_port))
    #else
       if (!ipc_init(DBENG_SERVICE_NAME))
    #endif
          {
          printf("%s:'ipc_init' initialization failure, "
                     "program abort\n", mname);
          return(FALSE);
          }

       /* initialize 'socloc' client API */

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

       /* get IP address of this machine */

       if (!ip_host2ip(server_host, mes))
          {
          printf("%s:unable to obtain IP address of this "
                 "machine\n", mname);
          printf("%s:program abort\n", mname);
          return(FALSE);
          }

       /* register this server with 'socloc' */

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

       /* initialize 'Bbuuzzb' engine */

       ret = db_initialize();

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

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

             break;

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

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

       /* set log flag high which will start logging */

       if ((ret = db_config_set_log_flag(TRUE)) != DBENG_OK)
          {
          printf("%s:error starting logging,program abort\n", mname);
          (void)c_terminate(DBSRV_TERM_PASSWD);
          return(FALSE);
          }

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

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

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

       (void)db_config_get_catalog(mes);
       logman("%s:catalog is %s", mname, mes);

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

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

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

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

       if ((messbuf = (char *)malloc(DBENG_MAXRECFIELD)) == (char *)NULL)
          {
          logman("%s:alloc fail[messbuf]", mname);
          (void)do_reply_code(DBENG_MEMORY_FAIL);
          return(FALSE);
          }

       memset(messbuf, 0, DBENG_MAXRECFIELD);

       // get the message from the client

    #ifdef IPC_TCP
       if ((nbytes = ipc_recv_data(messbuf)) == 0)
    #else
       if ((nbytes = ipc_recv_data(messbuf, DBENG_MAXRECFIELD)) == 0)
    #endif
          {
          free(messbuf);
          logman("%s:connection closed by client", mname);
    #ifdef IPC_TCP
          return(-1);
    #else
          return(FALSE);
    #endif
          }

       messbuf[nbytes] = EOS;
       nwords = command_words(messbuf);

       // no command words, empty string

       if (!nwords)
          {
          logman("%s:command contains no words", mname);
          (void)do_reply_code(DBENG_INVALID_FUNCTION);
          free(messbuf);
          return(FALSE);
          }

       // first command word must be a number

       if (!command_word(messbuf, tmp, 1))
          {
          free(messbuf);
          logman("%s:error command code", mname);
          (void)do_reply_code(DBENG_INTERNAL_ERROR);
          return(FALSE);
          }

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

       logman("%s:recv[%d],nwords[%d]", mname, mestype, nwords);

       /* if command contains more than one word, pass pointer
          to start of second word */

       if (nwords > 1)
          {
          indx = command_indxword(messbuf, 2);

          if (indx == -1)
             {
             free(messbuf);
             logman("%s:error getting index of second word", mname);
             (void)do_reply_code(DBENG_INTERNAL_ERROR);
             return(FALSE);
             }

          /* if the first char in the second word is a quote,
             'command_indxword' will skip over this, we need
             to backup one position */

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

          ret = do_comm(mestype, &messbuf[indx]);
          }
       else
          ret = do_comm(mestype, (char *)NULL);

       free(messbuf);
       logman("%s:normal exit rc[%d]", mname, ret);
       return(ret);
    }

    int do_comm(int mestype, char *slm)
    {
       /* High level database command dispatcher.
          Function returns 'TRUE' if a terminate
          request was encountered, 'FALSE'
          otherwise. */

       char mname[] = "do_comm";
       int ret, rc, session_flag, should_rs, tid;

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

       /* restore data from session table if appropriate */

       (void)db_config_get_session_flag(&session_flag);

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

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

          case DBENG_SEND_CLOSE:
             c_close(slm);
             break;

          case DBENG_SEND_NEXT:
             c_next(slm);
             break;

          case DBENG_SEND_TOP:
             c_top(slm);
             break;

          case DBENG_SEND_GET_REC:
             c_get_rec(slm);
             break;

          case DBENG_SEND_GET_REC_SIZE:
             c_get_rec_size(slm);
             break;

          case DBENG_SEND_GET_FIELD_SIZE:
             c_get_field_size(slm);
             break;

          case DBENG_SEND_GET_FIELD:
             c_get_field(slm);
             break;

          case DBENG_SEND_GOTO:
             c_goto(slm);
             break;

          case DBENG_SEND_PUT_FIELD:
             c_put_field(slm);
             break;

          case DBENG_SEND_WRITE:
             c_write(slm);
             break;

          case DBENG_SEND_DELETE:
             c_delete(slm);
             break;

          case DBENG_SEND_GET_NFIELDS:
             c_get_nfields(slm);
             break;

          case DBENG_SEND_GET_REC_NUM:
             c_get_rec_num(slm);
             break;

          case DBENG_SEND_GET_DELETE_FLAG:
             c_get_delete_flag(slm);
             break;

          case DBENG_SEND_SET_DELETE_FLAG:
             c_set_delete_flag(slm);
             break;

          case DBENG_SEND_COUNT:
             c_count(slm);
             break;

          case DBENG_SEND_PACK:
             c_pack(slm);
             break;

          case DBENG_SEND_FIND:
             c_find(slm);
             break;

          case DBENG_SEND_FIND_FIELD:
             c_find_field(slm);
             break;

          case DBENG_SEND_FIND_PART:
             c_find_part(slm);
             break;

          case DBENG_SEND_FIND_FIELD_PART:
             c_find_field_part(slm);
             break;

          case DBENG_SEND_GET_POS:
             c_get_pos(slm);
             break;

          case DBENG_SEND_SET_POS:
             c_set_pos(slm);
             break;

          case DBENG_SEND_GET_CHANGE_REC_FLAG:
             c_get_change_rec_flag(slm);
             break;

          case DBENG_SEND_SET_CHANGE_REC_FLAG:
             c_set_change_rec_flag(slm);
             break;

          case DBENG_SEND_NEW:
             c_new(slm);
             break;

          case DBENG_SEND_GET_REC_COUNT:
             c_get_rec_count(slm);
             break;

          case DBENG_SEND_GET_ENF_CHANGE_REC_FLAG:
             c_get_enf_change_rec_flag(slm);
             break;

          case DBENG_SEND_SET_ENF_CHANGE_REC_FLAG:
             c_set_enf_change_rec_flag(slm);
             break;

          case DBENG_SEND_GET_IS_TABLE_LOCKED:
             c_get_is_table_locked(slm);
             break;

          case DBENG_SEND_SET_IS_TABLE_LOCKED:
             c_set_is_table_locked(slm);
             break;

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

          case DBENG_SEND_NEW_TABLE:
             c_new_table(slm);
             break;

          case DBENG_SEND_GET_TMP_PATH:
             c_config_get_tmp_path();
             break;

          case DBENG_SEND_GET_LOG:
             c_config_get_log();
             break;

          case DBENG_SEND_GET_SESSION:
             c_config_get_session();
             break;

          case DBENG_SEND_GET_CATALOG:
             c_config_get_catalog();
             break;

          case DBENG_SEND_GET_LOG_FLAG:
             c_config_get_log_flag();
             break;

          case DBENG_SEND_GET_SESSION_FLAG:
             c_config_get_session_flag();
             break;

          case DBENG_SEND_GET_CATALOG_FLAG:
             c_config_get_catalog_flag();
             break;

          case DBENG_SEND_GET_REPLICATE_FLAG:
             c_config_get_replicate_flag();
             break;

          case DBENG_SEND_GET_DBENG_VERSION:
             /* get version of 'Bbuuzzb' engine */

             c_config_get_version();
             break;

          case DBENG_SEND_SET_TMP_PATH:
             c_config_set_tmp_path(slm);
             break;

          case DBENG_SEND_SET_SESSION:
             c_config_set_session(slm);
             break;

          case DBENG_SEND_SET_CATALOG:
             c_config_set_catalog(slm);
             break;

          case DBENG_SEND_SET_LOG_FLAG:
             c_config_set_log_flag(slm);
             break;

          case DBENG_SEND_SET_SESSION_FLAG:
             c_config_set_session_flag(slm);
             break;

          case DBENG_SEND_SET_CATALOG_FLAG:
             c_config_set_catalog_flag(slm);
             break;

          case DBENG_SEND_SET_REPLICATE_FLAG:
             c_config_set_replicate_flag(slm);
             break;

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

          case DBENG_SEND_LOG_OFF:
             /* common socket code, call config set log */

             c_config_set_log_flag("0");
             break;

          case DBENG_SEND_LOG_ON:
             /* common socket code, call config set log */

             c_config_set_log_flag("1");
             break;

          case DBENG_SEND_LOG_STATUS:
             c_log_status();
             break;

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

          case DBENG_SEND_VERSION:
             /* reply with version of server */

             (void)do_reply_char(DBENG_OK, VERSION);
             break;

          case DBENG_SEND_GET_OPEN_TABLE_LIST:
             c_get_open_table_list(slm);
             break;

          case DBENG_SEND_GET_NSUBFIELDS:
             c_get_nsubfields(slm);
             break;

          case DBENG_SEND_GET_SUBFIELD_SIZE:
             c_get_subfield_size(slm);
             break;

          case DBENG_SEND_GET_SUBFIELD:
             c_get_subfield(slm);
             break;

          case DBENG_SEND_PUT_SUBFIELD:
             c_put_subfield(slm);
             break;

          case DBENG_SEND_GET_NSUBSUBFIELDS:
             c_get_nsubsubfields(slm);
             break;

          case DBENG_SEND_GET_SUBSUBFIELD_SIZE:
             c_get_subsubfield_size(slm);
             break;

          case DBENG_SEND_GET_SUBSUBFIELD:
             c_get_subsubfield(slm);
             break;

          case DBENG_SEND_PUT_SUBSUBFIELD:
             c_put_subsubfield(slm);
             break;

          case DBENG_SEND_REPLICATE:
             c_replicate(slm);
             break;

          case DBENG_SEND_REPLICATE_UPDATE:
             c_replicate_update();
             break;

          case DBENG_SEND_DELETE_TABLE:
             c_delete_table(slm);
             break;

          case DBENG_SEND_EXIST:
             c_exist(slm);
             break;

          case DBENG_SEND_CLEAR_TABLE:
             c_clear_table(slm);
             break;

          case DBENG_SEND_COPY_TABLE:
             c_copy_table(slm);
             break;

          case DBENG_SEND_GET_CATALOG_LIST:
             c_get_catalog_list(slm);
             break;

          case DBENG_SEND_SORT:
             c_sort(slm);
             break;

          case DBENG_SEND_GET_SORT_MEM:
             c_get_sort_mem(slm);
             break;

          case DBENG_SEND_SET_SORT_MEM:
             c_set_sort_mem(slm);
             break;

          case DBENG_SEND_GET_SORT_OPEN_BIN:
             c_get_sort_open_bin(slm);
             break;

          case DBENG_SEND_SET_SORT_OPEN_BIN:
             c_set_sort_open_bin(slm);
             break;

          case DBENG_SEND_DELETE_FIELD:
             c_delete_field(slm);
             break;

          case DBENG_SEND_DELETE_SUBFIELD:
             c_delete_subfield(slm);
             break;

          case DBENG_SEND_DELETE_SUBSUBFIELD:
             c_delete_subsubfield(slm);
             break;

          case DBENG_SEND_TRANS_NUM:
             c_trans_num();
             break;

          case DBENG_SEND_CONNECT_NUM:
             c_connect_num();
             break;

          case DBENG_SEND_GET_AUTOPACK:
             c_get_autopack(slm);
             break;

          case DBENG_SEND_SET_AUTOPACK:
             c_set_autopack(slm);
             break;

          case DBENG_SEND_SET_LOG:
             c_config_set_log(slm);
             break;

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

       /* save session */

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

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

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

             file_name */

       char mname[25], *fname;
       int tid = 0;
       int ret, driret;

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

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

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

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

       ret = db_open(fname, &tid);
       free(fname);

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

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

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

             tid */

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

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

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

       len = strlen(comm);

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

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

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

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

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

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

             tid */

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

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

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

       len = strlen(comm);

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

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

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

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

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

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

             tid */

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

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

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

       len = strlen(comm);

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

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

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

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

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

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

             tid */

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

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

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

       len = strlen(comm);

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

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

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

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

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

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

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

       ret = db_get_rec(tid, rdata);
       (void)do_reply_char(ret, rdata);
       free(rdata);
       db_io_code_log(mname, "normal exit", ret);
    }

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

             tid */

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

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

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

       len = strlen(comm);

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

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

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

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

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

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

             tid field_number */

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

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

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

       len = strlen(comm);

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

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

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

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

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

       free(tid_char);

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

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

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

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

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

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

             tid field_number sub-field_number */

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

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

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

       len = strlen(comm);

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

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

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

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

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

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

       free(tid_char);

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

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

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

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

       free(fnum_char);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

       free(tid_char);

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

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

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

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

       free(fnum_char);

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

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

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

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

       free(sfnum_char);

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

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

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

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

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

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

             tid field_number */

       char *tid_char;
       char *fnum_char;
       char *field_out;
       char mname[25];
       int fnum;
       int field_size;
       int tid;
       int len;
       int ret;

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

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

       len = strlen(comm);

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

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

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

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

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

       free(tid_char);

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

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

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

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

       free(fnum_char);

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

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

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

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

             tid field_number sub-field_number */

       char *tid_char, *fnum_char, *sfnum_char, *subfield_out;
       char mname[] = "c_get_subfield";
       int tid, fnum, sfnum, sf_size, len, ret;

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

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

       len = strlen(comm);

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

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

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

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

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

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

       free(tid_char);

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

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

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

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

       free(fnum_char);

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

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

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

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

       free(sfnum_char);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

       free(tid_char);

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

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

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

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

       free(fnum_char);

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

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

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

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

       free(sfnum_char);

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

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

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

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

       free(ssfnum_char);

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

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

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

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

             tid record_number */

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

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

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

       len = strlen(comm);

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

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

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

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

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

       free(tid_char);

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

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

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

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

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

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

          tid field_number 'field data'

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

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

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

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

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

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

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

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

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

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

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

       free(tid_char);

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

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

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

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

       free(fnum_char);

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

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

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

          tid field_number sub-field_number 'field data'

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

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

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

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

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

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

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

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

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

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

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

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

       free(tid_char);

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

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

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

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

       free(fnum_char);

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

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

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

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

       free(sfnum_char);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

       free(tid_char);

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

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

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

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

       free(fnum_char);

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

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

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

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

       free(sfnum_char);

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

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

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

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

       free(ssfnum_char);

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

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

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

             tid */

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

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

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

       len = strlen(comm);

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

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

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

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

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

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

             tid field_number */

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

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

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

       len = strlen(comm);

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

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

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

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

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

       free(tid_char);

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

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

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

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

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

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

             tid field_number sub-field_number */

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

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

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

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

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

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

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

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

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

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

       free(tid_char);

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

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

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

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

       free(fnum_char);

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

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

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

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

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

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

             tid */

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

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

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

       len = strlen(comm);

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

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

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

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

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

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

             tid */

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

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

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

       len = strlen(comm);

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

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

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

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

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

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

             tid flag_value */

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

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

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

       len = strlen(comm);

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

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

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

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

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

       free(tid_char);

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

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

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

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

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

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

             tid */

       char *tid_char;
       char mname[] = "c_count", buf[128];
       long active_count, deleted_count;
       int tid;
       int len;
       int ret;

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

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

       len = strlen(comm);

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

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

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

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

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

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

             tid */

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

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

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

       len = strlen(comm);

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

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

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

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

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

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

             tid */

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

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

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

       len = strlen(comm);

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

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

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

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

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

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

             tid */

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

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

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

       len = strlen(comm);

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

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

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

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

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

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

          tid 'search field data' cs_flag

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

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

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

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

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

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

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

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

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

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

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

       free(tid_char);

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

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

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

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

       free(cs_char);

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

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

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

          tid field_num 'search field data' cs_flag

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

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

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

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

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

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

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

       if (nwords < 4)
          {
          db_io_code_log(mname, "missing case flag", DBENG_INVALID_FUNCTION);
          (void)do_reply_code(DBENG_INVALID_FUNCTION);
          return;
          }

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

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

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

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

       free(tid_char);

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

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

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

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

       free(fnum_char);

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

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

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

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

       free(cs_char);

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

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

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

          tid 'search field data' cs_flag

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

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

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

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

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

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

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

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

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

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

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

       free(tid_char);

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

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

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

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

       free(cs_char);

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

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

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

          tid field_num 'search field data' cs_flag

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

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

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

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

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

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

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

       if (nwords < 4)
          {
          db_io_code_log(mname, "missing case flag", DBENG_INVALID_FUNCTION);
          (void)do_reply_code(DBENG_INVALID_FUNCTION);
          return;
          }

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

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

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

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

       free(tid_char);

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

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

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

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

       free(fnum_char);

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

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

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

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

       free(cs_char);

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

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

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

             tid */

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

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

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

       len = strlen(comm);

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

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

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

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

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

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

             tid fpos */

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

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

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

       len = strlen(comm);

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

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

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

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

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

       free(tid_char);

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

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

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

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

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

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

             tid sort_specs

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

       char *tid_char, *specs;
       char mname[] = "c_sort";
       long pos;
       int tid;
       int len;
       int ret;

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

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

       len = strlen(comm);

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

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

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

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

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

       free(tid_char);

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

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

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

             tid */

       char *tid_char;
       char mname[] = "c_get_sort_mem";
       long mem;
       int tid;
       int len;
       int ret;

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

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

       len = strlen(comm);

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

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

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

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

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

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

             tid mem */

       char *tid_char;
       char *mem_char;
       char mname[] = "c_set_sort_mem";
       long mem;
       int tid;
       int len;
       int ret;

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

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

       len = strlen(comm);

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

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

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

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

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

       free(tid_char);

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

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

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

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

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

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

             tid */

       char *tid_char;
       char mname[] = "c_get_sort_open_bin";
       int open_bin;
       int tid;
       int len;
       int ret;

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

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

       len = strlen(comm);

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

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

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

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

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

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

             tid open_bin */

       char *tid_char;
       char *open_bin_char;
       char mname[] = "c_set_sort_open_bin";
       int open_bin;
       int tid;
       int len;
       int ret;

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

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

       len = strlen(comm);

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

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

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

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

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

       free(tid_char);

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

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

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

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

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

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

             tid */

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

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

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

       len = strlen(comm);

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

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

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

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

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

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

             tid flag_value */

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

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

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

       len = strlen(comm);

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

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

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

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

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

       free(tid_char);

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

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

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

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

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

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

             tid */

       char *tid_char;
       char mname[] = "c_get_autopack";
       int pval;
       int tid;
       int len;
       int ret;

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

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

       len = strlen(comm);

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

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

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

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

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

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

             tid autopack_value */

       char *tid_char;
       char *autopack_char;
       char mname[] = "c_set_autopack";
       int pval;
       int tid;
       int len;
       int ret;

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

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

       len = strlen(comm);

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

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

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

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

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

       free(tid_char);

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

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

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

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

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

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

             tid */

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

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

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

       len = strlen(comm);

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

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

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

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

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

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

             tid */

       char *tid_char;
       char mname[] = "c_get_rec_count", buf[128];
       long active_count, deleted_count;
       int tid;
       int len;
       int ret;

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

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

       len = strlen(comm);

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

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

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

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

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

       // reply with both the active and deleted record counts

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

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

             tid */

       char *tid_char;
       char mname[30];
       int flag;
       int tid;
       int len;
       int ret;

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

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

       len = strlen(comm);

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

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

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

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

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

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

             tid flag_value */

       char *tid_char;
       char *flag_char;
       char mname[30];
       int flag;
       int tid;
       int len;
       int ret;

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

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

       len = strlen(comm);

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

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

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

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

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

       free(tid_char);

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

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

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

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

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

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

             tid */

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

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

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

       len = strlen(comm);

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

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

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

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

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

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

             tid flag_value */

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

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

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

       len = strlen(comm);

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

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

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

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

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

       free(tid_char);

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

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

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

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

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

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

             file_name open_flag */

       char mname[25], *filename, *tid_char;
       int tid = 0;
       int ret, len, driret;

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

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

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

       len = strlen(comm);

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

       (void)command_word(comm, filename, 1);

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

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

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

       /* zero tid flag is ok and signifies no open after create */

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

       free(tid_char);
       ret = db_new_table(filename, &tid);
       free(filename);

       if ((driret = do_reply_int(ret, tid)) != DBENG_OK)
          {
          logman("%s:bad ret from do_reply_int:rc=%d", mname, driret);
          return;
          }

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

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

          */

       char *tmp_path;
       char mname[25];
       int ret;

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

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

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

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

          */

       char *slog;
       char mname[25];
       int ret;

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

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

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

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

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

    void c_log_status(void)
    {
       /* Get the status of the log including the flag value and the
          log name. */

       char mname[] = "c_log_status";
       char *reply, *slog;
       int len, flag;

       logman("%s:enter", mname);
       (void)db_config_get_log_flag(&flag);

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

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

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

       sprintf(reply, "%d %s", flag, slog);
       free(slog);
       (void)do_reply_char(DBENG_OK, reply);
       free(reply);
       db_io_code_log(mname, "normal exit", DBENG_OK);
    }

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

       char *ses_table;
       char mname[30];
       int ret;

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

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

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

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

       char *cat;
       char mname[25];
       int ret;

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

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

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

    void c_config_get_log_flag(void)
    {
       /* Get the engine log flag. Function replies with a
          'dbeng' i/o code */

       char mname[] = "c_config_get_log_flag";
       int ret, flag;

       logman("%s:enter", mname);
       ret = db_config_get_log_flag(&flag);
       (void)do_reply_int(ret, flag);
       db_io_code_log(mname, "normal exit", ret);
    }

    void c_config_get_session_flag(void)
    {
       /* Get the engine session flag. Function replies with a
          'dbeng' i/o code */

       char mname[] = "c_config_get_session_flag";
       int ret, flag;

       logman("%s:enter", mname);
       ret = db_config_get_session_flag(&flag);
       (void)do_reply_int(ret, flag);
       db_io_code_log(mname, "normal exit", ret);
    }

    void c_config_get_catalog_flag(void)
    {
       /* Get the engine catalog flag. Function replies with a
          'dbeng' i/o code */

       char mname[] = "c_config_get_catalog_flag";
       int ret, flag;

       logman("%s:enter", mname);
       ret = db_config_get_catalog_flag(&flag);
       (void)do_reply_int(ret, flag);
       db_io_code_log(mname, "normal exit", ret);
    }

    void c_config_get_replicate_flag(void)
    {
       /* Get the engine replication flag. Function replies with a
          'dbeng' i/o code */

       char mname[] = "c_config_get_replicate_flag";
       int ret, flag;

       logman("%s:enter", mname);
       ret = db_config_get_replicate_flag(&flag);
       (void)do_reply_int(ret, flag);
       db_io_code_log(mname, "normal exit", ret);
    }

    void c_config_get_version(void)
    {
       /* Get the 'dbeng' version ID string. Function replies
          with a 'dbeng' i/o code. */

       char *ver;
       char mname[] = "c_config_get_version";
       int ret;

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

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

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

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

             tmp_path */

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

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

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

       len = strlen(comm);

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

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

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

             session_table */

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

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

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

       len = strlen(comm);

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

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

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

             catalog */

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

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

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

       len = strlen(comm);

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

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

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

             log_name */

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

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

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

       len = strlen(comm);

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

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

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

             flag */

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

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

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

       len = strlen(comm);

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

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

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

       free(flag_char);

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

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

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

             flag */

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

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

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

       len = strlen(comm);

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

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

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

       free(flag_char);

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

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

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

             flag */

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

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

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

       len = strlen(comm);

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

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

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

       free(flag_char);

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

       ret = db_config_set_catalog_flag(flag);

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

       (void)db_config_get_replicate_flag(&rep_flag);

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

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

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

             flag */

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

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

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

       len = strlen(comm);

       if ((flag_char = malloc(len + 1)) == NULL)
          {
          db_io_code_log(mname, "alloc fail[flag_char]", DBENG_MEMORY_FAIL);
          (void)do_reply_code(DBENG_MEMORY_FAIL);
          return;
          }

       (void)word(comm, flag_char, 1);

       if (!qatoi(flag_char, &flag))
          {
          free(flag_char);
          db_io_code_log(mname, "flag not numeric", DBENG_INVALID_FUNCTION);
          (void)do_reply_code(DBENG_INVALID_FUNCTION);
          return;
          }

       free(flag_char);

       if (flag != TRUE && flag != FALSE)
          {
          db_io_code_log(mname, "flag not zero or one", DBENG_INVALID_FUNCTION);
          (void)do_reply_code(DBENG_INVALID_FUNCTION);
          return;
          }

    #ifdef IPC_TCP
       ret = db_config_set_replicate_flag(flag);

       /* initialize replication if flag is high */

       if (ret == DBENG_OK)
          if (flag)
             {
             if ((ret = dbengrep_init()) != DBENG_OK)
                {
                db_io_code_log(mname, "bad rc from dbengrep_init,forcing flag "
                              "down", ret);
                (void)db_config_set_replicate_flag(FALSE);
                }
             }
          else
             if ((ret = dbengrep_end()) != DBENG_OK)
                db_io_code_log(mname, "bad rc from dbengrep_end", ret);
    #else
       db_io_code_log(mname, "TCP IPC method only", DBENG_FUNCTION_NOT_IMPLEMENTED);
       ret = DBENG_FUNCTION_NOT_IMPLEMENTED;
    #endif

       (void)do_reply_code(ret);
       logman("%s:normal exit", mname);
    }

    void c_get_open_table_list(char *comm)
    {
       /* Get the list of open tables. Syntax:

             [pat]

          Where 'pat' is a string pattern acceptable to
          the 'pmatch' function consisting of physical
          file name pattern. Function replies with
          a list (delimited by 'DBENG_LIST_DELIM') of
          matching entries along with a 'DBENG'
          code. */

       char *list_out;
       char mname[] = "c_get_open_table_list";
       int ret;

       logman("%s:enter", mname);

       if ((list_out = (char *)malloc(DBENG_MAXRECFIELD)) == NULL)
          {
          db_io_code_log(mname, "alloc fail[list_out]", DBENG_MEMORY_FAIL);
          (void)do_reply_char(DBENG_MEMORY_FAIL, "");
          return;
          }

       ret = db_get_open_table_list(comm, list_out);
       (void)do_reply_char(ret, list_out);
       free(list_out);
       db_io_code_log(mname, "normal exit", ret);
    }

    void c_replicate(char *comm)
    {
       /* Process a received replication command. Command will only be
          processed if the replication flag is high. Applies
          to TCP IPC method only. */

       char mname[] = "c_replicate";
       int ret, rep_flag;

    #ifdef IPC_TCP
       (void)db_config_get_replicate_flag(&rep_flag);

       if (rep_flag)
          {
          if ((ret = dbengrep_recv(comm)) != DBENG_OK)
             db_io_code_log(mname, "received replication command failed", ret);
          }
       else
          ret = DBENG_REPLICATION_NOT_ACTIVE;
    #else
       db_io_code_log(mname, "TCP IPC method only", DBENG_FUNCTION_NOT_IMPLEMENTED);
       ret = DBENG_FUNCTION_NOT_IMPLEMENTED;
    #endif

       (void)do_reply_code(ret);
       logman("%s:normal exit", mname);
    }

    void c_replicate_update(void)
    {
       /* Update all replication information. Command will only be
          processed if the replication flag is high. Applies
          to TCP IPC method only. */

       char mname[] = "c_replicate_update";
       int ret, rep_flag;

    #ifdef IPC_TCP
       (void)db_config_get_replicate_flag(&rep_flag);

       if (rep_flag)
          {
          if ((ret = dbengrep_init()) != DBENG_OK)
             db_io_code_log(mname, "update failed", ret);
          }
       else
          ret = DBENG_REPLICATION_NOT_ACTIVE;
    #else
       db_io_code_log(mname, "TCP IPC method only", DBENG_FUNCTION_NOT_IMPLEMENTED);
       ret = DBENG_FUNCTION_NOT_IMPLEMENTED;
    #endif

       (void)do_reply_code(ret);
       logman("%s:normal exit", mname);
    }

    void c_delete_table(char *comm)
    {
       /* Delete a table. The file name is expected on the command line.
          Function replies with a 'dbeng' code. Syntax:

             file_name */

       char mname[] = "c_delete_table", *fname;
       int ret, driret;

       logman("%s:enter", mname);

       if (comm == (char *)NULL || !strlen(comm))
          {
          db_io_code_log(mname, "null or empty[comm]", DBENG_INVALID_FILE_NAME);
          (void)do_reply_code(DBENG_INVALID_FILE_NAME);
          return;
          }

       if ((fname = (char *)malloc(strlen(comm) + 1)) == NULL)
          {
          db_io_code_log(mname, "alloc fail[fname]", DBENG_MEMORY_FAIL);
          (void)do_reply_code(DBENG_MEMORY_FAIL);
          return;
          }

       if (!command_word(comm, fname, 1))
          {
          free(fname);
          db_io_code_log(mname, "bad rc from command_word[fname]",
                         DBENG_INTERNAL_ERROR);
          (void)do_reply_code(DBENG_INTERNAL_ERROR);
          return;
          }

       ret = db_delete_table(fname);
       free(fname);

       if ((driret = do_reply_code(ret)) != DBENG_OK)
          {
          logman("%s:bad ret from do_reply_code,rc[%d]", driret);
          return;
          }

       db_io_code_log(mname, "normal exit", ret);
    }

    void c_exist(char *comm)
    {
       /* Determine whether a table exists. Syntax:

             file_name */

       char mname[] = "c_exist", *filename;
       int exist_flag = FALSE;
       int ret, len, driret;

       logman("%s:enter", mname);

       if (comm == (char *)NULL || !strlen(comm))
          {
          db_io_code_log(mname, "null or empty[comm]", DBENG_INVALID_FILE_NAME);
          (void)do_reply_int(DBENG_INVALID_FILE_NAME, exist_flag);
          return;
          }

       len = strlen(comm);

       if ((filename = malloc(len + 1)) == NULL)
          {
          db_io_code_log(mname, "alloc fail[filename]", DBENG_MEMORY_FAIL);
          (void)do_reply_int(DBENG_MEMORY_FAIL, 0);
          return;
          }

       (void)command_word(comm, filename, 1);
       ret = db_exist(filename, &exist_flag);
       free(filename);

       if ((driret = do_reply_int(ret, exist_flag)) != DBENG_OK)
          {
          logman("%s:bad ret from do_reply_int:rc=%d", mname, driret);
          return;
          }

       db_io_code_log(mname, "normal exit", ret);
    }

    void c_clear_table(char *comm)
    {
       /* Clear a table of all records. Syntax:

             file_name */

       char mname[] = "c_clear_table", *filename;
       int ret, len, driret;

       logman("%s:enter", mname);

       if (comm == (char *)NULL || !strlen(comm))
          {
          db_io_code_log(mname, "null or empty[comm]", DBENG_INVALID_FILE_NAME);
          (void)do_reply_code(DBENG_INVALID_FILE_NAME);
          return;
          }

       len = strlen(comm);

       if ((filename = malloc(len + 1)) == NULL)
          {
          db_io_code_log(mname, "alloc fail[filename]", DBENG_MEMORY_FAIL);
          (void)do_reply_code(DBENG_MEMORY_FAIL);
          return;
          }

       (void)command_word(comm, filename, 1);
       ret = db_clear_table(filename);
       free(filename);

       if ((driret = do_reply_code(ret)) != DBENG_OK)
          {
          logman("%s:bad ret from do_reply_int:rc=%d", mname, driret);
          return;
          }

       db_io_code_log(mname, "normal exit", ret);
    }

    void c_copy_table(char *comm)
    {
       /* Copy a table from source to destination. Both tables are
          expected to be open. Function replies with a DBENG io code.
          Syntax:

             source_tid destination_tid */

       char *src_tid_char, *dest_tid_char;
       char mname[] = "c_copy_table";
       int src_tid, dest_tid;
       int len;
       int ret;

       logman("%s:enter", mname);

       if (comm == (char *)NULL || !strlen(comm))
          {
          db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
          (void)do_reply_code(DBENG_NO_SUCH_TID);
          return;
          }

       len = strlen(comm);

       if (words(comm) < 2)
          {
          db_io_code_log(mname, "missing tid", DBENG_INVALID_FUNCTION);
          (void)do_reply_code(DBENG_INVALID_FUNCTION);
          return;
          }

       if ((src_tid_char = (char *)malloc(len + 1)) == (char *)NULL)
          {
          db_io_code_log(mname, "alloc fail[src_tid_char]", DBENG_MEMORY_FAIL);
          (void)do_reply_code(DBENG_MEMORY_FAIL);
          return;
          }

       (void)word(comm, src_tid_char, 1);

       if (!qatoi(src_tid_char, &src_tid))
          {
          free(src_tid_char);
          db_io_code_log(mname, "non numeric source tid", DBENG_NO_SUCH_TID);
          (void)do_reply_code(DBENG_NO_SUCH_TID);
          return;
          }

       if (src_tid <= 0)
          {
          free(src_tid_char);
          db_io_code_log(mname, "source tid out of range", DBENG_NO_SUCH_TID);
          (void)do_reply_code(DBENG_NO_SUCH_TID);
          return;
          }

       free(src_tid_char);

       if ((dest_tid_char = (char *)malloc(len + 1)) == (char *)NULL)
          {
          db_io_code_log(mname, "alloc fail[dest_tid_char]", DBENG_MEMORY_FAIL);
          (void)do_reply_code(DBENG_MEMORY_FAIL);
          return;
          }

       (void)word(comm, dest_tid_char, 2);

       if (!qatoi(dest_tid_char, &dest_tid))
          {
          free(dest_tid_char);
          db_io_code_log(mname, "non numeric destination tid", DBENG_NO_SUCH_TID);
          (void)do_reply_code(DBENG_NO_SUCH_TID);
          return;
          }

       if (dest_tid <= 0)
          {
          free(dest_tid_char);
          db_io_code_log(mname, "destination tid out of range", DBENG_NO_SUCH_TID);
          (void)do_reply_code(DBENG_NO_SUCH_TID);
          return;
          }

       free(dest_tid_char);
       logman("%s:before db_copy_table:src_tid=%d,dest_tid=%d", mname,
                     src_tid, dest_tid);
       ret = db_copy_table(src_tid, dest_tid);
       logman("%s:after db_copy_table", mname);
       (void)do_reply_code(ret);
       db_io_code_log(mname, "normal exit", ret);
    }

    void c_get_catalog_list(char *comm)
    {
       /* Get a list of catalog entries. Syntax:

             [pat]

          Where 'pat' is a string pattern acceptable to
          the 'pmatch' function consisting of logical
          table name pattern. Function replies with
          a list (delimited by 'DBENG_LIST_DELIM') of
          matching catalog entries along with a 'DBENG'
          code. */

       char *list_out;
       char mname[] = "c_get_catalog_list";
       int ret;

       logman("%s:enter", mname);

       if ((list_out = (char *)malloc(DBENG_MAXRECFIELD)) == NULL)
          {
          db_io_code_log(mname, "alloc fail[list_out]", DBENG_MEMORY_FAIL);
          (void)do_reply_char(DBENG_MEMORY_FAIL, "");
          return;
          }

       ret = db_get_catalog_list(comm, list_out);
       (void)do_reply_char(ret, list_out);
       free(list_out);
       db_io_code_log(mname, "normal exit", ret);
    }

    void c_delete_field(char *comm)
    {
       /* Completly delete a field. Note that the field numbers of all
          fields after the one being deleted will change. Function replies
          with a DBENG io code. Syntax:

          tid field_number */

       char *tid_char, *fnum_char, mname[] = "c_delete_field";
       int nwords, fnum, tid, len, ret;

       logman("%s:enter", mname);

       if (comm == (char *)NULL || !strlen(comm))
          {
          db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
          (void)do_reply_code(DBENG_NO_SUCH_TID);
          return;
          }

       len = strlen(comm);
       nwords = words(comm);

       if (nwords < 2)
          {
          db_io_code_log(mname, "missing field number", DBENG_NO_SUCH_FIELD);
          (void)do_reply_code(DBENG_NO_SUCH_FIELD);
          return;
          }

       if ((tid_char = malloc(len + 1)) == NULL)
          {
          db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
          (void)do_reply_code(DBENG_MEMORY_FAIL);
          return;
          }

       (void)command_word(comm, tid_char, 1);

       if (!qatoi(tid_char, &tid))
          {
          free(tid_char);
          db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
          (void)do_reply_code(DBENG_NO_SUCH_TID);
          return;
          }

       if (tid <= 0)
          {
          free(tid_char);
          db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
          (void)do_reply_code(DBENG_NO_SUCH_TID);
          return;
          }

       free(tid_char);

       if ((fnum_char = malloc(len + 1)) == NULL)
          {
          db_io_code_log(mname, "alloc fail[fnum_char]", DBENG_MEMORY_FAIL);
          (void)do_reply_code(DBENG_MEMORY_FAIL);
          return;
          }

       (void)command_word(comm, fnum_char, 2);

       if (!qatoi(fnum_char, &fnum))
          {
          db_io_code_log(mname, "non numeric field number",
                         DBENG_INVALID_FUNCTION);
          (void)do_reply_code(DBENG_INVALID_FUNCTION);
          free(fnum_char);
          return;
          }

       if (fnum <= 0)
          {
          db_io_code_log(mname, "field number out of range",
                         DBENG_INVALID_FUNCTION);
          (void)do_reply_code(DBENG_INVALID_FUNCTION);
          free(fnum_char);
          return;
          }

       free(fnum_char);
       ret = db_delete_field(tid, fnum);
       (void)do_reply_code(ret);
       db_io_code_log(mname, "normal exit", ret);
    }

    void c_delete_subfield(char *comm)
    {
       /* Completly delete a subfield within a field. Note that the subfield
          numbers of all subfields after the one being deleted will change.
          Function replies with a DBENG io code. Syntax:

          tid field_number subfield_number */

       char *tid_char, *fnum_char, *sfnum_char, mname[] = "c_delete_subfield";
       int nwords, fnum, sfnum, tid, len, ret;

       logman("%s:enter", mname);

       if (comm == (char *)NULL || !strlen(comm))
          {
          db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
          (void)do_reply_code(DBENG_NO_SUCH_TID);
          return;
          }

       len = strlen(comm);
       nwords = words(comm);

       if (nwords < 2)
          {
          db_io_code_log(mname, "missing field number", DBENG_NO_SUCH_FIELD);
          (void)do_reply_code(DBENG_NO_SUCH_FIELD);
          return;
          }

       if (nwords < 3)
          {
          db_io_code_log(mname, "missing subfield number", DBENG_NO_SUCH_SUBFIELD);
          (void)do_reply_code(DBENG_NO_SUCH_SUBFIELD);
          return;
          }

       if ((tid_char = malloc(len + 1)) == NULL)
          {
          db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
          (void)do_reply_code(DBENG_MEMORY_FAIL);
          return;
          }

       (void)command_word(comm, tid_char, 1);

       if (!qatoi(tid_char, &tid))
          {
          free(tid_char);
          db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
          (void)do_reply_code(DBENG_NO_SUCH_TID);
          return;
          }

       if (tid <= 0)
          {
          free(tid_char);
          db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
          (void)do_reply_code(DBENG_NO_SUCH_TID);
          return;
          }

       free(tid_char);

       if ((fnum_char = malloc(len + 1)) == NULL)
          {
          db_io_code_log(mname, "alloc fail[fnum_char]", DBENG_MEMORY_FAIL);
          (void)do_reply_code(DBENG_MEMORY_FAIL);
          return;
          }

       (void)command_word(comm, fnum_char, 2);

       if (!qatoi(fnum_char, &fnum))
          {
          db_io_code_log(mname, "non numeric field number",
                         DBENG_INVALID_FUNCTION);
          (void)do_reply_code(DBENG_INVALID_FUNCTION);
          free(fnum_char);
          return;
          }

       if (fnum <= 0)
          {
          db_io_code_log(mname, "field number out of range",
                         DBENG_INVALID_FUNCTION);
          (void)do_reply_code(DBENG_INVALID_FUNCTION);
          free(fnum_char);
          return;
          }

       free(fnum_char);

       if ((sfnum_char = malloc(len + 1)) == NULL)
          {
          db_io_code_log(mname, "alloc fail[sfnum_char]", DBENG_MEMORY_FAIL);
          (void)do_reply_code(DBENG_MEMORY_FAIL);
          return;
          }

       (void)command_word(comm, sfnum_char, 3);

       if (!qatoi(sfnum_char, &sfnum))
          {
          db_io_code_log(mname, "non numeric subfield number",
                         DBENG_INVALID_FUNCTION);
          (void)do_reply_code(DBENG_INVALID_FUNCTION);
          free(sfnum_char);
          return;
          }

       if (sfnum <= 0)
          {
          db_io_code_log(mname, "subfield number out of range",
                         DBENG_INVALID_FUNCTION);
          (void)do_reply_code(DBENG_INVALID_FUNCTION);
          free(sfnum_char);
          return;
          }

       free(sfnum_char);
       ret = db_delete_subfield(tid, fnum, sfnum);
       (void)do_reply_code(ret);
       db_io_code_log(mname, "normal exit", ret);
    }

    void c_delete_subsubfield(char *comm)
    {
       /* Completly delete a subsubfield within a subfield. Note that the
          subsubfield numbers of all subsubfields after the one being deleted
          will change. Function replies with a DBENG io code. Syntax:

          tid field_number subfield_number subsubfield_number */

       char *tid_char, *fnum_char, *sfnum_char, *ssfnum_char;
       char mname[] = "c_delete_subsubfield";
       int nwords, fnum, sfnum, ssfnum, tid, len, ret;

       logman("%s:enter", mname);

       if (comm == (char *)NULL || !strlen(comm))
          {
          db_io_code_log(mname, "null or empty[comm]", DBENG_NO_SUCH_TID);
          (void)do_reply_code(DBENG_NO_SUCH_TID);
          return;
          }

       len = strlen(comm);
       nwords = words(comm);

       if (nwords < 2)
          {
          db_io_code_log(mname, "missing field number", DBENG_NO_SUCH_FIELD);
          (void)do_reply_code(DBENG_NO_SUCH_FIELD);
          return;
          }

       if (nwords < 3)
          {
          db_io_code_log(mname, "missing subfield number", DBENG_NO_SUCH_SUBFIELD);
          (void)do_reply_code(DBENG_NO_SUCH_SUBFIELD);
          return;
          }

       if (nwords < 4)
          {
          db_io_code_log(mname, "missing subsubfield number",
                         DBENG_NO_SUCH_SUBSUBFIELD);
          (void)do_reply_code(DBENG_NO_SUCH_SUBSUBFIELD);
          return;
          }

       if ((tid_char = malloc(len + 1)) == NULL)
          {
          db_io_code_log(mname, "alloc fail[tid_char]", DBENG_MEMORY_FAIL);
          (void)do_reply_code(DBENG_MEMORY_FAIL);
          return;
          }

       (void)command_word(comm, tid_char, 1);

       if (!qatoi(tid_char, &tid))
          {
          free(tid_char);
          db_io_code_log(mname, "non numeric tid", DBENG_NO_SUCH_TID);
          (void)do_reply_code(DBENG_NO_SUCH_TID);
          return;
          }

       if (tid <= 0)
          {
          free(tid_char);
          db_io_code_log(mname, "tid out of range", DBENG_NO_SUCH_TID);
          (void)do_reply_code(DBENG_NO_SUCH_TID);
          return;
          }

       free(tid_char);

       if ((fnum_char = malloc(len + 1)) == NULL)
          {
          db_io_code_log(mname, "alloc fail[fnum_char]", DBENG_MEMORY_FAIL);
          (void)do_reply_code(DBENG_MEMORY_FAIL);
          return;
          }

       (void)command_word(comm, fnum_char, 2);

       if (!qatoi(fnum_char, &fnum))
          {
          db_io_code_log(mname, "non numeric field number",
                         DBENG_INVALID_FUNCTION);
          (void)do_reply_code(DBENG_INVALID_FUNCTION);
          free(fnum_char);
          return;
          }

       if (fnum <= 0)
          {
          db_io_code_log(mname, "field number out of range",
                         DBENG_INVALID_FUNCTION);
          (void)do_reply_code(DBENG_INVALID_FUNCTION);
          free(fnum_char);
          return;
          }

       free(fnum_char);

       if ((sfnum_char = malloc(len + 1)) == NULL)
          {
          db_io_code_log(mname, "alloc fail[sfnum_char]", DBENG_MEMORY_FAIL);
          (void)do_reply_code(DBENG_MEMORY_FAIL);
          return;
          }

       (void)command_word(comm, sfnum_char, 3);

       if (!qatoi(sfnum_char, &sfnum))
          {
          db_io_code_log(mname, "non numeric subfield number",
                         DBENG_INVALID_FUNCTION);
          (void)do_reply_code(DBENG_INVALID_FUNCTION);
          free(sfnum_char);
          return;
          }

       if (sfnum <= 0)
          {
          db_io_code_log(mname, "subfield number out of range",
                         DBENG_INVALID_FUNCTION);
          (void)do_reply_code(DBENG_INVALID_FUNCTION);
          free(sfnum_char);
          return;
          }

       free(sfnum_char);

       if ((ssfnum_char = malloc(len + 1)) == NULL)
          {
          db_io_code_log(mname, "alloc fail[ssfnum_char]", DBENG_MEMORY_FAIL);
          (void)do_reply_code(DBENG_MEMORY_FAIL);
          return;
          }

       (void)command_word(comm, ssfnum_char, 4);

       if (!qatoi(ssfnum_char, &ssfnum))
          {
          db_io_code_log(mname, "non numeric subsubfield number",
                         DBENG_INVALID_FUNCTION);
          (void)do_reply_code(DBENG_INVALID_FUNCTION);
          free(ssfnum_char);
          return;
          }

       if (ssfnum <= 0)
          {
          db_io_code_log(mname, "subsubfield number out of range",
                         DBENG_INVALID_FUNCTION);
          (void)do_reply_code(DBENG_INVALID_FUNCTION);
          free(ssfnum_char);
          return;
          }

       free(ssfnum_char);
       ret = db_delete_subsubfield(tid, fnum, sfnum, ssfnum);
       (void)do_reply_code(ret);
       db_io_code_log(mname, "normal exit", ret);
    }

    int c_terminate(char *comm)
    {
       /* Terminate the server. Check the supplied password first.
          Syntax:

             password

          Function returns 'TRUE' if correct password was supplied,
          'FALSE' otherwise. */

       char mname[] = "c_terminate";
       char wrd[256];
       int ret;

       logman("%s:enter", mname);

       if (comm == (char *)NULL || !strlen(comm))
          {
          db_io_code_log(mname, "null or empty[comm]", DBENG_INVALID_FUNCTION);
          (void)do_reply_code(DBENG_INVALID_FUNCTION);
          return(FALSE);
          }

       if (!command_word(comm, wrd, 1))
          {
          (void)do_reply_code(DBENG_INTERNAL_ERROR);
          logman("%s:error getting password", mname);
          return(FALSE);
          }

       if (!strcmp(wrd, DBSRV_TERM_PASSWD))
          {
          (void)do_reply_code(DBENG_OK);
          return(TRUE);
          }

       logman("%s:illegal terminate request", mname);
       (void)do_reply_code(DBENG_ACCESS_DENIED);
       return(FALSE);
    }

    void c_trans_num(void)
    {
       /* Get the current transaction count. Syntax:

             DBENG_SEND_TRANS_NUM */

       char mname[] = "c_trans_num";
       long count;

       logman("%s:enter", mname);

    #ifdef IPC_TCP
       count = ipc_trans_num();
    #else
       count = server_trans_num;
    #endif

       (void)do_reply_long(DBENG_OK, count);
       logman("%s:normal exit", mname);
    }

    void c_connect_num(void)
    {
       /* Get the current connection count. Syntax:

             DBENG_SEND_CONNECT_NUM */

       char mname[] = "c_connect_num";
       int count;

       logman("%s:enter", mname);

    #ifdef IPC_TCP
       count = ipc_connect_num();
       (void)do_reply_int(DBENG_OK, count);
    #else
       (void)do_reply_int(DBENG_FUNCTION_NOT_IMPLEMENTED, 0);
    #endif

       logman("%s:normal exit", mname);
    }

    /* IPC primatives */

    int do_reply_int(int reply_code, int int_value)
    {
       /* Send a reply to a request which returns an int in addition
          to the reply code. Function returns 'DBENG_OK' upon success,
          an error code otherwise. */

       char reply_char[50];
       int anint = 0;

       if (reply_code == DBENG_OK)
          anint = int_value;

       memset(reply_char, 0, 50);
       sprintf(reply_char, "%d %d", reply_code, anint);
       logman("do_reply_int:reply=%s,%d", reply_char,
                     strlen(reply_char));

       if (ipc_send_data(reply_char) == 0)
          return(DBENG_VC_ERROR);

       return(DBENG_OK);
    }

    int do_reply_long(int reply_code, long long_value)
    {
       /* Send a reply to a request which returns a long in addition
          to the reply code. Function returns 'DBENG_OK' upon success,
          an error code otherwise. */

       char reply_char[50];
       int along = 0L;

       if (reply_code == DBENG_OK)
          along = long_value;

       memset(reply_char, 0, 50);
       sprintf(reply_char, "%d %ld", reply_code, along);
       logman("do_reply_long:reply=%s,%d", reply_char,
                     strlen(reply_char));

       if (ipc_send_data(reply_char) == 0)
          return(DBENG_VC_ERROR);

       return(DBENG_OK);
    }

    int do_reply_code(int reply_code)
    {
       /* Send a reply to a request which returns the reply code. Function
          returns 'DBENG_OK' upon success, an error code otherwise. */

       char reply_char[50];

       memset(reply_char, 0, 50);
       sprintf(reply_char, "%d", reply_code);
       logman("do_reply_code:reply=%s,%d", reply_char,
                     strlen(reply_char));

       if (ipc_send_data(reply_char) == 0)
          return(DBENG_VC_ERROR);

       return(DBENG_OK);
    }

    int do_reply_char(int reply_code, char *char_value)
    {
       /* Send a reply to a request that returns a string as well as
          the reply code. Function returns 'DBENG_OK' upon success, an
          error code otherwise. */

       char *reply_char;
       int len;

       if (char_value == (char *)NULL)
          return(DBENG_INVALID_FUNCTION);

       len = strlen(char_value);

       // alloc reply string, note that 'char_value' might be empty

       if ((reply_char = (char *)malloc(len + 10)) == (char *)NULL)
          return(DBENG_MEMORY_FAIL);

       memset(reply_char, 0, len + 10);
       sprintf(reply_char, "%d '%s'", reply_code, char_value);
       logman("do_reply_char:lreply=%d", strlen(reply_char));

       if (ipc_send_data(reply_char) == 0)
          {
          free(reply_char);
          return(DBENG_VC_ERROR);
          }

       free(reply_char);
       return(DBENG_OK);
    }

    void term_app(void)
    {
       // Prepare to terminate the application. Shutdown all IPC API's.

       db_end();
       logman("term_app:server down");

    #ifdef IPC_TCP
       (void)sloc_delete(server_port);
       sloc_term_api();
    #ifdef OS_WIN32
       WSACleanup();
    #endif
    #else
       (void)ipc_close();
    #endif

       (void)appinit_remove_name();
    }

    #ifdef IPC_TCP
    void usage(void)
    {
       /* Display program usage. */

       printf("usage:dbsrv [%cq] port\n", SWITCH_CHAR);
    }
    #endif

/* [<][>][^][v][top][bottom][index][help] */