tinycobol/lib/fileio.c

3045 lines
82 KiB
C

/*
* Copyright (C) 1999-2004, Rildo Pragana, Ferran Pegueroles, Jim Noeth,
* Bernard Giroud, David Essex, Andrew Cameron.
* Copyright (C) 1993, 1991 Rildo Pragana.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1,
* or (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; see the file COPYING.LIB. If
* not, write to the Free Software Foundation, Inc., 59 Temple Place,
* Suite 330, Boston, MA 02111-1307 USA
*/
/*
*
* Cobol Compiler Library -- File Handling Module
*
*/
/* Permissible statements -- table from CD-1.2 (cobol draft) pp. 450
* -----------------------------------------------------------------
* acc. mode | statement | -------- open mode ------
* | | input output i-o extend
* ----------+------------+--------------------------
* line | read | X
* sequential| write | X X
* ----------+------------+--------------------------
* sequential| read | X X
* | write | X X
* | rewrite | X
* ----------+------------+--------------------------
* sequential| delete | X
* (relative | |
* & indexed| start | X X
* files) | |
* ----------+------------+--------------------------
* random | read | X X
* | write | X X
* | rewrite | X
* | start |
* | delete | X
* ----------+------------+--------------------------
* dynamic | read | X X
* | write | X X
* | rewrite | X
* | start | X X
* | delete | X
* ----------+------------+--------------------------
*/
/*
ANSI 2000x FILE STATUS CODES
---------------------------
See http://www.ncits.org/tc_home/j4.htm for details
*/
#include "htcoblib.h"
#include <sys/stat.h>
#include <fcntl.h>
#ifdef USE_LOCKSERVER
#include "flckclient.h"
extern struct fd_filename name_info[];
extern char *temp_key;
extern char *lockserverhost;
#endif
int ignore_lock = 0;
#define bcounter 5
#if defined(SunOS)
va_list __builtin_va_alist;
#endif
int need_lock = 0;
#define RETURN_STATUS(x) do { save_status (f, x); return(x); } while (0)
#ifdef USE_MF_COMPATABILITY
#define TCOB_EXTERNFILE_MFCOMP 1
#endif
#ifdef __MINGW32__
#ifndef LT_DIRSEP_CHAR
#define LT_DIRSEP_CHAR '\\'
#endif
#ifndef LT_DIRSEP_STR
#define LT_DIRSEP_STR "\\"
#endif
#else
#ifndef LT_DIRSEP_CHAR
#define LT_DIRSEP_CHAR '/'
#endif
#ifndef LT_DIRSEP_STR
#define LT_DIRSEP_STR "/"
#endif
#endif
static void save_status(struct file_desc *f, int status)
{
f->file_status[0] = status / 10 + '0';
f->file_status[1] = status % 10 + '0';
}
#ifdef WANT_ALL_DYNAMIC_LIBS
static DB *db_open_stub( const char *s, int i, int j, DBTYPE d, const void *p );
static DB *(* db_open)( const char *, int, int, DBTYPE, const void * ) =
db_open_stub;
/*------------------------------------------------------------------------*\
| |
| db_open_stub |
| |
\*------------------------------------------------------------------------*/
static DB * db_open_stub( const char *s, int i, int j, DBTYPE d, const void *p )
{
char *libname = "libdb.so";
void *handle = dlopen(libname,RTLD_LAZY);
if (!handle)
{
fprintf(stderr,"*ERROR* loading %s: %s\n",libname,dlerror());
return NULL;
}
db_open = dlsym(handle,"dbopen");
return (* db_open)( s,i,j,d,p );
}
#else
#define db_open dbopen
#endif
/*------------------------------------------------------------------------*\
| |
| tcob_check_varying |
| |
\*------------------------------------------------------------------------*/
int tcob_check_varying(struct file_desc *f, struct fld_desc *min_desc,
char *min_value, struct fld_desc *max_desc, char *max_value,
struct fld_desc *reclen_desc, char *reclen_value)
{
int mi_value;
int mx_value;
int rc_len;
char temp[20];
struct fld_desc *t;
char *t_value;
char *b;
t = (struct fld_desc *) malloc(sizeof(struct fld_desc *));
t_value = (char *) malloc(sizeof(char *));
b = (char *) malloc(sizeof(char *));
memset(temp, 0, 19);
if (min_desc == NULL)
{
mi_value = 0;
}
else
{
strncpy(temp, min_value, min_desc->len);
mi_value = atoi(temp);
}
memset(temp, 0, 19);
strncpy(temp, max_value, max_desc->len);
mx_value = atoi(temp);
memset(temp, 0, 19);
t->len = reclen_desc->len;
t->type = DTYPE_DISPLAY;
t->decimals = reclen_desc->decimals;
t->all = reclen_desc->all;
t->just_r = reclen_desc->just_r;
t->reserved = reclen_desc->reserved;
t->pic = b;
tcob_move(reclen_desc, reclen_value, t, t_value);
strncpy(temp, t_value, t->len);
rc_len = atoi(temp);
if ((rc_len <= mx_value) && (rc_len >= mi_value))
{
f->reclen = rc_len;
}
else
{
f->reclen = -1;
return 99;
}
return 0;
}
#ifdef TCOB_EXTERNFILE_MFCOMP
/*-----------------------------------------------------------*\
* map_file_name *
* *
* When the programmer wrote the COBOL SELECT statement, *
* we assume he intended the User to define an Environment *
* Variable that will tell the program where to find the *
* file. *
* *
* There are several possibilities: *
* *
* 1. The programmer wants the User to specify the base *
* directory for the data. In this case, the *
* programmer would have put something like *
* "DATA/Stock/ProductFile" in the SELECT clause. *
* *
* In this case, we would expect the User to set an *
* Environment Variable named "$DD_DATA". *
* Example (i) *
* DD_DATA=/usr/local/AccountsData *
* In this case, the full name of the file will *
* be: /usr/local/AccountsData/Stock/ProductFile *
* *
* However, Users like to do dumb things so we also *
* check to see whether they set up an environment *
* Variable named "$DATA". *
* Example (ii) *
* DATA=/u/Accts *
* In this case, the full name of the file will *
* be : /u/Accts/Stock/ProductFile *
* *
* (Note that these two examples prove that dumb Users *
* always use shorter, less meaningful names than the *
* theoretically possible intellegent User.) *
* *
* 2. The programmer wants the User to specify the full *
* file name. In this case, the programmer would have *
* put something like "PRODUCTFILE" in his SELECT *
* statement. *
* *
* In this case, we would like the User to have set *
* up an Environment Variable named "$DD_PRODUCTFILE". *
* Example (iii) *
* DD_PRODUCTFILE=/u/Data/Stock/ProductFile *
* In this case, the full name of the file will *
* simply be : /u/Data/Stock/ProductFile *
* *
* Again, we need to cater for the less intelligent *
* User, so we also check to see whether he named the *
* Environment Variable "$PRODUCTFILE". *
* Example (iv) *
* PRODUCTFILE=/ProductFile *
* In this case, the full name of the file will *
* simply be : /ProductFile *
* (Note that example (iv) is a true to life example *
* showing just how dumb Users can be. It takes a *
* truly ingenious kind of studidity to manage to *
* set your data files up in the root directory.) *
* *
* 3. (a) The programmer wants to hard-code the name of *
* file himself and hence will have something *
* like "/Data/Stock/ProductFile" in his *
* SELECT statement. *
* (b) The programmer really wanted the User to *
* specify an Environment Variable, but the User *
* stuffed up the installation process and there *
* is no Environment Variable to be found. *
* *
* In this case, we can do nothing except to use the *
* name the programmer typed in the SELECT statement *
* as the actual name of the file. *
* That is, we actually look for a file called : *
* "/Data/Stock/ProductFile". *
* *
* (Note that in this case we can be confident that *
* "/Data" is a separate partition and not a *
* directory in the root partition - Yeah, sure!) *
* *
\*-----------------------------------------------------------*/
char *map_file_name( char *evname )
{
int slash_pos;
int len, lenDD, lenSuffix;
char *file_name;
char *evDataDir, *dataDir, *file_Suffix;
file_name = NULL;
// fprintf(stderr, "debug: map_file_name: LT_DIRSEP_STR=%s;\n", LT_DIRSEP_STR);
/* First we search through the file name specified
* by the Cobol programmer and find the first
* occurance of the character "/".
* We will then use this to divide the name into
* the "Data Directory" and the "File Suffix".
* ( If there is no "/" in the name, then we treat
* the entire name as the "Data Directory" and
* assume a NULL File Suffix. I know it sounds
* crazy, but no less crazy than assuming a Null
* Data Directory).
*/
slash_pos = strcspn(evname, "/\\"); //LT_DIRSEP_STR);
/* Now we cheat a little by setting file_suffix
* to point to the same string as "evname",
* but starting half way through.
* This is naughty, and we must be careful that
* we don't go changing the contents of evname.
*/
file_Suffix = evname + slash_pos;
lenSuffix = strlen(file_Suffix);
/* Next we start forming up the name of the
* Environment Variable we wepect to find.
* We allocate enough room to hold the
* prefix for the environment variable
* :- "DD_"
* as well as the "Name" and the terminating
* Null character.
*/
evDataDir = malloc(slash_pos + 4);
strncpy(evDataDir, "DD_", 3);
strncpy(evDataDir + 3, evname, slash_pos);
evDataDir[slash_pos + 3] = 0;
/* Now lets see if the Environment Variable
* has been set up/
*/
dataDir = getenv(evDataDir);
/* If we failed to find an environment variable named
* "$DD_DataDir" then we don't give up yet...
*
* We will see whether the User has defined an
* environment variable named "$DataDir".
* Obviously, To do this, we just drop the first three
* characters from "DD_DataDir".
*/
if (dataDir == NULL)
{
evDataDir = evDataDir + 3;
dataDir = getenv(evDataDir);
}
/* If we found an environment variable containing the
* Data Directory, then we go ahead and use it.
* That is, we glue the file Suffix onto the end
* of the Data Directory to give us the full name
* of the file.
*/
if (dataDir != NULL)
{
lenDD = strlen(dataDir);
file_name = malloc(lenDD + lenSuffix + 1);
strcpy(file_name, dataDir);
strcpy(file_name + lenDD, file_Suffix);
}
else
/* If we failed to find an environment variable
* containing the name of the Data Directory,
* then we assume that the Programmer has
* Hard-Coded the file name.
* That is, we assume the name of the Environment
* Variable is really the name of the file itself.
*/
{
len = strlen(evname);
file_name = malloc(len+1);
strncpy(file_name,evname,len);
file_name[len] = '\0';
}
//fprintf(stderr, "debug: map_file_name: file_name=%s;\n", file_name);
return(file_name);
}
#endif
/*------------------------------------------------------------------------*\
| |
| tcob_open |
| |
\*------------------------------------------------------------------------*/
int tcob_open(struct file_desc *f, char *record, char *fname, int mode)
{
DBTYPE type = DB_BTREE;
void *infop = NULL;
int sflags = S_IRUSR | S_IWUSR;
int oflags = 0;
char *filename, *evname;
#ifndef TCOB_EXTERNFILE_MFCOMP
char *pt;
#endif
char alt_filename[128];
int alt_key_no;
int len;
BTREEINFO alt_key;
alt_key.flags = 0;
alt_key.cachesize = 0;
alt_key.maxkeypage = 0;
alt_key.minkeypage = 0;
alt_key.psize = 0;
alt_key.compare = NULL;
alt_key.prefix = NULL;
alt_key.lorder = 0;
/* Check the correct structure */
if (f->vers_id < RTL_FILE_VERSION)
{
fprintf(stderr, "You need to recompile your program\n");
fprintf(stderr, "Version mismatch; structure %x, RTL %x\n", f->vers_id,
RTL_FILE_VERSION);
RETURN_STATUS(99);
}
f->read_done = 0;
/*
BEWARE:
fname points to a field storage (non null-terminated)
we must copy fname to a C string and terminate it with a \0
and also trim spaces at the end.
NOTE:
This is a hack to accommodate the 'EXTERNAL' clause in
the SELECT statement.
The 'access_mode' in the file structure 'struct file_desc' is
used to indicate how the value stored in 'fname' is used.
It can be used to define a filename variable or a environment
variable.
If the access_mode < ACCEV_ENVAR (5), then 'fname' is used to
define a filename. Else 'fname' is used as an environment
variable which is used to determined the actual filename.
If no environment variable is found or is empty, then the
filename defaults to the value stored in 'fname'.
*/
f->eof_hit = 0;
if (f->access_mode < ACCEV_ENVAR)
{
len = f->fname_desc->len;
filename = malloc(len + 1);
memmove(filename, fname, len);
// printf("Will try open %s\n",filename);
do
{
filename[len--] = 0;
} while (filename[len] == ' ');
evname = NULL;
}
else
{
len = f->fname_desc->len;
evname = malloc(len + 1);
memmove(evname, fname, len);
do
{
evname[len--] = 0;
} while (evname[len] == ' ');
/* Get environment variable, if it exists */
#ifdef TCOB_EXTERNFILE_MFCOMP
filename = map_file_name(evname);
#else
if ((pt = getenv(evname)) != NULL)
{
len = strlen(pt);
if (len > 0)
{
filename = malloc(len + 1);
strncpy(filename, pt, len);
}
else
{
len = strlen(evname);
filename = malloc(len + 1);
strncpy(filename, evname, len);
}
}
else
{
len = strlen(evname);
filename = malloc(len + 1);
strncpy(filename, evname, len);
}
filename[len] = '\0';
#endif
}
/* Check to see if the file is already open. If so return
File Status 41 in according to the Ansi 85 Standard. */
if (f->dbp != NULL)
RETURN_STATUS(41);
switch (mode)
{
case FMOD_INPUT:
oflags = O_RDONLY;
break;
case FMOD_IO:
if (f->organization == ORG_LINESEQUENTIAL)
{
/* Line Sequential does not Support Mode IO */
RETURN_STATUS(37);
}
oflags = O_RDWR;
if (f->optional)
oflags = O_CREAT | O_RDWR;
break;
case FMOD_OUTPUT:
/* libdb doesn't support O_WRONLY */
oflags = O_CREAT | O_TRUNC | O_RDWR;
break;
case FMOD_EXTEND:
oflags = O_RDWR | O_APPEND;
if (f->optional)
oflags = O_CREAT | O_RDWR | O_APPEND;
break;
}
#if defined(__MINGW32__) || defined(__CYGWIN__)
oflags |= O_BINARY;
#endif
#ifdef USE_SYNC
if (f->organization != ORG_INDEXED)
oflags |= O_SYNC;
#endif
if (f->organization == ORG_INDEXED)
{
type = DB_BTREE;
}
else if (f->organization == ORG_RELATIVE)
{
/* type= DB_RECNO; */
}
if (f->organization == ORG_INDEXED)
{
struct altkey_desc *akd;
alt_key_no = 1;
for (akd = (struct altkey_desc *) (f + 1); akd->offset != -1; akd++)
{
/* printf("Alternate key: offset=%d, descriptor pic=0x%08x, dupl=%d\n",
akd->offset, (int)akd->descriptor->pic, akd->duplicates); */
if (akd->duplicates > 0)
{
alt_key.flags = R_DUP;
}
else
{
alt_key.flags = 0;
}
sprintf(alt_filename, "%s%d", filename, alt_key_no);
akd->alt_dbp = db_open(alt_filename, oflags, sflags, type, &alt_key);
if (!akd->alt_dbp)
{
if (errno == EINVAL)
{
f->dbp = NULL;
RETURN_STATUS(37);
}
if (errno == ENOENT)
{
f->dbp = NULL;
RETURN_STATUS(35);
}
f->dbp = NULL;
RETURN_STATUS(91);
}
alt_key_no++;
}
f->dbp = db_open(filename, oflags, sflags, type, infop);
}
/* otherwise it is sequential or relative, save its file handle, converted */
else if ((f->organization == ORG_LINESEQUENTIAL) && (mode == FMOD_INPUT))
f->dbp = (void *) fopen(filename, "rb");
else
{
f->dbp = (void *) open(filename, oflags, sflags);
if ((int) f->dbp == -1)
f->dbp = 0;
}
// free(filename);
if (evname != NULL)
free(evname);
if (!f->dbp)
{
/* Check to see if optional */
if (f->optional && mode == FMOD_INPUT)
{
f->dbp = NULL;
f->file_missing = 1;
}
else
{
if (errno == EINVAL)
{
f->dbp = NULL;
free(filename);
RETURN_STATUS(37);
}
if (errno == ENOENT)
{
f->dbp = NULL;
free(filename);
RETURN_STATUS(35);
}
f->dbp = NULL;
free(filename);
RETURN_STATUS(91);
}
}
/* save mode to check later (read,write,start,...) */
f->open_mode = mode;
/* save the file in the list of open files for the proces */
tcob_add_file_list(f);
#ifdef USE_LOCKSERVER
insert_filename((int)(f->dbp),filename);
#endif
free(filename);
RETURN_STATUS(0);
}
/*------------------------------------------------------------------------*\
| |
| tcob_close_real |
| |
\*------------------------------------------------------------------------*/
int tcob_close_real(struct file_desc *f, char *record)
{
f->read_done = 0;
/* Check to see if file is open. If not return File Status 42
In accordance with the Cobol 85 Standard. */
if (f->dbp == NULL)
{
if (f->optional && f->file_missing)
return 0;
return 42;
}
/* If there is a start not yet used delete it */
if (f->start_record != NULL)
{
free(f->start_record);
f->start_record = NULL;
}
if (f->organization == ORG_INDEXED)
{
struct altkey_desc *akd;
for (akd = (struct altkey_desc *) (f + 1); akd->offset != -1; akd++)
{
akd->alt_dbp->close(akd->alt_dbp);
}
f->dbp->close(f->dbp);
}
else
{
/* if ((f->organization == ORG_LINESEQUENTIAL || f->organization == ORG_SEQUENTIAL) && f->open_mode == FMOD_OUTPUT */
if ((f->organization == ORG_LINESEQUENTIAL) && (f->open_mode
== FMOD_OUTPUT) && (f->with_advancing) && (f->adv_before == 0))
{
/* write( (int)f->dbp, "\x0a", 1 ); */
}
if ((f->organization == ORG_LINESEQUENTIAL) && (f->open_mode
== FMOD_INPUT))
fclose((FILE *) f->dbp);
else
close((int) f->dbp);
}
#ifdef USE_LOCKSERVER
lockserver_release_specific_lock(fd_filename((int)f->dbp), "*");
remove_filename((int)f->dbp);
#endif
f->dbp = NULL;
return 0;
}
int tcob_close(struct file_desc *f, char *record)
{
int retval;
retval = tcob_close_real(f, record);
if (retval == 0)
tcob_remove_file_list(f); /* remove from the list of open files */
RETURN_STATUS(retval);
}
/*------------------------------------------------------------------------*\
| |
| tcob_file_init |
| |
\*------------------------------------------------------------------------*/
int tcob_file_init(struct file_desc *f, char *record)
{
#ifdef DEBUG_RTS
fprintf(stderr, "file_init: \n");
#endif
tcob_close(f, record);
f->open_mode = 0;
f->file_missing = 0;
return 0;
}
/*------------------------------------------------------------------------*\
| |
| tcob_setlock |
| |
\*------------------------------------------------------------------------*/
void tcob_setlock()
{
/* this just make aware we need to lock current record,
used before a read */
need_lock = 1;
}
static int lock_record(int fd, int len)
{
#if defined(__MINGW32__)
return -1;
#else
struct flock lk;
lk.l_type = F_WRLCK;
lk.l_whence = SEEK_CUR;
lk.l_start = 0;
lk.l_len = len;
lk.l_pid = getpid();
need_lock = 0;
return (fcntl(fd,F_SETLK,&lk));
#endif
}
/*------------------------------------------------------------------------*\
| |
| tcob_unlock |
| |
| BEWARE THIS ONLY WORKS WITH RELATIVE FILES FOR NOW!!! |
| ANY OTHER USE MAY CRASH YOUR RUNTIME ENVIRONMENT. |
\*------------------------------------------------------------------------*/
void tcob_unlock(struct file_desc *f)
{
#ifdef USE_LOCKSERVER
if(f->organization == ORG_INDEXED)
{
lockserver_release_specific_lock(fd_filename((int)f->dbp), "*");
return;
}
#endif
#if defined(__MINGW32__)
return;
#else
{
struct flock lk;
lk.l_type = F_UNLCK;
lk.l_whence = SEEK_CUR;
lk.l_start = 0;
lk.l_len = f->reclen;
lk.l_pid = getpid();
fcntl((int)f->dbp,F_SETLK,&lk);
}
#endif
}
/*------------------------------------------------------------------------*\
| |
| tcob_ignorelock |
| |
\*------------------------------------------------------------------------*/
void tcob_ignorelock()
{
/* this just make aware we need to ignore locks on the current record,
used before a read */
ignore_lock = 1;
}
/*------------------------------------------------------------------------*\
| |
| tcob_read |
| |
\*------------------------------------------------------------------------*/
int tcob_read(struct file_desc *f, char *record, ...)
{
int result;
recno_t recno;
struct fld_desc *fkey;
char *keybuf;
struct fld_desc *reclen_desc;
char *reclen_buf = NULL;
DBT key, data;
DBT save_key;
va_list args;
int offset;
char rsize[bcounter];
int rlen;
char *temp_record;
struct fld_desc *t;
char t_value[bcounter];
char *b;
int lockstat;
f->read_done = 0;
/* Check to see if file is open. If not return File Status 47
In accordance with the Cobol 85 Standard. */
if (f->dbp == NULL)
{
if (f->optional && f->file_missing)
RETURN_STATUS(10);
RETURN_STATUS(47);
}
/* Check to see that the record length is valid */
if (f->reclen == -1)
RETURN_STATUS(99);
/* Check the mode the file is opened in to make sure that read
is Allowed */
if (((f->open_mode != FMOD_INPUT) && (f->open_mode != FMOD_IO)))
RETURN_STATUS(47);
/* Check that we didn't already hit eof */
if ((f->open_mode == FMOD_INPUT || f->open_mode == FMOD_IO) && f->eof_hit)
RETURN_STATUS(46);
/* check if reclen was given */
va_start(args,record);
reclen_desc = va_arg(args, struct fld_desc *);
if (reclen_desc != NULL)
reclen_buf = va_arg(args, char *);
/* If there is a start record outstanding use it to fulfill the read */
if (f->start_record != NULL)
{
memmove(record, f->start_record, f->reclen);
free(f->start_record);
f->start_record = NULL;
f->read_done = 1;
#ifdef USE_LOCKSERVER
if (ignore_lock)
{
ignore_lock=0;
}
else
if (f->organization == ORG_INDEXED)
{
key.data = record+f->rec_index;
key.size = f->ixd_desc->len;
/* Check to see if the record is Locked*/
temp_key = (char *) malloc (sizeof(char) * (key.size+1));
strncpy(temp_key,key.data,key.size);
temp_key[key.size]='\0';
result=get_lockserver_lock_owner(fd_filename((int)f->dbp),temp_key);
free(temp_key);
if(result>0)
{
/* This record is locked by another user. Return the Bad news*/
need_lock = 0;
RETURN_STATUS(51);
}
/* Lock the Record */
if(need_lock)
{
temp_key = (char *) malloc (sizeof(char) * (key.size+1));
strncpy(temp_key,key.data,key.size);
temp_key[key.size]='\0';
result=set_lockserver_lock(fd_filename((int)f->dbp),temp_key);
free(temp_key);
need_lock=0;
if(result>0)
{
/* This record is locked by another user. Return the Bad news*/
need_lock = 0;
RETURN_STATUS(51);
}
}
}
#endif
RETURN_STATUS(0);
}
switch (f->organization)
{
case ORG_RELATIVE:
recno = va_arg(args,recno_t);
va_end(args);
if (recno < 1)
RETURN_STATUS(23);
// lseek( (int)f->dbp, recno * f->reclen, SEEK_SET);
lseek((int) f->dbp, ((recno) * ((f->reclen))), SEEK_SET);
if (need_lock)
{
if ((lockstat = lock_record((int) f->dbp, f->reclen)) != 0)
{
RETURN_STATUS(51); /* not able to lock */
}
}
result = read((int) f->dbp, record, f->reclen);
if (record[0] == '\0')
RETURN_STATUS(23);
if (result == f->reclen)
f->read_done = 1;
RETURN_STATUS(0);
if (reclen_desc != NULL)
{
sprintf(reclen_buf, "%0*i", (int) reclen_desc->len, result);
f->read_done = 1;
RETURN_STATUS(0);
}
RETURN_STATUS(30);
case ORG_INDEXED:
fkey = va_arg(args, struct fld_desc *);
keybuf = va_arg(args, char *);
va_end(args);
key.data = record + f->rec_index;
save_key.data = record + f->rec_index;
key.size = f->ixd_desc->len;
save_key.size = f->ixd_desc->len;
if (fkey == NULL)
{
f->key_in_use = NULL;
}
else
{
struct altkey_desc *akd;
for (akd = (struct altkey_desc *) (f + 1); akd->offset != -1; akd++)
{
if (akd->descriptor->pic == fkey->pic)
{
f->key_in_use = akd;
key.data = keybuf;
key.size = akd->descriptor->len;
result = akd->alt_dbp->seq(akd->alt_dbp, &key, &data,
R_CURSOR);
if (result)
RETURN_STATUS(23);
if (memcmp(key.data, keybuf, key.size) != 0)
RETURN_STATUS(23);
key.data = data.data;
save_key.data = data.data;
key.size = f->ixd_desc->len;
save_key.size = f->ixd_desc->len;
}
}
}
#ifdef USE_LOCKSERVER
if (ignore_lock)
{
ignore_lock=0;
}
else
{
/* Check to see if the record is Locked*/
temp_key = (char *) malloc (sizeof(char) * (key.size+1));
strncpy(temp_key,key.data,key.size);
temp_key[key.size]='\0';
result=get_lockserver_lock_owner(fd_filename((int)f->dbp),temp_key);
free(temp_key);
if(result>0)
{
/* This record is locked by another user. Return the Bad news*/
need_lock = 0;
RETURN_STATUS(51);
}
}
#endif
result = f->dbp->seq(f->dbp, &key, &data, R_CURSOR);
if (result)
RETURN_STATUS(23); /* should have a better error info here */
if ((int) data.size < f->reclen)
{
if (reclen_desc != NULL)
{
sprintf(reclen_buf, "%0*i", (int) reclen_desc->len, result);
f->read_done = 1;
#ifdef USE_LOCKSERVER
/* Lock the Record */
if(need_lock)
{
temp_key = (char *) malloc (sizeof(char) * (key.size+1));
strncpy(temp_key,key.data,key.size);
temp_key[key.size]='\0';
result=set_lockserver_lock(fd_filename((int)f->dbp),temp_key);
free(temp_key);
need_lock=0;
if(result>0)
{
/* This record is locked by another user. Return the Bad news*/
need_lock = 0;
RETURN_STATUS(51);
}
}
#endif
RETURN_STATUS(0);
}
else
RETURN_STATUS(23);
}
if (memcmp(save_key.data, (char *) data.data + f->rec_index,
save_key.size) != 0)
RETURN_STATUS(23);
memmove(record, data.data, f->reclen);
f->read_done = 1;
#ifdef USE_LOCKSERVER
/* Lock the Record */
if(need_lock)
{
temp_key = (char *) malloc (sizeof(char) * (key.size+1));
strncpy(temp_key,key.data,key.size);
temp_key[key.size]='\0';
result=set_lockserver_lock(fd_filename((int)f->dbp),temp_key);
free(temp_key);
need_lock=0;
if(result>0)
{
/* This record is locked by another user. Return the Bad news*/
need_lock = 0;
RETURN_STATUS(51);
}
}
#endif
RETURN_STATUS(0);
case ORG_LINESEQUENTIAL:
{
char *tmpbuf, *s;
/* If the file is LINE SEQUENTIAL we need to read in the <NL> as well */
tmpbuf = malloc(f->reclen + 2);
memset(tmpbuf, 0, (f->reclen) + 2);
memset(record, ' ', f->reclen);
fgets(tmpbuf, f->reclen + 2, (void *) f->dbp);
printf("Record readed: [%s], size: [%d]\n",tmpbuf,strlen(tmpbuf));
if ((int) tmpbuf[0] == (int) NULL)
{
free(tmpbuf);
RETURN_STATUS(10);
}
s = strchr(tmpbuf, '\n');
if (s == NULL)
{
/* tmpbuf[f->reclen] = ' '; */
memmove(record, tmpbuf, f->reclen);
}
else
{
offset = s - tmpbuf;
memset(s, ' ', (f->reclen) - offset);
memmove(record, tmpbuf, f->reclen);
}
free(tmpbuf);
RETURN_STATUS(0);
}
default: /* sequential files */
if (reclen_desc != NULL)
{
/* Variable Length Sequential File */
result = read((int) f->dbp, rsize, bcounter);
if (result == 0)
RETURN_STATUS(10);
rlen = atoi(rsize);
f->reclen = rlen - bcounter;
temp_record = malloc(f->reclen + bcounter);
memset(temp_record, ' ', rlen);
result = read((int) f->dbp, temp_record, rlen);
if (result == 0)
RETURN_STATUS(10);
memmove(record, temp_record, result - bcounter);
sprintf(t_value, "%0*i", bcounter, result - bcounter);
t = (struct fld_desc *) malloc(sizeof(struct fld_desc*));
b = (char *) malloc(sizeof(char *));
t->len = bcounter;
t->type = DTYPE_DISPLAY;
t->decimals = 0;
t->all = reclen_desc->all;
t->just_r = reclen_desc->just_r;
t->reserved = reclen_desc->reserved;
t->pic = b;
tcob_move(t, t_value, reclen_desc, reclen_buf);
RETURN_STATUS(0);
}
else
{
result = read((int) f->dbp, record, f->reclen);
}
if (result == f->reclen)
RETURN_STATUS(0);
if (result == 0)
RETURN_STATUS(10);
RETURN_STATUS(30);
}
}
/*------------------------------------------------------------------------*\
| |
| tcob_read_next |
| |
\*------------------------------------------------------------------------*/
int tcob_read_next(struct file_desc *f, char *record, ...)
{
int result;
int flags = R_NEXT;
#ifdef USE_LOCKSERVER
int reverse_flag=R_PREV;
#endif
DBT key, data;
va_list args;
struct fld_desc *reclen_desc;
char *reclen_buf;
/* Check to see if file is open. If not return File Status 47
In accordance with the Cobol 85 Standard. */
if (f->dbp == NULL)
{
if (f->optional && f->file_missing)
RETURN_STATUS(10);
RETURN_STATUS(47);
}
/* Check the mode the file is opened in to make sure that read
is Allowed */
if (((f->open_mode != FMOD_INPUT) && (f->open_mode != FMOD_IO)))
RETURN_STATUS(47);
/* Check that we didn't already hit eof */
if ((f->open_mode == FMOD_INPUT || f->open_mode == FMOD_IO) && f->eof_hit)
RETURN_STATUS(46);
/* check if reclen was given */
va_start(args,record);
reclen_desc = va_arg(args, struct fld_desc *);
if (reclen_desc != NULL)
reclen_buf = va_arg(args, char *);
/* If there is a start record outstanding use it to fulfill the read */
if (f->start_record != NULL)
{
memmove(record, f->start_record, f->reclen);
free(f->start_record);
f->start_record = NULL;
#ifdef USE_LOCKSERVER
if (ignore_lock)
{
ignore_lock=0;
}
else
if (f->organization == ORG_INDEXED)
{
key.data = record+f->rec_index;
key.size = f->ixd_desc->len;
/* Check to see if the record is Locked*/
temp_key = (char *) malloc (sizeof(char) * (key.size+1));
strncpy(temp_key,key.data,key.size);
temp_key[key.size]='\0';
result=get_lockserver_lock_owner(fd_filename((int)f->dbp),temp_key);
free(temp_key);
if(result>0)
{
/* This record is locked by another user. Return the Bad news*/
need_lock = 0;
RETURN_STATUS(51);
}
/* Lock the Record */
if(need_lock)
{
temp_key = (char *) malloc (sizeof(char) * (key.size+1));
strncpy(temp_key,key.data,key.size);
temp_key[key.size]='\0';
result=set_lockserver_lock(fd_filename((int)f->dbp),temp_key);
free(temp_key);
need_lock=0;
if(result>0)
{
/* This record is locked by another user. Return the Bad news*/
need_lock = 0;
RETURN_STATUS(51);
}
}
}
#endif
f->read_done = 1;
RETURN_STATUS(0);
}
switch (f->organization)
{
case ORG_SEQUENTIAL:
result = read((int) f->dbp, record, f->reclen);
if (result <= 0)
RETURN_STATUS(10); /* what errors should I return? */
f->read_done = 1;
RETURN_STATUS(0);
case ORG_RELATIVE:
result = 1;
record[0] = '\0';
while (record[0] == '\0' && result > 0)
{
result = read((int) f->dbp, record, f->reclen);
}
if (result <= 0)
RETURN_STATUS(10); /* what errors should I return? */
f->read_done = 1;
RETURN_STATUS(0);
case ORG_INDEXED:
if (f->key_in_use != NULL)
{
struct altkey_desc *akd;
akd = (struct altkey_desc *) (f->key_in_use);
result = akd->alt_dbp->seq(akd->alt_dbp, &key, &data, flags);
if (result)
RETURN_STATUS(10);
key.data = data.data;
key.size = f->ixd_desc->len;
#ifdef USE_LOCKSERVER
if(ignore_lock)
{
ignore_lock=0;
}
else
{
/* Check to see if the record is Locked*/
temp_key = (char *) malloc (sizeof(char) * (key.size+1));
strncpy(temp_key,key.data,key.size);
temp_key[key.size]='\0';
result=get_lockserver_lock_owner(fd_filename((int)f->dbp),temp_key);
free(temp_key);
if(result>0)
{
/* This record is locked by another user. Roll Back and Return the Bad news*/
result=akd->alt_dbp->seq(akd->alt_dbp,&key,&data,reverse_flag);
need_lock = 0;
RETURN_STATUS(51);
}
}
#endif
flags = 0;
result = f->dbp->get(f->dbp, &key, &data, flags);
if (result)
RETURN_STATUS(10); /* should have a better error info here */
if ((int) data.size < f->reclen)
RETURN_STATUS(10);
memmove(record, data.data, f->reclen);
f->read_done = 1;
#ifdef USE_LOCKSERVER
/* Lock the Record */
if(need_lock)
{
temp_key = (char *) malloc (sizeof(char) * (key.size+1));
strncpy(temp_key,key.data,key.size);
temp_key[key.size]='\0';
result=set_lockserver_lock(fd_filename((int)f->dbp),temp_key);
free(temp_key);
need_lock=0;
if(result>0)
{
/* This record is locked by another user. Roll Back and Return the Bad news*/
result=akd->alt_dbp->seq(akd->alt_dbp,&key,&data,reverse_flag);
need_lock = 0;
RETURN_STATUS(51);
}
}
#endif
RETURN_STATUS(0);
}
result = f->dbp->seq(f->dbp, &key, &data, flags);
if (result)
{
f->eof_hit = 1;
RETURN_STATUS(10); /* should have a better error info here */
}
if ((int) data.size < f->reclen)
{
f->eof_hit = 1;
RETURN_STATUS(98); /* partial record read */
}
memmove(record, data.data, f->reclen);
f->read_done = 1;
#ifdef USE_LOCKSERVER
/* Lock the Record */
if(need_lock)
{
temp_key = (char *) malloc (sizeof(char) * (key.size+1));
strncpy(temp_key,key.data,key.size);
temp_key[key.size]='\0';
result=set_lockserver_lock(fd_filename((int)f->dbp),temp_key);
free(temp_key);
need_lock=0;
if(result>0)
{
/* This record is locked by another user. Roll Back and Return the Bad news*/
result = f->dbp->seq(f->dbp,&key,&data,reverse_flag);
need_lock = 0;
RETURN_STATUS(51);
}
}
#endif
RETURN_STATUS(0);
}
RETURN_STATUS(99);
}
/*------------------------------------------------------------------------*\
| |
| tcob_read_prev |
| |
\*------------------------------------------------------------------------*/
int tcob_read_prev(struct file_desc *f, char *record, ...)
{
int result;
int flags = R_PREV;
#ifdef USE_LOCKSERVER
int reverse_flag=R_NEXT;
#endif
DBT key, data;
va_list args;
struct fld_desc *reclen_desc;
char *reclen_buf;
/* Check to see if file is open. If not return File Status 47
In accordance with the Cobol 85 Standard. */
if (f->dbp == NULL)
{
if (f->optional && f->file_missing)
RETURN_STATUS(10);
RETURN_STATUS(47);
}
/* Check the mode the file is opened in to make sure that read
is Allowed */
if (((f->open_mode != FMOD_INPUT) && (f->open_mode != FMOD_IO)))
RETURN_STATUS(47);
/* check if reclen was given */
va_start(args,record);
reclen_desc = va_arg(args, struct fld_desc *);
if (reclen_desc != NULL)
reclen_buf = va_arg(args, char *);
/* If there is a start record outstanding use it to fulfill the read */
if (f->start_record != NULL)
{
memmove(record, f->start_record, f->reclen);
free(f->start_record);
f->start_record = NULL;
#ifdef USE_LOCKSERVER
if(ignore_lock)
{
ignore_lock=0;
}
else
if (f->organization == ORG_INDEXED)
{
key.data = record+f->rec_index;
key.size = f->ixd_desc->len;
/* Check to see if the record is Locked*/
temp_key = (char *) malloc (sizeof(char) * (key.size+1));
strncpy(temp_key,key.data,key.size);
temp_key[key.size]='\0';
result=get_lockserver_lock_owner(fd_filename((int)f->dbp),temp_key);
free(temp_key);
if(result>0)
{
/* This record is locked by another user. Return the Bad news*/
need_lock = 0;
RETURN_STATUS(51);
}
/* Lock the Record */
if(need_lock)
{
temp_key = (char *) malloc (sizeof(char) * (key.size+1));
strncpy(temp_key,key.data,key.size);
temp_key[key.size]='\0';
result=set_lockserver_lock(fd_filename((int)f->dbp),temp_key);
free(temp_key);
need_lock=0;
if(result>0)
{
/* This record is locked by another user. Return the Bad news*/
need_lock = 0;
RETURN_STATUS(51);
}
}
}
#endif
RETURN_STATUS(0);
}
switch (f->organization)
{
case ORG_SEQUENTIAL:
/* Need some logic here to figure out if at beginning of file */
/* As a result of the previous Read Previous */
lseek((int) f->dbp, (2 * ((f->reclen) * -1)), SEEK_CUR);
result = read((int) f->dbp, record, f->reclen);
if (result <= 0)
RETURN_STATUS(10);
f->read_done = 1;
RETURN_STATUS(0);
case ORG_RELATIVE:
result = 1;
record[0] = '\0';
while (record[0] == '\0' && result > 0)
{
if (lseek((int) f->dbp, (2 * ((f->reclen) * -1)), SEEK_CUR)
== 0)
RETURN_STATUS(10);
result = read((int) f->dbp, record, f->reclen);
}
if (result <= 0)
RETURN_STATUS(10);
f->read_done = 1;
RETURN_STATUS(0);
case ORG_INDEXED:
if (f->key_in_use != NULL)
{
struct altkey_desc *akd;
akd = (struct altkey_desc *) (f->key_in_use);
result = akd->alt_dbp->seq(akd->alt_dbp, &key, &data, flags);
if (result)
RETURN_STATUS(10);
key.data = data.data;
key.size = f->ixd_desc->len;
#ifdef USE_LOCKSERVER
if(ignore_lock)
{
ignore_lock=0;
}
else
{
/* Check to see if the record is Locked*/
temp_key = (char *) malloc (sizeof(char) * (key.size+1));
strncpy(temp_key,key.data,key.size);
temp_key[key.size]='\0';
result=get_lockserver_lock_owner(fd_filename((int)f->dbp),temp_key);
free(temp_key);
if(result>0)
{
/* This record is locked by another user. Roll Back and Return the Bad news*/
result=akd->alt_dbp->seq(akd->alt_dbp,&key,&data,reverse_flag);
need_lock = 0;
RETURN_STATUS(51);
}
}
#endif
flags = 0;
result = f->dbp->get(f->dbp, &key, &data, flags);
if (result)
RETURN_STATUS(10); /* should have a better error info here */
if ((int) data.size < f->reclen)
RETURN_STATUS(10);
memmove(record, data.data, f->reclen);
f->read_done = 1;
#ifdef USE_LOCKSERVER
/* Lock the Record */
if(need_lock)
{
temp_key = (char *) malloc (sizeof(char) * (key.size+1));
strncpy(temp_key,key.data,key.size);
temp_key[key.size]='\0';
result=set_lockserver_lock(fd_filename((int)f->dbp),temp_key);
free(temp_key);
need_lock=0;
if(result>0)
{
/* This record is locked by another user. Roll Back and Return the Bad news*/
result=akd->alt_dbp->seq(akd->alt_dbp,&key,&data,reverse_flag);
need_lock = 0;
RETURN_STATUS(51);
}
}
#endif
RETURN_STATUS(0);
}
result = f->dbp->seq(f->dbp, &key, &data, flags);
if (result)
RETURN_STATUS(10); /* should have a better error info here */
if ((int) data.size < f->reclen)
RETURN_STATUS(10);
memmove(record, data.data, f->reclen);
f->read_done = 1;
#ifdef USE_LOCKSERVER
/* Lock the Record */
if(need_lock)
{
temp_key = (char *) malloc (sizeof(char) * (key.size+1));
strncpy(temp_key,key.data,key.size);
temp_key[key.size]='\0';
result=set_lockserver_lock(fd_filename((int)f->dbp),temp_key);
free(temp_key);
need_lock=0;
if(result>0)
{
/* This record is locked by another user. Roll Back and Return the Bad news*/
result = f->dbp->seq(f->dbp,&key,&data,reverse_flag);
need_lock = 0;
RETURN_STATUS(51);
}
}
#endif
RETURN_STATUS(0);
}
RETURN_STATUS(99);
}
/*------------------------------------------------------------------------*\
| |
| tcob_write |
| |
\*------------------------------------------------------------------------*/
int tcob_write(struct file_desc *f, char *record, ...)
{
int result;
recno_t recno;
int flags = 0;
DBT key, data;
va_list args;
char *tmpbuf;
int offset;
struct fld_desc *reclen_desc;
char *reclen_buf;
unsigned int slen = 0;
unsigned int elen = 0;
char sclen[bcounter];
char eclen[bcounter];
/* Check to see if file is open. If not return File Status 48
In accordance with the Cobol 85 Standard. */
if (f->dbp == NULL)
return 48;
/* Check to see that the record length is valid */
if (f->reclen == -1)
return 99;
/* Check the mode the file is opened in to make sure that write
is Allowed */
if (((f->open_mode != FMOD_OUTPUT) && (f->open_mode != FMOD_IO)
&& (f->open_mode != FMOD_EXTEND)))
return 48;
/* check if reclen was given */
va_start(args,record);
reclen_desc = va_arg(args, struct fld_desc *);
if (reclen_desc != NULL)
reclen_buf = va_arg(args, char *);
data.data = record;
data.size = f->reclen;
switch (f->organization)
{
case ORG_INDEXED:
key.data = record + f->rec_index;
key.size = f->ixd_desc->len;
result = f->dbp->put(f->dbp, &key, &data, R_NOOVERWRITE);
if (result == 1)
return 22;
else if (result)
return 99;
/* If the main write was successfull then we proceed to
write out the alternate keys. Any Failure will mean that
we have to delete the writes we have just done.
*/
{
struct altkey_desc *akd;
for (akd = (struct altkey_desc *) (f + 1); akd->offset != -1; akd++)
{
key.data = record + akd->offset;
key.size = akd->descriptor->len;
data.data = record + f->rec_index;
data.size = f->ixd_desc->len;
result
= akd->alt_dbp->put(akd->alt_dbp, &key, &data,
flags);
#ifdef USE_SYNC
result=akd->alt_dbp->sync(akd->alt_dbp,0);
#endif
/* If an error occurs we need code to back out.
Will be done later.
*/
}
}
#ifdef USE_SYNC
result = f->dbp->sync(f->dbp,0);
#endif
break;
case ORG_RELATIVE:
/* va_start(args,record); */
recno = va_arg(args,recno_t);
va_end(args);
if (recno < 1)
return 23;
// lseek((int)f->dbp, recno * f->reclen, SEEK_SET);
lseek((int) f->dbp, ((recno) * ((f->reclen))), SEEK_SET);
result = write((int) f->dbp, record, f->reclen);
if (!result)
return 99; /* what errors should I return? */
break;
case ORG_LINESEQUENTIAL:
/* Create buffer with room for the string and a line feed */
tmpbuf = malloc(f->reclen + 1);
memmove(tmpbuf, record, f->reclen);
for (offset = f->reclen - 1; offset >= 0; offset--)
{
/* Do not output trailing spaces and nulls */
if ((tmpbuf[offset] != ' ') && (tmpbuf[offset] != '\0'))
{
tmpbuf[offset + 1] = '\n';
result = write((int) f->dbp, tmpbuf, offset + 2);
}
else if (offset == 0)
{ /* Blank line */
result = write((int) f->dbp, "\n", 1);
}
else
{
continue;
}
/* Handle any errors writing to file */
if (!result)
{
free(tmpbuf);
return 99; /* FIXME: what error code? */
}
break;
}
free(tmpbuf);
break;
default:
if (reclen_desc != NULL)
{
/* If this is a variable length record write out the length */
char *temp_record = (char *) malloc(f->reclen);
slen = f->reclen + bcounter;
elen = slen;
sprintf(sclen, "%0*i", bcounter, slen);
sprintf(eclen, "%0*i", bcounter, elen);
memmove(temp_record, record, f->reclen);
result = write((int) f->dbp, sclen, bcounter);
result = write((int) f->dbp, temp_record, f->reclen);
result = write((int) f->dbp, eclen, bcounter);
free(temp_record);
}
else
{
result = write((int) f->dbp, record, f->reclen);
}
if (!result)
return 99; /* what errors should I return? */
break;
}
f->read_done = 0;
return 0;
}
/*------------------------------------------------------------------------*\
| |
| tcob_delete |
| |
\*------------------------------------------------------------------------*/
int tcob_delete(struct file_desc *f, char *record, ...)
{
int result;
recno_t recno;
int flags = 0;
va_list args;
DBT key;
/* Check to see if file is open. If not return File Status 49
In accordance with the Cobol 85 Standard. */
if (f->dbp == NULL)
return 49;
/* Check to see that the record length is valid */
if (f->reclen == -1)
return 99;
/* Check the mode the file is opened in to make sure that delete
is Allowed */
if (f->open_mode != FMOD_IO)
return 49;
switch (f->organization)
{
case ORG_INDEXED:
key.data = record + f->rec_index;
key.size = f->ixd_desc->len;
#ifdef USE_LOCKSERVER
/* Check to see if the record is Locked*/
temp_key = (char *) malloc (sizeof(char) * (key.size+1));
strncpy(temp_key,key.data,key.size);
temp_key[key.size]='\0';
result=get_lockserver_lock_owner(fd_filename((int)f->dbp),temp_key);
free(temp_key);
if(result>0)
{
/* This record is locked by another user. Return the Bad news*/
RETURN_STATUS(51);
}
#endif
result = f->dbp->del(f->dbp, &key, flags);
if (result != 0)
return 23;
#ifdef USE_SYNC
result = f->dbp->sync(f->dbp,0);
#endif
#ifdef USE_LOCKSERVER
/* Unlock the Record if it is Locked */
temp_key = (char *) malloc (sizeof(char) * (key.size+1));
strncpy(temp_key,key.data,key.size);
temp_key[key.size]='\0';
result=lockserver_release_specific_lock(fd_filename((int)f->dbp),temp_key);
free(temp_key);
if(result>0)
{
/* This record was not locked */
}
#endif
{
struct altkey_desc *akd;
for (akd = (struct altkey_desc *) (f + 1); akd->offset != -1; akd++)
{
key.data = record + akd->offset;
key.size = akd->descriptor->len;
result = akd->alt_dbp->del(akd->alt_dbp, &key, flags);
#ifdef USE_SYNC
result=akd->alt_dbp->sync(akd->alt_dbp,0);
#endif
}
}
break;
case ORG_RELATIVE:
va_start(args,record);
recno = va_arg(args,recno_t);
va_end(args);
if (recno < 1)
return 23;
/* recno = recno - 1; */
lseek((int) f->dbp, recno * f->reclen, SEEK_SET);
memset(record, 0, f->reclen);
result = write((int) f->dbp, record, f->reclen);
if (!result)
return 99; /* what errors should I return? */
break;
default:
return 37;
}
return 0;
}
/*------------------------------------------------------------------------*\
| |
| tcob_start |
| |
\*------------------------------------------------------------------------*/
int tcob_start(struct file_desc *f, char *record, int cond, ...)
{
int result;
recno_t recno;
int flags = R_CURSOR;
DBT key, data;
va_list args;
int alternate = 0;
struct fld_desc *r;
char *key_ptr;
char new_record[f->reclen];
f->eof_hit = 0; /* additon AL : reset eof if already positioned */
f->read_done = 0;
/* Check to see if file is open. If not return File Status 47
In accordance with the Cobol 85 Standard. */
if (f->dbp == NULL)
return 47;
/* Check to see that the record length is valid */
if (f->reclen == -1)
return 99;
/* Check the mode the file is opened in to make sure that start
is Allowed */
if (((f->open_mode != FMOD_INPUT) && (f->open_mode != FMOD_IO)))
return 47;
switch (f->organization)
{
case ORG_RELATIVE:
va_start(args,cond);
recno = va_arg(args,recno_t);
va_end(args);
switch (cond)
{
case 1: /* Equal to */
if (lseek((int) f->dbp, ((recno) * ((f->reclen))), SEEK_SET)
> 0)
{
result = read((int) f->dbp, new_record, f->reclen);
if (new_record[0] == '\0')
return 23;
if (result == f->reclen)
{
f->start_record = malloc(f->reclen);
memmove(f->start_record, new_record, f->reclen);
return 0;
}
}
break;
case 2: /* Less Than */
if (recno < 1)
return 23;
recno = recno - 1;
if (lseek((int) f->dbp, ((recno) * ((f->reclen))), SEEK_SET)
> 0)
{
result = read((int) f->dbp, new_record, f->reclen);
if (new_record[0] == '\0')
{
result = 1;
while (new_record[0] == '\0' && result > 0)
{
recno--;
lseek((int) f->dbp, recno * f->reclen, SEEK_SET);
result = read((int) f->dbp, new_record,
f->reclen);
}
if (result <= 0)
return 23;
}
if (result == f->reclen)
{
f->start_record = malloc(f->reclen);
memmove(f->start_record, new_record, f->reclen);
return 0;
}
}
break;
case 3: /* Less than or equal to */
if (lseek((int) f->dbp, ((recno) * ((f->reclen))), SEEK_SET)
> 0)
{
result = read((int) f->dbp, new_record, f->reclen);
if (new_record[0] == '\0')
{
result = 1;
while (new_record[0] == '\0' && result > 0)
{
recno--;
lseek((int) f->dbp, ((recno) * ((f->reclen))),
SEEK_SET);
result = read((int) f->dbp, new_record,
f->reclen);
}
if (result <= 0)
return 23;
}
if (result == f->reclen)
{
f->start_record = malloc(f->reclen);
memmove(f->start_record, new_record, f->reclen);
return 0;
}
}
break;
case 4: /* Greater Than */
recno++;
if (lseek((int) f->dbp, ((recno) * ((f->reclen))), SEEK_SET)
> 0)
{
result = read((int) f->dbp, new_record, f->reclen);
if (new_record[0] == '\0')
{
result = 1;
while (new_record[0] == '\0' && result > 0)
{
result = read((int) f->dbp, new_record,
f->reclen);
recno++;
}
if (result <= 0)
return 23;
}
if (result == f->reclen)
{
f->start_record = malloc(f->reclen);
memmove(f->start_record, new_record, f->reclen);
return 0;
}
}
break;
case 5: /* Greater than or Equal to */
if (lseek((int) f->dbp, ((recno) * ((f->reclen))), SEEK_SET)
> 0)
{
result = read((int) f->dbp, new_record, f->reclen);
if (new_record[0] == '\0')
{
result = 1;
while (new_record[0] == '\0' && result > 0)
{
result = read((int) f->dbp, new_record,
f->reclen);
recno++;
}
if (result <= 0)
return 23;
}
if (result == f->reclen)
{
f->start_record = malloc(f->reclen);
memmove(f->start_record, new_record, f->reclen);
return 0;
}
}
break;
default:
return 99;
}
return 23;
case ORG_INDEXED:
{
struct altkey_desc *akd;
va_start(args,cond);
r = va_arg(args,struct fld_desc *);
key_ptr = va_arg(args,char *);
va_end(args);
f->key_in_use = NULL;
for (akd = (struct altkey_desc *) (f + 1); akd->offset != -1; akd++)
{
if (akd->descriptor == r)
{
f->key_in_use = akd;
alternate = 1;
break;
}
}
switch (cond)
{
case 1: /* Equal To */
if (alternate == 1)
{
key.data = key_ptr;
key.size = akd->descriptor->len;
result = akd->alt_dbp->seq(akd->alt_dbp, &key, &data,
flags);
if (result)
return 23;
if (memcmp(key.data, key_ptr, key.size) != 0)
return 23;
key.data = data.data;
key.size = f->ixd_desc->len;
flags = 0;
result = f->dbp->get(f->dbp, &key, &data, flags);
if (result)
return 23;
if ((int) data.size < f->reclen)
return 23;
memmove(new_record, data.data, f->reclen);
}
else
{
key.data = record + f->rec_index;
key.size = f->ixd_desc->len;
result = f->dbp->seq(f->dbp, &key, &data, flags);
if (result)
return 23; /* should have a better error info here */
if ((int) data.size < f->reclen)
return 23;
memmove(new_record, data.data, f->reclen);
if (memcmp(record + f->rec_index, new_record
+ f->rec_index, key.size) != 0)
return 23;
}
f->start_record = malloc(f->reclen);
memmove(f->start_record, new_record, f->reclen);
break;
case 2: /* Less than */
if (alternate == 1)
{
key.data = key_ptr;
key.size = akd->descriptor->len;
result = akd->alt_dbp->seq(akd->alt_dbp, &key, &data,
flags);
if (result)
{
flags = R_LAST;
result = akd->alt_dbp->seq(akd->alt_dbp, &key,
&data, flags);
if (result)
return 23;
}
/* If result greater than or equal Key read prev record */
if (memcmp(key.data, key_ptr, key.size) > -1)
{
flags = R_PREV;
result = akd->alt_dbp->seq(akd->alt_dbp, &key,
&data, flags);
if (result)
return 23;
}
key.data = data.data;
key.size = f->ixd_desc->len;
flags = 0;
result = f->dbp->get(f->dbp, &key, &data, flags);
if (result)
return 23;
if ((int) data.size < f->reclen)
return 23;
memmove(new_record, data.data, f->reclen);
}
else
{
key.data = record + f->rec_index;
key.size = f->ixd_desc->len;
result = f->dbp->seq(f->dbp, &key, &data, flags);
if (result)
{
flags = R_LAST;
result = f->dbp->seq(f->dbp, &key, &data, flags);
if (result)
return 23; /* should have a better error info here */
}
if ((int) data.size < f->reclen)
return 23;
memmove(new_record, data.data, f->reclen);
/* If result greater than or equal key read prev record */
if (memcmp(record + f->rec_index, new_record
+ f->rec_index, key.size) > -1)
{
flags = R_PREV;
result = f->dbp->seq(f->dbp, &key, &data, flags);
if (result)
return 23; /* should have a better error info here */
if ((int) data.size < f->reclen)
return 23;
memmove(new_record, data.data, f->reclen);
}
}
f->start_record = malloc(f->reclen);
memmove(f->start_record, new_record, f->reclen);
break;
case 3: /* Less than or Equal To */
if (alternate == 1)
{
key.data = key_ptr;
key.size = akd->descriptor->len;
result = akd->alt_dbp->seq(akd->alt_dbp, &key, &data,
flags);
if (result)
{
flags = R_LAST;
result = akd->alt_dbp->seq(akd->alt_dbp, &key,
&data, flags);
if (result)
return 23;
}
/* If result greater than Key read prev record */
if (memcmp(key.data, key_ptr, key.size) > 0)
{
flags = R_PREV;
result = akd->alt_dbp->seq(akd->alt_dbp, &key,
&data, flags);
if (result)
return 23;
}
key.data = data.data;
key.size = f->ixd_desc->len;
flags = 0;
result = f->dbp->get(f->dbp, &key, &data, flags);
if (result)
return 23;
if ((int) data.size < f->reclen)
return 23;
memmove(new_record, data.data, f->reclen);
}
else
{
key.data = record + f->rec_index;
key.size = f->ixd_desc->len;
result = f->dbp->seq(f->dbp, &key, &data, flags);
if (result)
{
flags = R_LAST;
result = f->dbp->seq(f->dbp, &key, &data, flags);
if (result)
return 23; /* should have a better error info here */
}
if ((int) data.size < f->reclen)
return 23;
memmove(new_record, data.data, f->reclen);
/* If result greater than key read prev record */
if (memcmp(record + f->rec_index, new_record
+ f->rec_index, key.size) > 0)
{
flags = R_PREV;
result = f->dbp->seq(f->dbp, &key, &data, flags);
if (result)
return 23; /* should have a better error info here */
if ((int) data.size < f->reclen)
return 23;
memmove(new_record, data.data, f->reclen);
}
}
f->start_record = malloc(f->reclen);
memmove(f->start_record, new_record, f->reclen);
break;
case 4: /* Greater than */
if (alternate == 1)
{
key.data = key_ptr;
key.size = akd->descriptor->len;
result = akd->alt_dbp->seq(akd->alt_dbp, &key, &data,
flags);
if (result)
return 23;
/* If result equals Key read next record */
/* if(memcmp(data.data,key_ptr,akd->descriptor->len)==0) */
if (memcmp(key.data, key_ptr, key.size) == 0)
{
flags = R_NEXT;
result = akd->alt_dbp->seq(akd->alt_dbp, &key,
&data, flags);
if (result)
return 23;
}
key.data = data.data;
key.size = f->ixd_desc->len;
flags = 0;
result = f->dbp->get(f->dbp, &key, &data, flags);
if (result)
return 23;
if ((int) data.size < f->reclen)
return 23;
memmove(new_record, data.data, f->reclen);
}
else
{
key.data = record + f->rec_index;
key.size = f->ixd_desc->len;
result = f->dbp->seq(f->dbp, &key, &data, flags);
if (result)
return 23; /* should have a better error info here */
if ((int) data.size < f->reclen)
return 23;
memmove(new_record, data.data, f->reclen);
/* If result equals key read next record */
if (memcmp(record + f->rec_index, new_record
+ f->rec_index, key.size) == 0)
{
flags = R_NEXT;
result = f->dbp->seq(f->dbp, &key, &data, flags);
if (result)
return 23; /* should have a better error info here */
if ((int) data.size < f->reclen)
return 23;
memmove(new_record, data.data, f->reclen);
}
}
f->start_record = malloc(f->reclen);
memmove(f->start_record, new_record, f->reclen);
break;
case 5: /* Greater than or Equal To */
if (alternate == 1)
{
key.data = key_ptr;
key.size = akd->descriptor->len;
result = akd->alt_dbp->seq(akd->alt_dbp, &key, &data,
flags);
if (result)
return 23;
key.data = data.data;
key.size = f->ixd_desc->len;
flags = 0;
result = f->dbp->get(f->dbp, &key, &data, flags);
if (result)
return 23;
if ((int) data.size < f->reclen)
return 23;
memmove(new_record, data.data, f->reclen);
}
else
{
key.data = record + f->rec_index;
key.size = f->ixd_desc->len;
result = f->dbp->seq(f->dbp, &key, &data, flags);
if (result)
return 23; /* should have a better error info here */
if ((int) data.size < f->reclen)
return 23;
memmove(new_record, data.data, f->reclen);
}
f->start_record = malloc(f->reclen);
memmove(f->start_record, new_record, f->reclen);
break;
case 6:
default:
return 99;
}
return 0;
}
default: /* sequential files */
return 0;
}
}
/*------------------------------------------------------------------------*\
| |
| tcob_save_status |
| |
\*------------------------------------------------------------------------*/
int tcob_save_status(char *status, int rt)
{
status[0] = rt / 10 + '0';
status[1] = rt % 10 + '0';
return rt;
}
/*------------------------------------------------------------------------*\
| |
| tcob_rewrite |
| |
\*------------------------------------------------------------------------*/
int tcob_rewrite(struct file_desc *f, char *record, ...)
{
int result;
int read_done = f->read_done;
recno_t recno;
DBT key, data;
va_list args;
char *NL = "\n";
struct fld_desc *reclen_desc;
char *reclen_buf;
f->read_done = 0;
/* Check to see if file is open. If not return File Status 49
In accordance with the Cobol 85 Standard. */
if (f->dbp == NULL)
return 49;
/* Check to see that the record length is valid */
if (f->reclen == -1)
return 99;
/* Check the mode the file is opened in to make sure that rewrite
is Allowed */
if (f->open_mode != FMOD_IO)
return 49;
/* Check that we didn't already hit eof */
if ((f->open_mode == FMOD_IO) && f->eof_hit)
RETURN_STATUS(43);
/* Check that we had a previous successful read */
if (!read_done)
RETURN_STATUS(43);
/* check if reclen was given */
va_start(args,record);
reclen_desc = va_arg(args, struct fld_desc *);
if (reclen_desc != NULL)
reclen_buf = va_arg(args, char *);
switch (f->organization)
{
case ORG_INDEXED:
break;
case ORG_RELATIVE:
break;
case ORG_SEQUENTIAL:
lseek((int) f->dbp, ((f->reclen) * -1), SEEK_CUR);
break;
case ORG_LINESEQUENTIAL:
/* Rewrite No longer supported on Line Sequential files */
return 30;
/* lseek((int)f->dbp, ((f->reclen+1)* -1), SEEK_CUR); */
/* break; */
default:
return 30;
}
data.data = record;
data.size = f->reclen;
/* Save the new record */
switch (f->organization)
{
case ORG_INDEXED:
{
struct altkey_desc *akd;
char *newdata_data;
unsigned int newdata_size;
newdata_data = (char *) malloc(f->reclen);
memmove(newdata_data, record, f->reclen);
newdata_size = f->reclen;
key.data = record + f->rec_index;
key.size = f->ixd_desc->len;
#ifdef USE_LOCKSERVER
/* Check to see if the record is Locked*/
temp_key = (char *) malloc (sizeof(char) * (key.size+1));
strncpy(temp_key,key.data,key.size);
temp_key[key.size]='\0';
result=get_lockserver_lock_owner(fd_filename((int)f->dbp),temp_key);
free(temp_key);
if(result>0)
{
/* This record is locked by another user. Return the Bad news*/
RETURN_STATUS(51);
}
#endif
/* Get the origional Record so we can delete the
Alternate Keys if there is any change */
result = f->dbp->get(f->dbp, &key, &data, 0);
memmove(record, data.data, f->reclen);
if (result)
{
free(newdata_data);
return 23;
}
for (akd = (struct altkey_desc *) (f + 1); akd->offset != -1; akd++)
{
key.data = record + akd->offset;
key.size = akd->descriptor->len;
result = akd->alt_dbp->del(akd->alt_dbp, &key, 0);
#ifdef USE_SYNC
result=akd->alt_dbp->sync(akd->alt_dbp,0);
#endif
}
memmove(record, newdata_data, newdata_size);
key.data = record + f->rec_index;
key.size = f->ixd_desc->len;
data.data = newdata_data;
data.size = newdata_size;
/* Rewrite the Main Record */
result = f->dbp->put(f->dbp, &key, &data, 0);
#ifdef __MINGW32__
int flags = R_PREV;
result = f->dbp->seq(f->dbp, &key, &data, flags);//NILONILO
//f->dbp->get(f->dbp, &key, &data, 0); //NILO
#endif
free(newdata_data);
if (result)
return 99; /* ? error code to be determined */
#ifdef USE_SYNC
result = f->dbp->sync(f->dbp,0);
#endif
#ifdef USE_LOCKSERVER
/* Unlock the Record if it is Locked */
temp_key = (char *) malloc (sizeof(char) * (key.size+1));
strncpy(temp_key,key.data,key.size);
temp_key[key.size]='\0';
result=lockserver_release_specific_lock(fd_filename((int)f->dbp),temp_key);
free(temp_key);
if(result>0)
{
/* This record was not locked */
}
#endif
/* Rewrite the Alternate Keys */
for (akd = (struct altkey_desc *) (f + 1); akd->offset != -1; akd++)
{
key.data = record + akd->offset;
key.size = akd->descriptor->len;
data.data = record + f->rec_index;
data.size = f->ixd_desc->len;
result = akd->alt_dbp->put(akd->alt_dbp, &key, &data, 0);
#ifdef USE_SYNC
result=akd->alt_dbp->sync(akd->alt_dbp,0);
#endif
}
break;
}
case ORG_RELATIVE:
/* va_start(args,record); */
recno = va_arg(args,recno_t);
va_end(args);
lseek((int) f->dbp, ((recno) * ((f->reclen))), SEEK_SET);
result = write((int) f->dbp, record, f->reclen);
if (!result)
return 99; /* what errors should I return? */
break;
case ORG_LINESEQUENTIAL:
result = write((int) f->dbp, record, f->reclen);
if (!result)
return 99; /* what errors should I return? */
result = write((int) f->dbp, NL, 1);
if (!result)
return 99; /* what errors should I return? */
break;
default:
result = write((int) f->dbp, record, f->reclen);
if (!result)
return 99; /* what errors should I return? */
break;
}
return 0;
}
/*------------------------------------------------------------------------*\
| |
| tcob_write_adv |
| |
\*------------------------------------------------------------------------*/
int tcob_write_adv(struct file_desc *f, char *record, int opt, ...)
{
int result;
va_list args;
struct fld_desc *cnt_desc;
char *cnt_buf;
int lines = 0;
int len;
struct fld_desc *reclen_desc;
char *reclen_buf;
/* Check to see if file is open. If not return File Status 48
In accordance with the Cobol 85 Standard. */
if (f->dbp == NULL)
return 48;
/* Check the mode the file is opened in to make sure that write
is Allowed */
if (((f->open_mode != FMOD_OUTPUT) && (f->open_mode != FMOD_IO)
&& (f->open_mode != FMOD_EXTEND)))
return 48;
/* check if reclen was given */
va_start(args,opt);
reclen_desc = va_arg(args, struct fld_desc *);
if (reclen_desc != NULL)
reclen_buf = va_arg(args, char *);
f->with_advancing = 1;
f->adv_before = 0;
/* va_start( args, opt ); */
if (opt > 0)
{
cnt_desc = va_arg( args, struct fld_desc * );
cnt_buf = va_arg( args,char * );
lines = tcob_get_index(cnt_desc, cnt_buf);
}
len = f->reclen;
if (f->organization == ORG_LINESEQUENTIAL)
{
/* removing trailling blanks */
while (len > 0 && record[len - 1] == ' ')
len--;
}
switch (opt)
{
/* 1: write before advancing N lines */
case 1:
result = write((int) f->dbp, record, len);
write((int) f->dbp, "\x0d", 1);
for (; lines > 0; lines--)
write((int) f->dbp, "\x0a", 1);
break;
/* 2: write after advancing N lines */
case 2:
for (; lines > 0; lines--)
write((int) f->dbp, "\x0a", 1);
result = write((int) f->dbp, record, len);
write((int) f->dbp, "\x0d", 1);
break;
/* -1: before advancing page */
case -1:
result = write((int) f->dbp, record, len);
write((int) f->dbp, "\x0c", 1);
break;
/* -2: after advancing page */
case -2:
write((int) f->dbp, "\x0c", 1);
result = write((int) f->dbp, record, len);
write((int) f->dbp, "\x0d", 1);
break;
/* only normal write (error?) */
default:
result = write((int) f->dbp, record, len);
if (f->organization == ORG_LINESEQUENTIAL)
{
write((int) f->dbp, "\x0a", 1);
}
break;
}
if (result == len)
RETURN_STATUS(0);
RETURN_STATUS(result);
}
/*------------------------------------------------------------------------*\
| |
| tcob_sort_open |
| |
\*------------------------------------------------------------------------*/
int tcob_sort_open(struct file_desc *f, char *record, char *fname)
{
DBTYPE type = DB_BTREE;
int sflags = S_IRUSR | S_IWUSR;
#if defined(__MINGW32__) || defined(__CYGWIN__)
int oflags = O_CREAT | O_RDWR | O_BINARY;
#else
int oflags = O_CREAT | O_RDWR;
#endif
/* char *filename; */
int len;
BTREEINFO b;
b.flags = R_DUP;
b.cachesize = 0;
b.maxkeypage = 0;
b.minkeypage = 0;
b.psize = 0;
b.compare = NULL;
b.prefix = NULL;
b.lorder = 0;
/*
beware: fname points to a field storage (non null-terminated)
we must copy fname to a C string and terminate it with a \0
and also trim spaces at the end.
*/
len = f->fname_desc->len;
/*
filename = malloc(len+1);
memmove(filename,fname,len);
do {
filename[len--] = 0;
} while (filename[len] == ' ');
*/
type = DB_BTREE;
f->dbp = db_open(NULL, oflags, sflags, type, &b);
if (!f->dbp)
{
if (errno == EINVAL)
RETURN_STATUS(37);
RETURN_STATUS(30);
}
RETURN_STATUS(0);
}
/*------------------------------------------------------------------------*\
| |
| tcob_sort_release |
| |
\*------------------------------------------------------------------------*/
int tcob_sort_release(struct file_desc *f, char *record, char *sd, ...)
{
int result;
DBT key, data;
va_list args;
char *key1, *key_ptr;
unsigned int i;
data.data = record;
data.size = f->reclen;
key_ptr = key1 = (char *) malloc(f->reclen);
va_start(args, sd);
for (i = 0; sd[i]; i += 2)
{
unsigned int element_size = (unsigned char) sd[i + 1];
char *fld = va_arg (args, char *);
memcpy(key_ptr, fld, element_size);
if (sd[i] == 2)
{
/* If the key is descending then for each character we
perform a binary complement giving the final value.
This way we can combine the Ascending and Descending
Keys into one long key. The result is the final key and
saves us from having to run sort.
*/
unsigned int j;
for (j = 0; j < element_size; j++)
key_ptr[j] = ~key_ptr[j];
}
key_ptr += element_size;
}
va_end(args);
key.data = key1;
key.size = key_ptr - key1;
result = f->dbp->put(f->dbp, &key, &data, 0);
free(key1);
if (!result) /* success */
RETURN_STATUS(0);
else
/* failure */
RETURN_STATUS(99);
}
/*------------------------------------------------------------------------*\
| |
| tcob_sort_return |
| |
\*------------------------------------------------------------------------*/
int tcob_sort_return(struct file_desc *f, char *record)
{
int result;
DBT key, data;
int flags = R_NEXT;
result = f->dbp->seq(f->dbp, &key, &data, flags);
if (result)
RETURN_STATUS(10);
if ((int) data.size < f->reclen)
RETURN_STATUS(10);
memmove(record, data.data, f->reclen);
RETURN_STATUS(0);
}
/*------------------------------------------------------------------------*\
| |
| tcob_sort_using |
| |
\*------------------------------------------------------------------------*/
int tcob_sort_using(struct file_desc *f1, char *fname1, ...)
{
int result, idx;
int sflags = S_IRUSR | S_IWUSR;
DBT key, data;
va_list args;
unsigned int cnt;
unsigned int file_num = 0;
unsigned int key_num;
struct file_desc *temp_f;
char *temp_fname;
struct file_desc *sort_file;
char *sd;
char *record, *rec;
struct file_desc *f[TCOB_MAX_PATHLN];
char *fname[TCOB_MAX_PATHLN];
char *fld[TCOB_MAX_PATHLN];
va_start(args, fname1);
f[file_num] = f1;
fname[file_num] = fname1;
temp_f = f1;
while (temp_f != NULL)
{
temp_f = va_arg(args, struct file_desc *);
if (temp_f == NULL)
break;
temp_fname = va_arg(args, char *);
file_num++;
f[file_num] = temp_f;
fname[file_num] = temp_fname;
}
sort_file = va_arg(args, struct file_desc *);
record = va_arg(args, char *);
sd = va_arg(args, char *);
for (key_num = 0; key_num < (strlen(sd) / 2); key_num++)
{
fld[key_num] = va_arg(args, char * );
}
va_end(args);
for (cnt = 0; cnt <= file_num; cnt++)
{
char *filename;
unsigned int adjusted_reclen;
int len;
int oflags = O_RDONLY;
#if defined(__MINGW32__) || defined(__CYGWIN__)
oflags |= O_BINARY;
#endif
/*
beware: fname points to a field storage (non null-terminated)
we must copy fname to a C string and terminate it with a \0
and also trim spaces at the end.
*/
len = f[cnt]->fname_desc->len;
filename = malloc(len + 1);
memmove(filename, fname[cnt], len);
do
{
filename[len--] = 0;
} while (filename[len] == ' ');
adjusted_reclen = f[cnt]->reclen;
if (f[cnt]->organization != ORG_LINESEQUENTIAL)
{
f[cnt]->dbp = (void *) open(filename, oflags, sflags);
free(filename);
if (!f[cnt]->dbp)
{
if (errno == EINVAL)
{
f[cnt]->dbp = NULL;
return 37;
}
if (errno == ENOENT)
{
f[cnt]->dbp = NULL;
return 35;
}
f[cnt]->dbp = NULL;
return 91;
}
}
else
{
/* create read buffer which can include record delimiters CR, LF */
rec = (char *) malloc(f1->reclen + 3);
if (rec == NULL)
{
free(filename);
return 91;
}
f[cnt]->dbp = (void *) fopen(filename, "r");
free(filename);
if (f[cnt]->dbp == NULL)
return 91;
adjusted_reclen = adjusted_reclen + 2;
}
/*
FIXME:
This code will result in a error condition
when EOF is reached, regarless.
*/
result = 0;
while (result == 0)
{
unsigned int i;
char *key1, *key_ptr;
if (f[cnt]->organization != ORG_LINESEQUENTIAL)
{
result = read((int) f[cnt]->dbp, record, adjusted_reclen);
if (result == 0)
{
close((int) f[cnt]->dbp);
f[cnt]->dbp = NULL;
result = 99;
break;
}
if (result != f[cnt]->reclen)
{
close((int) f[cnt]->dbp);
f[cnt]->dbp = NULL;
result = 99;
return 30;
}
}
else
{
if (fgets(rec, adjusted_reclen, (FILE *) f[cnt]->dbp) == NULL)
{
fclose((FILE *) f[cnt]->dbp);
f[cnt]->dbp = NULL;
result = 99;
break;
}
else
{
/*
remove trailing CR, LF and pad short record
length with blanks
*/
len = strlen(rec);
idx = 0;
while ((len > 0) && (idx < 2))
{
if ((rec[len - 1] == '\r') || (rec[len - 1] == '\n'))
{
rec[len - 1] = '\0';
len--;
}
idx++;
}
while (len <= f[cnt]->reclen)
{
rec[len - 1] = ' ';
len++;
}
memcpy(record, rec, f[cnt]->reclen);
result = f[cnt]->reclen;
}
}
data.data = record;
data.size = f[cnt]->reclen;
key_ptr = key1 = (char *) malloc(f1->reclen);
for (i = 0; sd[i]; i += 2)
{
unsigned int element_size = (unsigned char) sd[i + 1];
memcpy(key_ptr, fld[i >> 1], element_size);
if (sd[i] == 2)
{
/* If the key is descending then for each
character we perform a binary complement
giving the final value. This way we can
combine the Ascending and Descending keys
into one long key. The result is the final
key and saves us from having to run sort.
*/
unsigned int j;
for (j = 0; j < element_size; j++)
key_ptr[j] = ~key_ptr[j];
}
key_ptr += element_size;
}
key.data = key1;
key.size = key_ptr - key1;
result = sort_file->dbp->put(sort_file->dbp, &key, &data, 0);
free(key1);
if (result) /* failure */
return 99;
}
free(rec);
}
return 0;
}
/*------------------------------------------------------------------------*\
| |
| tcob_sort_giving |
| |
\*------------------------------------------------------------------------*/
int tcob_sort_giving(struct file_desc *f1, char *fname1, ...)
{
int result;
int sflags = S_IRUSR | S_IWUSR;
DBT key, data;
int flags = R_NEXT;
struct file_desc *f[TCOB_MAX_PATHLN];
char *fname[TCOB_MAX_PATHLN];
int file_num = 0;
int cnt = 0;
char *temp_fname;
struct file_desc *temp_f;
char *filename;
va_list args;
struct file_desc *sort_file;
char *record, **rec, *pt;
int len;
va_start(args, *fname1);
f[file_num] = f1;
fname[file_num] = fname1;
temp_f = f1;
while (temp_f != NULL)
{
temp_f = va_arg(args, struct file_desc *);
if (temp_f == NULL)
break;
temp_fname = va_arg(args, char *);
file_num++;
f[file_num] = temp_f;
fname[file_num] = temp_fname;
}
sort_file = va_arg(args, struct file_desc *);
record = va_arg(args, char *);
va_end(args);
rec = (char **) malloc(sizeof(char*) * file_num);
for (cnt = 0; cnt <= file_num; cnt++)
{
int oflags = O_CREAT | O_TRUNC | O_RDWR;
#if defined(__MINGW32__) || defined(__CYGWIN__)
oflags |= O_BINARY;
#endif
/* beware: fname points to a field storage (non null-terminated)
we must copy fname to a C string and terminate it with a \0
and also trim spaces at the end. */
len = f[cnt]->fname_desc->len;
filename = malloc(len + 1);
memmove(filename, fname[cnt], len);
do
{
filename[len--] = 0;
} while (filename[len] == ' ');
if (f[cnt]->organization != ORG_LINESEQUENTIAL)
{
rec[cnt] = NULL;
}
else
{
rec[cnt] = (char*) malloc(f[cnt]->reclen + 3);
}
f[cnt]->dbp = (void *) open(filename, oflags, sflags);
free(filename);
if (!f[cnt]->dbp)
{
if (errno == EINVAL)
{
f[cnt]->dbp = NULL;
return 37;
}
if (errno == ENOENT)
{
f[cnt]->dbp = NULL;
return 35;
}
f[cnt]->dbp = NULL;
return 91;
}
result = 0;
}
result = 0;
while (result == 0)
{
result = sort_file->dbp->seq(sort_file->dbp, &key, &data, flags);
if (result)
{
result = 10;
break;
}
if ((int) data.size < sort_file->reclen)
{
result = 10;
break;
}
memmove(record, data.data, sort_file->reclen);
for (cnt = 0; cnt <= file_num; cnt++)
{
if (f[cnt]->organization != ORG_LINESEQUENTIAL)
{
result = write((int) f[cnt]->dbp, record, f[cnt]->reclen);
if (!result)
return 99;
else
result = 0;
}
else
{
memmove(rec[cnt], record, f[cnt]->reclen);
len = f[cnt]->reclen;
pt = rec[cnt];
pt[len--] = '\0';
while ((pt[len] == ' ') && (len >= 0))
{
pt[len] = '\0';
len--;
}
len = strlen(pt);
pt[len++] = '\n';
pt[len] = '\0';
result = write((int) f[cnt]->dbp, rec[cnt], len);
if (!result)
return 99;
else
result = 0;
}
}
}
if (result != 10)
return 99;
for (cnt = 0; cnt <= file_num; cnt++)
{
if (f[cnt]->dbp != NULL)
{
close((int) f[cnt]->dbp);
f[cnt]->dbp = NULL;
}
if (rec[cnt] != NULL)
{
free(rec[cnt]);
rec[cnt] = NULL;
}
}
free(rec);
return 0;
}
/* EOF fileio.c */