## root/dbeng/dbengcfg.c

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

## DEFINITIONS

This source file includes following definitions.

1. dbeng_config_read
2. dbeng_config_get_tmp_path
3. dbeng_config_get_log
4. dbeng_config_is_session
5. dbeng_config_is_catalog
6. dbeng_config_get_session
7. dbeng_config_get_catalog
8. dbeng_config_get_log_flag
9. dbeng_config_get_session_flag
10. dbeng_config_get_catalog_flag
11. dbeng_config_get_replicate_flag
12. dbeng_config_get_version
13. dbeng_config_set_tmp_path
14. dbeng_config_set_log
15. dbeng_config_set_session
16. dbeng_config_set_catalog
17. dbeng_config_set_log_flag
18. dbeng_config_set_session_flag
19. dbeng_config_set_catalog_flag
20. dbeng_config_set_replicate_flag
21. dbeng_config_valid_tmp_path
22. dbeng_config_valid_session
23. dbeng_config_valid_catalog

    /* DBENG (Bbuuzzb) configuration module. This module reads the
       settings in the DBENG config file (DBENG_CONFIG_FILE).
       This module also provides the 'get' and 'set' low level
       access functions. Used in single user database applications
       and the database server.
       Rick Smereka, Copyright (C) 1998-2004.

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

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

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

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

       The DBENG config file is a normal ASCII file that can
       contain the following settings:

          tmp_path path
          log file
          session_table file
          catalog file

       'tmp_path' specifies the complete path to use for
       DBENG temporary files. If not specified, the
       path used will be 'DBENG_DEFAULT_TMP_PATH'.
       'log' is the path and file name of the
       DBENG error log. If not specified, the file
       used will be 'DBENG_DEFAULT_LOG'.
       'session_table' is the path and file name of
       the system session table. If not specified,
       the file used will be 'DBENG_DEFAULT_SESSION_TABLE'.
       'catalog' is the path and file name of the
       system catalog. If not specified, the file
       used will be 'DBENG_DEFAULT_CATALOG'.
       The session table is only used with
       the c/s version. It is currently used by 'dbsrv'.
       All data on the configuration lines after the
       required parameters and all lines not containing
       a valid keyword will be ignored.

       Original QNX version, Dec/98, Rick Smereka

       Ported to 32bit Windows under CodeWarrior V4.
       Jan/99, Rick Smereka

       Moved global configuration data from 'dbeng.c' into
       this module. Also moved 'get' functions and wrote
       'set' functions. Wrote 'valid' functions.
       Ported to HP-UX under GNU C 2.8.1.
       Feb/99, Rick Smereka

       Added session table and catalog functions and put
       them on conditional compile only with the multiuser
       define. Changed 'error_log' to 'log'. Added on/off
       switches for the log, session table and catalog
       along with 'get' and 'set' functions.
       Mar/99, Rick Smereka

       Added support for obtaining the Bbuuzzb version ID.
       Apr/99, Rick Smereka

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

       Added include of 'flsocket.h'. Mar/2000, Rick Smereka

       Added include of 'dbeng.h'. Feb/2001, Rick Smereka

       Changed 'session_flag' and 'catalog_flag' default values
       to 'FALSE'. Jun/2001, Rick Smereka

       Changed function 'dbeng_config_is_systable' to detect temporary
       tables. Oct/2001, Rick Smereka

       Added member 'replicate_flag' to configuration structure. Added
       functions 'dbeng_config_get_replicate_flag' and
       'dbeng_config_set_replicate_flag'. Jan/2002, Rick Smereka

       Added function 'dbeng_config_is_session' and deleted the
       function 'dbeng_is_systable'. System tables are now
       recognized by the 'is_systable' flag in the 'dbeng_table'
       structure. Feb/2002, Rick Smereka

       Added function 'dbeng_config_is_catalog'. Jun/2002,
       Rick Smereka

       Changed function 'dbeng_config_set_session_flag' to flush
       the session table by calling 'dbeng_session_flush_all' when
       the session flag is set high. Jul/2002, Rick Smereka

       Ported to Debian Linux. Nov/2002, Rick Smereka

       Changed 'dbeng_config' structure to always contain catalog
       information and enabled config catalog functions
       in both single user apps and the database server. Nov/2003,
       Rick Smereka

       Modified 'dbeng_config_read' to automatically enable the catalog
       in single user mode if a catalog table was supplied in the config
       file. Feb/2004, Rick Smereka

       Changed all logging calls from 'sys_log' to 'logman'.
       Changed function 'dbeng_config_set_log' so that it no longer
       attempts to validate the path/file name of the log.
       Changed function 'dbeng_config_set_log_flag' so that it
       activates or de-activates logging.
       Added include of 'appinit.h'.
       Removed private function 'dbeng_config_valid_log'.
       Mar/2004, Rick Smereka */

    #include "stdhead.h"
    #include "dbeng.h"
    #include "dbmess.h"
    #include "dblocal.h"
    #include "dbengcfg.h"
    #include "dbengver.h"
    #include "dbiocode.h"

    #ifndef OS_DOS
    #include "appinit.h"
    #endif

    /* global configuration data */

    struct
       {
       char *tmp_path;
       char *log;
       int log_flag;
       char *catalog;
       int catalog_flag;
    #ifdef MULTIUSER
       char *session_table;
       int session_flag;
       int replicate_flag;
       } dbeng_config = {(char *)NULL, (char *)NULL, FALSE, (char *)NULL, FALSE,
                         (char *)NULL, FALSE, FALSE};
    #else
       } dbeng_config = {(char *)NULL, (char *)NULL, FALSE, (char *)NULL, FALSE};
    #endif

    /* private functions */

    static int dbeng_config_valid_tmp_path(char *);
    static int dbeng_config_valid_catalog(char *);

    #ifdef MULTIUSER
    static int dbeng_config_valid_session(char *);
    #endif

    int dbeng_config_read(char *fname)
    {
       /* Read and parse the DBENG config file 'fname'.
          Upon successful completion, the global configuration
          data will be loaded from the file. Note that missing
          data will be filled in from default data as defined
          in 'dbengcfg.h'. Function returns a 'dbeng' code. */

       FILE *in;
       char *line, *word, *ucase_word;
       char mname[25];
       int nwords;
       int ret;

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

       /* attempt to open config file, if not found, attempt
          to load compiled defaults and exit */

       if ((in = fopen(fname, "r")) == (FILE *)NULL)
          {
          if ((ret = dbeng_config_set_tmp_path(DBENG_DEFAULT_TMP_PATH)) !=
               DBENG_OK)
             {
             dbeng_io_code_log(mname,
                               "exit:bad ret from dbeng_config_set_tmp_path",
                               ret);
             return(ret);
             }

          if ((ret = dbeng_config_set_log(DBENG_DEFAULT_LOG)) !=
             DBENG_OK)
             {
             dbeng_io_code_log(mname,
                               "exit:bad ret from dbeng_config_set_log", ret);
             return(ret);
             }

    #ifdef MULTIUSER
          if ((ret = dbeng_config_set_session(DBENG_DEFAULT_SESSION))
               != DBENG_OK)
             {
             dbeng_io_code_log(mname,
                               "exit:bad ret from dbeng_config_set_session_table",
                               ret);
             return(ret);
             }
    #endif

          if ((ret = dbeng_config_set_catalog(DBENG_DEFAULT_CATALOG)) != DBENG_OK)
             {
             dbeng_io_code_log(mname,
                               "exit:bad ret from dbeng_config_set_catalog",
                               ret);
             return(ret);
             }

          dbeng_io_code_log(mname, "exit:no config file, loaded defaults",
                            DBENG_CONFIG_UNABLE_TO_OPEN);
          return(DBENG_CONFIG_UNABLE_TO_OPEN);
          }

       /* alloc line buffer */

       if ((line = (char *)malloc(BUFSIZE)) == (char *)NULL)
          {
          fclose(in);
          dbeng_io_code_log(mname, "alloc fail[line]", DBENG_MEMORY_FAIL);
          return(DBENG_MEMORY_FAIL);
          }

       /* get first record/line */

       get_rec(in, line);

       while(!feof(in))
          {
          /* number of command words on line */

          nwords = command_words(line);

          /* must have at least two command words per record */

          if (nwords < 2)
             {
             free(line);
             fclose(in);
             dbeng_io_code_log(mname, "exit:missing parameter",
                               DBENG_CONFIG_PARAMETER_MISSING);
             return(DBENG_CONFIG_PARAMETER_MISSING);
             }

          /* create word string by dynamically copying and
             set length to zero */

          word = initstring(line);
          word[0] = EOS;

          /* get first command word on line */

          if (!command_word(line, word, 1))
             {
             free(word);
             free(line);
             fclose(in);
             dbeng_io_code_log(mname, "exit:command_word[1] fail",
                               DBENG_INTERNAL_ERROR);
             return(DBENG_INTERNAL_ERROR);
             }

          /* make another copy and convert it to upper case */

          ucase_word = initstring(word);
          ucase_word[0] = EOS;
          ucase(word, ucase_word);

          /* is it the 'tmp_path' keyword? */

          if (!strcmp(ucase_word, "TMP_PATH"))
             {
             word[0] = EOS;

             /* get second command word */

             if (!command_word(line, word, 2))
                {
                free(word);
                free(line);
                free(ucase_word);
                fclose(in);
                dbeng_io_code_log(mname, "exit:command_word[2,tmp_path] fail",
                               DBENG_INTERNAL_ERROR);
                return(DBENG_INTERNAL_ERROR);
                }

             /* set path */

             if ((ret = dbeng_config_set_tmp_path(word)) != DBENG_OK)
                {
                free(word);
                free(line);
                free(ucase_word);
                fclose(in);
                dbeng_io_code_log(mname, "exit:bad ret dbeng_config_set_tmp_path",
                                  ret);
                return(ret);
                }
             }

          /* is it the 'log' keyword? */

          if (!strcmp(ucase_word, "LOG"))
             {
             word[0] = EOS;

             if (!command_word(line, word, 2))
                {
                free(word);
                free(line);
                free(ucase_word);
                fclose(in);
                dbeng_io_code_log(mname, "exit:command_word[2,log] fail",
                                  DBENG_INTERNAL_ERROR);
                return(DBENG_INTERNAL_ERROR);
                }

             /* set log name */

             if ((ret = dbeng_config_set_log(word)) != DBENG_OK)
                {
                free(word);
                free(line);
                free(ucase_word);
                fclose(in);
                dbeng_io_code_log(mname, "exit:bad ret dbeng_config_set_log", ret);
                return(ret);
                }
             }

    #ifdef MULTIUSER
          /* is it the 'session_table' keyword?
             which is valid only for the database
             server */

          if (!strcmp(ucase_word, "SESSION_TABLE"))
             {
             word[0] = EOS;

             if (!command_word(line, word, 2))
                {
                free(word);
                free(line);
                free(ucase_word);
                fclose(in);
                dbeng_io_code_log(mname, "exit:command_word[2,session_table] fail",
                                  DBENG_INTERNAL_ERROR);
                return(DBENG_INTERNAL_ERROR);
                }

             if ((ret = dbeng_config_set_session(word)) != DBENG_OK)
                {
                free(word);
                free(line);
                free(ucase_word);
                fclose(in);
                dbeng_io_code_log(mname,
                                  "exit:bad ret dbeng_config_set_session",
                                  ret);
                return(ret);
                }
             }
    #endif

          // is it the 'catalog' keyword?

          if (!strcmp(ucase_word, "CATALOG"))
             {
             word[0] = EOS;

             if (!command_word(line, word, 2))
                {
                free(word);
                free(line);
                free(ucase_word);
                fclose(in);
                dbeng_io_code_log(mname, "exit:command_word[2,catalog] fail",
                                  DBENG_INTERNAL_ERROR);
                return(DBENG_INTERNAL_ERROR);
                }

             /* set error log path/name */

             if ((ret = dbeng_config_set_catalog(word)) != DBENG_OK)
                {
                free(word);
                free(line);
                free(ucase_word);
                fclose(in);
                dbeng_io_code_log(mname, "exit:bad ret dbeng_config_set_catalog",
                                  ret);
                return(ret);
                }
             }

          // dealloc temp vars

          free(word);
          free(ucase_word);

          // get next record

          get_rec(in, line);
          }

       fclose(in);
       free(line);

       /* handle defaults in the case of missing data */

       if (dbeng_config.tmp_path == (char *)NULL)
          if ((ret = dbeng_config_set_tmp_path(DBENG_DEFAULT_TMP_PATH)) !=
             DBENG_OK)
             {
             dbeng_io_code_log(mname, "exit:bad ret dbeng_config_set_tmp_path",
                               ret);
             return(ret);
             }

       if (dbeng_config.log == (char *)NULL)
          if ((ret = dbeng_config_set_log(DBENG_DEFAULT_LOG)) !=
             DBENG_OK)
             {
             dbeng_io_code_log(mname, "exit:bad ret dbeng_config_set_log",
                               ret);
             return(ret);
             }

    #ifdef MULTIUSER
       if (dbeng_config.session_table == (char *)NULL)
          if ((ret = dbeng_config_set_session(DBENG_DEFAULT_SESSION))
             != DBENG_OK)
             {
             dbeng_io_code_log(mname, "exit:bad ret dbeng_config_set_session",
                               ret);
             return(ret);
             }

       /* we set the default if no catalog given for the database
          server, single user apps will have no default if no
          catalog is given */

       if (dbeng_config.catalog == (char *)NULL)
          if ((ret = dbeng_config_set_catalog(DBENG_DEFAULT_CATALOG))
             != DBENG_OK)
             {
             dbeng_io_code_log(mname, "exit:bad ret dbeng_config_set_catalog",
                               ret);
             return(ret);
             }
    #else
       /* single user apps have the catalog enabled if it was
          supplied in the config file */

       if (dbeng_config.catalog != (char *)NULL)
          if ((ret = dbeng_config_set_catalog_flag(TRUE)) != DBENG_OK)
             {
             dbeng_io_code_log(mname, "exit:bad rc from "
                               "dbeng_config_set_catalog_flag", ret);
             return(ret);
             }
    #endif

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

    int dbeng_config_get_tmp_path(char *path)
    {
       /* Load the global 'dbeng_config.tmp_path' into 'path' which
          must already be allocated to sufficient size.
          Function returns 'DBENG_OK' upon success,
          an engine i/o code otherwise. */

       char mname[30];

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

       if (path == (char *)NULL)
          {
          dbeng_io_code_log(mname, "exit:[path]null", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       /* if global tmp path has not been loaded, it is an error */

       if (dbeng_config.tmp_path == (char *)NULL)
          {
          dbeng_io_code_log(mname, "exit:tmp path not loaded",
                            DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       strcpy(path, dbeng_config.tmp_path);
       dbeng_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }

    int dbeng_config_get_log(char *slog)
    {
       /* Load the global 'dbeng_config.log' into 'slog'
          which must already be allocated to sufficient size.
          Function returns 'DBENG_OK' upon success,
          an engine i/o code otherwise. */

       char mname[25];

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

       if (slog == (char *)NULL)
          {
          dbeng_io_code_log(mname, "exit:[slog]null", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       /* if log name has not been loaded, it is an error */

       if (dbeng_config.log == (char *)NULL)
          {
          dbeng_io_code_log(mname, "exit:log not loaded", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       strcpy(slog, dbeng_config.log);
       dbeng_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }

    #ifdef MULTIUSER
    int dbeng_config_is_session(char *fname)
    {
       /* Determine whether 'fname' is the session table. Function
          returns 'TRUE' if the session table was found, 'FALSE'
          otherwise. */

       char mname[] = "dbeng_config_is_session", ses_table[128];
       int session_flag;

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

       logman("%s:enter:fname=%s,l=%d", mname, fname, strlen(fname));
       (void)dbeng_config_get_session_flag(&session_flag);

       /* if session table is not active, cannot be the session table
          even if the name matches */

       if (!session_flag)
          {
          logman("%s:exit[FALSE]:session table not active", mname);
          return(FALSE);
          }

       (void)dbeng_config_get_session(ses_table);

       if (!strcmp(fname, ses_table))
          {
          logman("%s:exit[TRUE]:matches session table", mname);
          return(TRUE);
          }

       logman("%s:exit[FALSE]:no match", mname);
       return(FALSE);
    }
    #endif

    int dbeng_config_is_catalog(char *fname)
    {
       /* Determine whether 'fname' is the catalog. Function
          returns 'TRUE' if the catalog was found, 'FALSE'
          otherwise. */

       char mname[] = "dbeng_config_is_catalog", cat[128];
       int catalog_flag;

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

       logman("%s:enter:fname=%s,l=%d", mname, fname, strlen(fname));
       (void)dbeng_config_get_catalog_flag(&catalog_flag);
       cat[0] = EOS;

       /* if catalog is not active, cannot be the catalog
          even if the name matches */

       if (!catalog_flag)
          {
          logman("%s:exit[FALSE]:catalog not active", mname);
          return(FALSE);
          }

       (void)dbeng_config_get_catalog(cat);

       if (!strcmp(fname, cat))
          {
          logman("%s:exit[TRUE]:matches catalog", mname);
          return(TRUE);
          }

       logman("%s:exit[FALSE]:no match", mname);
       return(FALSE);
    }

    #ifdef MULTIUSER
    int dbeng_config_get_session(char *ses_table)
    {
       /* Load the global 'dbeng_config.session_table' into 'ses_table'
          which must already be allocated to sufficient size.
          Function returns 'DBENG_OK' upon success,
          an engine i/o code otherwise. */

       char mname[35];

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

       if (ses_table == (char *)NULL)
          {
          dbeng_io_code_log(mname, "exit:[ses_table]null", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       /* if session table path/name has not been loaded, it is an error */

       if (dbeng_config.session_table == (char *)NULL)
          {
          dbeng_io_code_log(mname, "exit:session table not loaded",
                            DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       strcpy(ses_table, dbeng_config.session_table);
       dbeng_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }
    #endif

    int dbeng_config_get_catalog(char *cat)
    {
       /* Load the global 'dbeng_config.catalog' into 'cat'
          which must already be allocated to sufficient size.
          Function returns 'DBENG_OK' upon success,
          an engine i/o code otherwise. */

       char mname[30];

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

       if (cat == (char *)NULL)
          {
          dbeng_io_code_log(mname, "exit:[cat]null", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       // if catalog path/name has not been loaded, catalog is not in use

       if (dbeng_config.catalog == (char *)NULL)
          {
          dbeng_io_code_log(mname, "exit:catalog not loaded",
                            DBENG_NO_CATALOG);
          return(DBENG_NO_CATALOG);
          }

       strcpy(cat, dbeng_config.catalog);
       dbeng_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }

    int dbeng_config_get_log_flag(int *flag)
    {
       /* Get the value of  'dbeng_config.log_flag' and load
          the value into 'flag'. Function returns 'DBENG_OK'
          upon success, an engine i/o code otherwise. */

       char mname[30];

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

       if (flag == (int *)NULL)
          {
          dbeng_io_code_log(mname, "exit:[flag] is null", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       *flag = dbeng_config.log_flag;
       dbeng_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }

    #ifdef MULTIUSER
    int dbeng_config_get_session_flag(int *flag)
    {
       /* Get the value of  'dbeng_config.session_flag' and load
          the value into 'flag'. Function returns 'DBENG_OK'
          upon success, an engine i/o code otherwise. */

       char mname[] = "dbeng_config_get_session_flag";

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

       if (flag == (int *)NULL)
          {
          dbeng_io_code_log(mname, "exit:[flag] is null", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       *flag = dbeng_config.session_flag;
       logman("%s:normal exit[0],flag=%d", mname, *flag);
       return(DBENG_OK);
    }
    #endif

    int dbeng_config_get_catalog_flag(int *flag)
    {
       /* Get the value of  'dbeng_config.catalog_flag' and load
          the value into 'flag'. Function returns 'DBENG_OK'
          upon success, an engine i/o code otherwise. */

       char mname[35];

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

       if (flag == (int *)NULL)
          {
          dbeng_io_code_log(mname, "exit:[flag] is null", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       *flag = dbeng_config.catalog_flag;
       logman("%s:normal exit[0],flag=%d", mname, *flag);
       return(DBENG_OK);
    }

    #ifdef MULTIUSER
    int dbeng_config_get_replicate_flag(int *flag)
    {
       /* Get the value of  'dbeng_config.replicate_flag' and load
          the value into 'flag'. Function returns 'DBENG_OK'
          upon success, an engine i/o code otherwise. */

       char mname[] = "dbeng_config_get_replicate_flag";

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

       if (flag == (int *)NULL)
          {
          dbeng_io_code_log(mname, "exit:[flag] is null", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       *flag = dbeng_config.replicate_flag;
       logman("%s:normal exit[0],flag=%d", mname, *flag);
       return(DBENG_OK);
    }
    #endif

    int dbeng_config_get_version(char *ver)
    {
       /* Get the 'dbeng' version ID string. Function returns
          'DBENG_OK' upon success with the version ID
          loaded into 'ver' which must already be allocated
          to sufficient size. Function returns a 'dbeng'
          i/o code otherwise. */

       char mname[] = "dbeng_config_get_version";

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

       if (ver == (char *)NULL)
          {
          dbeng_io_code_log(mname, "exit:[ver]is null", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       strcpy(ver, DBENG_VERSION);
       dbeng_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }

    int dbeng_config_set_tmp_path(char *path)
    {
       /* Load 'dbeng_config.tmp_path' with data from 'path'.
          'dbeng_config.tmp_path' is dynamically allocated.
          Function returns a 'dbeng' i/o code. */

       char mname[] = "dbeng_config_set_tmp_path";
       int len;
       int ret;

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

       if (path == (char *)NULL)
          {
          dbeng_io_code_log(mname, "exit:[path]null", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       len = strlen(path);

       if (!len)
          {
          dbeng_io_code_log(mname, "exit:[path]empty", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (len >= DBENG_PATH_LIMIT)
          {
          dbeng_io_code_log(mname, "exit:[path]too large",
                            DBENG_CONFIG_TMP_PATH_SIZE);
          return(DBENG_CONFIG_TMP_PATH_SIZE);
          }

       if ((ret = dbeng_config_valid_tmp_path(path)) != DBENG_OK)
          {
          dbeng_io_code_log(mname, "exit:bad ret dbeng_config_valid_tmp_path",
                            ret);
          return(ret);
          }

       if (dbeng_config.tmp_path != (char *)NULL)
          free(dbeng_config.tmp_path);

       if ((dbeng_config.tmp_path = (char *)malloc(len + 1)) == (char *)NULL)
          {
          dbeng_io_code_log(mname, "exit:alloc fail[dbeng_config.tmp_path]",
                            DBENG_MEMORY_FAIL);
          return(DBENG_MEMORY_FAIL);
          }

       strcpy(dbeng_config.tmp_path, path);
       dbeng_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }

    int dbeng_config_set_log(char *slog)
    {
       /* Load 'dbeng_config.log' with data from 'slog'.
          'dbeng_config.log' is dynamically allocated.
          Function returns a 'dbeng' i/o code. */

       char mname[] = "dbeng_config_set_log";
       int len;

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

       if (slog == (char *)NULL)
          {
          dbeng_io_code_log(mname, "exit:[slog]null", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       len = strlen(slog);

       if (!len)
          {
          dbeng_io_code_log(mname, "exit:[slog]empty", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (len >= DBENG_PATH_LIMIT)
          {
          dbeng_io_code_log(mname, "exit:[slog]too large",
                            DBENG_CONFIG_LOG_SIZE);
          return(DBENG_CONFIG_LOG_SIZE);
          }

       if (dbeng_config.log != (char *)NULL)
          free(dbeng_config.log);

       if ((dbeng_config.log = (char *)malloc(len + 1)) == (char *)NULL)
          {
          dbeng_io_code_log(mname, "exit:alloc fail[dbeng_config.log]",
                            DBENG_MEMORY_FAIL);
          return(DBENG_MEMORY_FAIL);
          }

       strcpy(dbeng_config.log, slog);
       dbeng_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }

    #ifdef MULTIUSER
    int dbeng_config_set_session(char *ses_table)
    {
       /* Load 'dbeng_config.session_table' with data from 'ses_table'.
          'dbeng_config.session_table' is dynamically allocated.
          If the file does not already exist, an attempt will be
          made to create it. Function returns a 'dbeng' i/o code. */

       char mname[35];
       int len;
       int ret;

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

       if (ses_table == (char *)NULL)
          {
          dbeng_io_code_log(mname, "exit:[ses_table]null", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       len = strlen(ses_table);

       if (!len)
          {
          dbeng_io_code_log(mname, "exit:[ses_table]empty",
                            DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (len >= DBENG_PATH_LIMIT)
          {
          dbeng_io_code_log(mname, "exit:[slog]too large",
                            DBENG_CONFIG_SESSION_TABLE_SIZE);
          return(DBENG_CONFIG_SESSION_TABLE_SIZE);
          }

       /* attempt to create the file if it does not exist */

       if (!exist(ses_table))
          if (!zcreate(ses_table))
             {
             dbeng_io_code_log(mname, "exit:cannot create session table",
                               DBENG_CANNOT_CREATE_TABLE);
             return(DBENG_CANNOT_CREATE_TABLE);
             }

       if ((ret = dbeng_config_valid_session(ses_table)) != DBENG_OK)
          {
          dbeng_io_code_log(mname, "exit:bad ret dbeng_config_valid_session", ret);
          return(ret);
          }

       if (dbeng_config.session_table != (char *)NULL)
          free(dbeng_config.session_table);

       if ((dbeng_config.session_table = (char *)malloc(len + 1)) == (char *)NULL)
          {
          dbeng_io_code_log(mname, "exit:alloc fail[dbeng_config.session_table]",
                            DBENG_MEMORY_FAIL);
          return(DBENG_MEMORY_FAIL);
          }

       strcpy(dbeng_config.session_table, ses_table);
       dbeng_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }
    #endif

    int dbeng_config_set_catalog(char *cat)
    {
       /* Load 'dbeng_config.catalog' with data from 'cat'.
          'dbeng_config.catalog' is dynamically allocated.
          The catalog file must exist. Function returns a
          'dbeng' i/o code. */

       char mname[30];
       int len;
       int ret;

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

       if (cat == (char *)NULL)
          {
          dbeng_io_code_log(mname, "exit:[cat]null", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       len = strlen(cat);

       if (!len)
          {
          dbeng_io_code_log(mname, "exit:[cat]empty", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (len >= DBENG_PATH_LIMIT)
          {
          dbeng_io_code_log(mname, "exit:[cat]too large",
                            DBENG_CONFIG_INVALID_CATALOG);
          return(DBENG_CONFIG_INVALID_CATALOG);
          }

       if ((ret = dbeng_config_valid_catalog(cat)) != DBENG_OK)
          {
          dbeng_io_code_log(mname, "exit:bad ret dbeng_config_valid_catalog",
                            ret);
          return(ret);
          }

       if (dbeng_config.catalog != (char *)NULL)
          free(dbeng_config.catalog);

       if ((dbeng_config.catalog = (char *)malloc(len + 1)) == (char *)NULL)
          {
          dbeng_io_code_log(mname, "exit:alloc fail[dbeng_config.catalog]",
                            DBENG_MEMORY_FAIL);
          return(DBENG_MEMORY_FAIL);
          }

       strcpy(dbeng_config.catalog, cat);
       dbeng_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }

    int dbeng_config_set_log_flag(int flag)
    {
       /* Set 'dbeng_config.log_flag' to the value of
          'flag' which must be zero or one and activate
          or de-activate logging. Function
          returns 'DBENG_OK' upon success, an
          engine i/o code otherwise. */

       char mname[] = "dbeng_config_set_log_flag";
       char *ap;

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

       if (flag != TRUE && flag != FALSE)
          {
          dbeng_io_code_log(mname, "exit:[flag]not 0 or 1", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (flag)
          {
          if ((ap = (char *)malloc(DBENG_PATH_LIMIT)) == (char *)NULL)
             {
             dbeng_io_code_log(mname, "exit:alloc fail[ap]", DBENG_MEMORY_FAIL);
             return(DBENG_MEMORY_FAIL);
             }

    #ifndef OS_DOS
          if (!appinit_get_name(ap))
             {
             free(ap);
             dbeng_io_code_log(mname, "exit:bad rc[FALSE] from appinit_get_name",
                               DBENG_INVALID_FUNCTION);
             return(DBENG_INVALID_FUNCTION);
             }
    #else
          ap[0] = EOS;
    #endif

          if (logman_start(dbeng_config.log, ap))
             {
             free(ap);
             dbeng_io_code_log(mname, "exit:bad rc[TRUE] from logman_start",
                               DBENG_CONFIG_INVALID_LOG);
             return(DBENG_CONFIG_INVALID_LOG);
             }

          free(ap);
          }
       else
          logman_end();

       dbeng_config.log_flag = flag;
       dbeng_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }

    #ifdef MULTIUSER
    int dbeng_config_set_session_flag(int flag)
    {
       /* Set 'dbeng_config.session_flag' to the value of
          'flag' which must be zero or one. The session
          table will be flushed when the session flag
          is set to on. Function returns 'DBENG_OK' upon
          success, an engine i/o code otherwise. */

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

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

       if (flag != TRUE && flag != FALSE)
          {
          dbeng_io_code_log(mname, "exit:[flag]not 0 or 1", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       dbeng_config.session_flag = flag;

       if (flag)
          if ((ret = dbeng_session_flush_all()) != DBENG_OK)
             dbeng_io_code_log(mname, "bad rc from dbeng_session_flush_all", ret);

       dbeng_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }
    #endif

    int dbeng_config_set_catalog_flag(int flag)
    {
       /* Set 'dbeng_config.catalog_flag' to the value of
          'flag' which must be zero or one. Function
          returns 'DBENG_OK' upon success, an
          engine i/o code otherwise. */

       char mname[30];

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

       if (flag != TRUE && flag != FALSE)
          {
          dbeng_io_code_log(mname, "exit:[flag]not 0 or 1", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       // if activating catalog, make sure catalog name is loaded

       if (flag == TRUE)
          if (dbeng_config.catalog == (char *)NULL || !strlen(dbeng_config.catalog))
             {
             dbeng_io_code_log(mname, "exit:no catalog name", DBENG_NO_CATALOG);
             return(DBENG_NO_CATALOG);
             }

       dbeng_config.catalog_flag = flag;
       dbeng_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }

    #ifdef MULTIUSER
    int dbeng_config_set_replicate_flag(int flag)
    {
       /* Set 'dbeng_config.replicate_flag' to the value of
          'flag' which must be zero or one. Catalog must also
          be active to activate replication. Function
          returns 'DBENG_OK' upon success, an
          engine i/o code otherwise. */

       char mname[] = "dbeng_config_set_replicate_flag";

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

       if (flag != TRUE && flag != FALSE)
          {
          dbeng_io_code_log(mname, "exit:[flag]not 0 or 1", DBENG_INVALID_FUNCTION);
          return(DBENG_INVALID_FUNCTION);
          }

       if (flag && !dbeng_config.catalog_flag)
          {
          dbeng_io_code_log(mname, "exit:catalog not active", DBENG_ACCESS_DENIED);
          return(DBENG_ACCESS_DENIED);
          }

       dbeng_config.replicate_flag = flag;
       dbeng_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }
    #endif

    static int dbeng_config_valid_tmp_path(char *path)
    {
       /* Validate the temporary 'path' by attempting
          to open a file for writing. Function
          returns 'DBENG_OK' upon success, an engine
          code otherwise. */

       FILE *tst;
       char mname[30];
       char rname[15], *tname;

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

       if (path == (char *)NULL || !strlen(path))
          {
          dbeng_io_code_log(mname, "exit:[path]null or empty",
                            DBENG_CONFIG_INVALID_TMP_PATH);
          return(DBENG_CONFIG_INVALID_TMP_PATH);
          }

       if (!unique(path, rname))
          {
          dbeng_io_code_log(mname, "bad ret unique",
                            DBENG_CONFIG_INVALID_TMP_PATH);
          return(DBENG_CONFIG_INVALID_TMP_PATH);
          }

       if ((tname = (char *)malloc(DBENG_PATH_LIMIT + 16)) == (char *)NULL)
          {
          dbeng_io_code_log(mname, "exit:alloc fail[tname]", DBENG_MEMORY_FAIL);
          return(DBENG_MEMORY_FAIL);
          }

       sprintf(tname, "%s%c%s", path, PATH_SEP, rname);

       if ((tst = fopen(tname, "w")) == (FILE *)NULL)
          {
          free(tname);
          dbeng_io_code_log(mname, "exit:cannot create tmp file",
                            DBENG_CONFIG_INVALID_TMP_PATH);
          return(DBENG_CONFIG_INVALID_TMP_PATH);
          }

       fclose(tst);
       unlink(tname);
       free(tname);
       dbeng_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }

    #ifdef MULTIUSER
    static int dbeng_config_valid_session(char *ses_table)
    {
       /* Validate the session table path/name by attempting
          to open it. Function returns 'DBENG_OK' upon
          success, an engine code otherwise. */

       char mname[35];
       int tid;
       int ret;

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

       if (ses_table == (char *)NULL || !strlen(ses_table))
          {
          dbeng_io_code_log(mname, "exit:[ses_table]null or empty",
                            DBENG_CONFIG_INVALID_SESSION_TABLE);
          return(DBENG_CONFIG_INVALID_SESSION_TABLE);
          }

       if ((ret = db_open(ses_table, &tid)) != DBENG_OK)
          {
          dbeng_io_code_log(mname, "exit:bad ret db_open", ret);
          return(ret);
          }

       (void)db_close(tid);
       dbeng_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }
    #endif

    static int dbeng_config_valid_catalog(char *cat)
    {
       /* Validate the system catalog path/name by attempting
          to open it. Function returns 'DBENG_OK' upon
          success, an engine code otherwise. */

       char mname[30];
       int tid;
       int ret;

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

       if (cat == (char *)NULL || !strlen(cat))
          {
          dbeng_io_code_log(mname, "exit:[cat]null or empty",
                            DBENG_CONFIG_INVALID_CATALOG);
          return(DBENG_CONFIG_INVALID_CATALOG);
          }

       if ((ret = db_open(cat, &tid)) != DBENG_OK)
          {
          dbeng_io_code_log(mname, "exit:bad ret db_open", ret);
          return(ret);
          }

       (void)db_close(tid);
       dbeng_io_code_log(mname, "normal exit", DBENG_OK);
       return(DBENG_OK);
    }

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