OpenCOBOL 1.1pre-rel
fileio.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2002-2009 Keisuke Nishida
00003  * Copyright (C) 2007-2009 Roger While
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Lesser General Public License
00007  * as published by the Free Software Foundation; either version 2.1,
00008  * or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU Lesser General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public
00016  * License along with this library; see the file COPYING.LIB.  If
00017  * not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor
00018  * Boston, MA 02110-1301 USA
00019  */
00020 
00021 #include "config.h"
00022 
00023 #define _LFS64_LARGEFILE                1
00024 #define _LFS64_STDIO                    1
00025 #define _FILE_OFFSET_BITS               64
00026 #define _LARGEFILE64_SOURCE             1
00027 #ifdef _AIX
00028 #define _LARGE_FILES                    1
00029 #endif /* _AIX */
00030 #if defined(__hpux__) && !defined(__LP64__)
00031 #define _APP32_64BIT_OFF_T              1
00032 #endif
00033 
00034 #ifdef __MINGW32__
00035 #define __USE_MINGW_FSEEK       1
00036 #endif /* __MINGW32__ */
00037 
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <stdarg.h>
00041 #include <string.h>
00042 #include <errno.h>
00043 #include <ctype.h>
00044 #include <time.h>
00045 #ifdef  HAVE_SYS_TYPES_H
00046 #include <sys/types.h>
00047 #endif
00048 #ifdef  HAVE_UNISTD_H
00049 #include <unistd.h>
00050 #endif
00051 #include <sys/stat.h>
00052 
00053 #ifdef _WIN32
00054 #define WINDOWS_LEAN_AND_MEAN
00055 #include <windows.h>            /* for GetTempPath, GetTempFileName */
00056 #include <direct.h>
00057 #define fsync   _commit
00058 #define getcwd  _getcwd
00059 #define chdir   _chdir
00060 #define mkdir   _mkdir
00061 #define rmdir   _rmdir
00062 #endif
00063 
00064 #ifdef  HAVE_FCNTL_H
00065 #include <fcntl.h>
00066 #endif
00067 
00068 #ifdef  WITH_DB
00069 #ifdef  USE_DB41
00070 #include <db.h>
00071 #else
00072 #if HAVE_DB1_DB_H
00073 #include <db1/db.h>
00074 #elif HAVE_DB_185_H
00075 #include <db_185.h>
00076 #elif HAVE_DB3_DB_185_H
00077 #include <db3/db_185.h>
00078 #elif HAVE_DB4_DB_185_H
00079 #include <db4/db_185.h>
00080 #elif HAVE_DB4_1_DB_185_H
00081 #include <db4.1/db_185.h>
00082 #elif HAVE_DB4_2_DB_185_H
00083 #include <db4.2/db_185.h>
00084 #elif HAVE_DB4_3_DB_185_H
00085 #include <db4.3/db_185.h>
00086 #elif HAVE_DB4_4_DB_185_H
00087 #include <db4.4/db_185.h>
00088 #elif HAVE_DB4_5_DB_185_H
00089 #include <db4.5/db_185.h>
00090 #elif HAVE_DB_H
00091 #include <db.h>
00092 #endif
00093 #endif  /* USE_DB41 */
00094 #endif  /* WITH_DB */
00095 
00096 #if     defined(WITH_CISAM) || defined(WITH_DISAM) || defined(WITH_VBISAM)
00097 #include <signal.h>
00098 #endif
00099 
00100 #ifdef  WITH_CISAM
00101 #include <isam.h>
00102 #endif
00103 
00104 #ifdef  WITH_DISAM
00105 #include <disam.h>
00106 #endif
00107 
00108 #ifdef  WITH_VBISAM
00109 #include <vbisam.h>
00110 #endif
00111 
00112 #if defined(__hpux__) || defined(_AIX) || defined(__sparc)
00113 #define fseek fseeko
00114 #define ftell ftello
00115 #endif
00116 
00117 #ifdef  _MSC_VER
00118 #define fseek _fseeki64
00119 #define ftell _ftelli64
00120 #define lseek _lseeki64
00121 #define off_t __int64
00122 #endif
00123 
00124 #include "common.h"
00125 #include "coblocal.h"
00126 #include "move.h"
00127 #include "numeric.h"
00128 #include "fileio.h"
00129 #include "byteswap.h"
00130 
00131 #if !defined(__linux__)
00132 #define SEEK_INIT(f)    fseek ((FILE *)f->file, (off_t)0, SEEK_CUR)
00133 #else
00134 #define SEEK_INIT(f)
00135 #endif
00136 
00137 #ifndef O_BINARY
00138 #define O_BINARY        0
00139 #endif
00140 
00141 #ifndef O_LARGEFILE
00142 #define O_LARGEFILE     0
00143 #endif
00144 
00145 #ifdef _WIN32
00146 #define INITIAL_FLAGS   O_BINARY
00147 #else
00148 #define INITIAL_FLAGS   0
00149 #endif
00150 
00151 /* SORT definitions */
00152 
00153 #define COBSORTEND        1
00154 #define COBSORTABORT      2
00155 #define COBSORTFILEERR    3
00156 #define COBSORTNOTOPEN    4
00157 
00158 struct cobitem {
00159         struct cobitem          *next;
00160         size_t                  end_of_block;
00161         unsigned char           block_byte;
00162         unsigned char           unique[sizeof(size_t)];
00163         unsigned char           item[1];
00164 };
00165 
00166 struct memory_struct {
00167         struct cobitem  *first;
00168         struct cobitem  *last;
00169         size_t          count;
00170 };
00171 
00172 struct file_struct {
00173         FILE            *fp;
00174         size_t          count;  /* count of items in temporary files */
00175 };
00176 
00177 struct cobsort {
00178         void                    *pointer;
00179         struct cobitem          *empty;
00180         void                    *sort_return;
00181         cob_field               *fnstatus;
00182         size_t                  unique;
00183         size_t                  retrieving;
00184         size_t                  files_used;
00185         size_t                  size;
00186         size_t                  r_size;
00187         size_t                  w_size;
00188         size_t                  memory;
00189         int                     destination_file;
00190         int                     retrieval_queue;
00191         struct memory_struct    queue[4];
00192         struct file_struct      file[4];
00193 };
00194 
00195 /* End SORT definitions */
00196 
00197 cob_file                *cob_error_file;
00198 
00199 #ifndef _WIN32
00200 static int              cob_iteration = 0;
00201 static pid_t            cob_process_id = 0;
00202 #endif
00203 
00204 static size_t           eop_status = 0;
00205 
00206 static int              cob_do_sync = 0;
00207 static int              cob_sort_memory = 128*1024*1024;
00208 
00209 #ifdef  USE_DB41
00210 static DB_ENV           *bdb_env = NULL;
00211 static char             *bdb_home;
00212 static char             *bdb_buff;
00213 static const char       **bdb_data_dir = NULL;
00214 static void             *record_lock_object;
00215 static size_t           rlo_size = 0;
00216 static unsigned int     bdb_lock_id;
00217 #endif
00218 
00219 static struct file_list {
00220         struct file_list        *next;
00221         cob_file                *file;
00222 } *file_cache = NULL;
00223 
00224 static char             *cob_file_path = NULL;
00225 static char             *cob_ls_nulls = NULL;
00226 static char             *cob_ls_fixed = NULL;
00227 static char             *file_open_env;
00228 static char             *file_open_name;
00229 static char             *file_open_buff;
00230 
00231 /* Emergence buffer in case of malloc fail */
00232 static char             runtime_buffer[COB_SMALL_BUFF];
00233 
00234 #define RETURN_STATUS(x)        do { save_status (f, x, fnstatus); return; } while (0)
00235 
00236 static const int        status_exception[] = {
00237         0,                              /* 0x */
00238         COB_EC_I_O_AT_END,              /* 1x */
00239         COB_EC_I_O_INVALID_KEY,         /* 2x */
00240         COB_EC_I_O_PERMANENT_ERROR,     /* 3x */
00241         COB_EC_I_O_LOGIC_ERROR,         /* 4x */
00242         COB_EC_I_O_RECORD_OPERATION,    /* 5x */
00243         COB_EC_I_O_FILE_SHARING,        /* 6x */
00244         COB_EC_I_O,                     /* unused */
00245         COB_EC_I_O,                     /* unused */
00246         COB_EC_I_O_IMP                  /* 9x */
00247 };
00248 
00249 static const char       * const prefix[] = { "DD_", "dd_", "" };
00250 #define NUM_PREFIX      sizeof(prefix) / sizeof(char *)
00251 
00252 #ifdef  COB_PARAM_CHECK
00253 static const char       parm_msg[] = "CALL to %s requires %d parameters";
00254 #endif
00255 
00256 static int dummy_rnxt_del (cob_file *f);
00257 static int dummy_rewrite (cob_file *f, const int opt);
00258 static int dummy_read (cob_file *f, cob_field *key, const int read_opts);
00259 static int dummy_start (cob_file *f, const int cond, cob_field *key);
00260 
00261 static int cob_file_open (cob_file *f, char *filename, const int mode,
00262                           const int sharing);
00263 static int cob_file_close (cob_file *f, const int opt);
00264 static int cob_file_write_opt (cob_file *f, const int opt);
00265 
00266 static int sequential_read (cob_file *f, const int read_opts);
00267 static int sequential_write (cob_file *f, const int opt);
00268 static int sequential_rewrite (cob_file *f, const int opt);
00269 static int lineseq_read (cob_file *f, const int read_opts);
00270 static int lineseq_write (cob_file *f, const int opt);
00271 static int relative_start (cob_file *f, const int cond, cob_field *k);
00272 static int relative_read (cob_file *f, cob_field *k, const int read_opts);
00273 static int relative_read_next (cob_file *f, const int read_opts);
00274 static int relative_write (cob_file *f, const int opt);
00275 static int relative_rewrite (cob_file *f, const int opt);
00276 static int relative_delete (cob_file *f);
00277 
00278 #if     defined(WITH_DB) || defined(WITH_CISAM) || defined(WITH_DISAM) || defined(WITH_VBISAM) || defined(WITH_INDEX_EXTFH)
00279 
00280 #ifdef  WITH_DB
00281 #ifdef  USE_DB41
00282 #define DB_PUT(db,flags)        db->put (db, NULL, &p->key, &p->data, flags)
00283 #define DB_GET(db,flags)        db->get (db, NULL, &p->key, &p->data, flags)
00284 #define DB_SEQ(db,flags)        db->c_get (db, &p->key, &p->data, flags)
00285 #define DB_DEL(db,key,flags)    db->del (db, NULL, key, flags)
00286 #define DB_CLOSE(db)            db->close (db, 0)
00287 #define DB_SYNC(db)             db->sync (db, 0)
00288 #define cob_dbtsize_t           u_int32_t
00289 #else
00290 #define DB_PUT(db,flags)        db->put (db, &p->key, &p->data, flags)
00291 #define DB_GET(db,flags)        db->get (db, &p->key, &p->data, flags)
00292 #define DB_SEQ(db,flags)        db->seq (db, &p->key, &p->data, flags)
00293 #define DB_DEL(db,key,flags)    db->del (db, key, flags)
00294 #define DB_CLOSE(db)            db->close (db)
00295 #define DB_SYNC(db)             db->sync (db, 0)
00296 #define DB_FIRST                R_FIRST
00297 #define DB_LAST                 R_LAST
00298 #define DB_NEXT                 R_NEXT
00299 #define DB_PREV                 R_PREV
00300 #define cob_dbtsize_t           size_t
00301 #endif
00302 
00303 #define DBT_SET(key,fld)                        \
00304   key.data = fld->data;                         \
00305   key.size = (cob_dbtsize_t) fld->size
00306 
00307 struct indexed_file {
00308         size_t          key_index;
00309         unsigned char   *last_key;      /* the last key written */
00310         unsigned char   *temp_key;      /* used for temporary storage */
00311         DB              **db;           /* database handlers */
00312         DBT             key;
00313         DBT             data;
00314         unsigned char   **last_readkey; /* the last key read */
00315         unsigned int    *last_dupno;    /* the last number of duplicates read */
00316         int             *rewrite_sec_key;
00317 #ifdef  USE_DB41
00318         DBC             **cursor;
00319         DB_LOCK         bdb_file_lock;
00320         char            *filename;      /*needed for record locks*/
00321         DB_LOCK         bdb_record_lock;
00322         int             write_cursor_open;
00323         unsigned int    bdb_lock_id;
00324         int             record_locked;
00325         int             filenamelen;
00326 #endif
00327 };
00328 #endif  /* WITH_DB */
00329 
00330 
00331 static int indexed_open (cob_file *f, char *filename, const int mode,
00332                          const int sharing);
00333 static int indexed_close (cob_file *f, const int opt);
00334 static int indexed_start (cob_file *f, const int cond, cob_field *key);
00335 static int indexed_read (cob_file *f, cob_field *key, const int read_opts);
00336 static int indexed_read_next (cob_file *f, const int read_opts);
00337 static int indexed_write (cob_file *f, const int opt);
00338 static int indexed_delete (cob_file *f);
00339 static int indexed_rewrite (cob_file *f, const int opt);
00340 
00341 #if     !defined(WITH_INDEX_EXTFH) && !defined(WITH_CISAM) && !defined(WITH_DISAM) && !defined(WITH_VBISAM)
00342 static int indexed_write_internal (cob_file *f, const int rewrite, const int opt);
00343 static int indexed_delete_internal (cob_file *f, const int rewrite);
00344 #endif  /* WITH_INDEX_EXTFH */
00345 
00346 static const struct cob_fileio_funcs indexed_funcs = {
00347         indexed_open,
00348         indexed_close,
00349         indexed_start,
00350         indexed_read,
00351         indexed_read_next,
00352         indexed_write,
00353         indexed_rewrite,
00354         indexed_delete
00355 };
00356 
00357 #else   /* WITH_DB || WITH_CISAM || WITH_DISAM || WITH_VBISAM || WITH_INDEX_EXTFH */
00358 
00359 static int
00360 dummy_open (cob_file *f, char *filename, const int mode, const int sharing)
00361 {
00362         return COB_STATUS_91_NOT_AVAILABLE;
00363 }
00364 
00365 static int
00366 dummy_write_close (cob_file *f, const int opt)
00367 {
00368         return COB_STATUS_91_NOT_AVAILABLE;
00369 }
00370 
00371 
00372 static struct cob_fileio_funcs indexed_funcs = {
00373         dummy_open,
00374         dummy_write_close,
00375         dummy_start,
00376         dummy_read,
00377         dummy_rnxt_del,
00378         dummy_write_close,
00379         dummy_rewrite,
00380         dummy_rnxt_del
00381 };
00382 
00383 #endif  /* WITH_DB || WITH_CISAM || WITH_DISAM || WITH_VBISAM || WITH_INDEX_EXTFH */
00384 
00385 
00386 static const struct cob_fileio_funcs sequential_funcs = {
00387         cob_file_open,
00388         cob_file_close,
00389         dummy_start,
00390         dummy_read,
00391         sequential_read,
00392         sequential_write,
00393         sequential_rewrite,
00394         dummy_rnxt_del
00395 };
00396 
00397 static const struct cob_fileio_funcs lineseq_funcs = {
00398         cob_file_open,
00399         cob_file_close,
00400         dummy_start,
00401         dummy_read,
00402         lineseq_read,
00403         lineseq_write,
00404         dummy_rewrite,
00405         dummy_rnxt_del
00406 };
00407 
00408 static const struct cob_fileio_funcs relative_funcs = {
00409         cob_file_open,
00410         cob_file_close,
00411         relative_start,
00412         relative_read,
00413         relative_read_next,
00414         relative_write,
00415         relative_rewrite,
00416         relative_delete
00417 };
00418 
00419 static const struct cob_fileio_funcs    *fileio_funcs[COB_ORG_MAX] = {
00420         &sequential_funcs,
00421         &lineseq_funcs,
00422         &relative_funcs,
00423         &indexed_funcs,
00424         NULL
00425 };
00426 
00427 #if     defined(WITH_INDEX_EXTFH) || defined(WITH_SEQRA_EXTFH)
00428 extern void     extfh_cob_init_fileio   (const struct cob_fileio_funcs *,
00429                                         const struct cob_fileio_funcs *,
00430                                         const struct cob_fileio_funcs *,
00431                                         int (*)(cob_file *, const int));
00432 extern void     extfh_cob_exit_fileio   (void);
00433 #endif
00434 
00435 #ifdef  WITH_INDEX_EXTFH
00436 extern void extfh_indexed_unlock        (cob_file *);
00437 extern int extfh_indexed_locate         (cob_file *, char *);
00438 extern int extfh_indexed_open           (cob_file *, char *, int, int);
00439 extern int extfh_indexed_close          (cob_file *, int);
00440 extern int extfh_indexed_start          (cob_file *, int, cob_field *);
00441 extern int extfh_indexed_read           (cob_file *, cob_field *, int);
00442 extern int extfh_indexed_read_next      (cob_file *, int);
00443 extern int extfh_indexed_write          (cob_file *, int);
00444 extern int extfh_indexed_delete         (cob_file *);
00445 extern int extfh_indexed_rewrite        (cob_file *, int);
00446 #endif
00447 
00448 #ifdef  WITH_SEQRA_EXTFH
00449 extern void extfh_seqra_unlock          (cob_file *);
00450 extern int extfh_seqra_locate           (cob_file *, char *);
00451 extern int extfh_cob_file_open          (cob_file *, char *, int, int);
00452 extern int extfh_cob_file_close         (cob_file *, int);
00453 extern int extfh_sequential_read        (cob_file *, int);
00454 extern int extfh_sequential_write       (cob_file *, int);
00455 extern int extfh_sequential_rewrite     (cob_file *, int);
00456 extern int extfh_relative_start         (cob_file *, int, cob_field *);
00457 extern int extfh_relative_read          (cob_file *, cob_field *, int);
00458 extern int extfh_relative_read_next     (cob_file *, int);
00459 extern int extfh_relative_write         (cob_file *, int);
00460 extern int extfh_relative_rewrite       (cob_file *, int);
00461 extern int extfh_relative_delete        (cob_file *);
00462 #endif
00463 
00464 #if     defined(WITH_CISAM) || defined(WITH_DISAM) || defined(WITH_VBISAM) 
00465 /* Isam File handler packet */
00466 
00467 struct indexfile {
00468         char            *filename;      /* ISAM data file name */
00469         char            *savekey;       /* Area to save last Prime Key read */
00470         char            *recwrk;        /* Record work/save area */
00471         int             isfd;           /* ISAM file number */
00472         int             recnum;         /* last record number read */
00473         int             saverecnum;     /* isrecnum of next record to process */
00474         int             saveerrno;      /* savefileposition errno */
00475         int             lmode;          /* File lock mode for 'isread' */
00476         int             curkey;         /* Current active index */
00477         int             startcond;      /* Previous 'start' condition value */
00478         int             readdir;        /* read direction: ISPREV or ISNEXT */
00479         int             nkeys;          /* Actual keys in file */
00480         int             lenkey;         /* Length of savekey area */
00481         int             eofpending;     /* end of file pending */
00482         int             readdone;       /* A 'read' has been succesfully done */
00483         int             startiscur;     /* The 'start' record is current */
00484         int             keyhasdups;     /* 'curkey' has dups */
00485         int             wrkhasrec;      /* 'recwrk' buffer holds the next|prev record */
00486         struct keydesc  key[1];         /* Table of key information */
00487                                         /* keydesc is defined in (d|c|vb)isam.h */
00488 };
00489 
00490 /* Translate ISAM status to COBOL status and return */
00491 
00492 static int COB_NOINLINE
00493 isretsts (int dfltsts)
00494 {
00495         switch (iserrno) {
00496         case 0:
00497                 dfltsts = COB_STATUS_00_SUCCESS;
00498                 break;
00499         case ENOREC:
00500                 dfltsts = COB_STATUS_23_KEY_NOT_EXISTS;
00501                 break;
00502         case EENDFILE:
00503                 dfltsts = COB_STATUS_10_END_OF_FILE;
00504                 break;
00505         case EPERM:
00506                 dfltsts = COB_STATUS_37_PERMISSION_DENIED;
00507                 break;
00508         case EACCES:
00509                 dfltsts = COB_STATUS_37_PERMISSION_DENIED;
00510                 break;
00511         case EISDIR:
00512                 dfltsts = COB_STATUS_37_PERMISSION_DENIED;
00513                 break;
00514         case EDUPL:
00515                 dfltsts = COB_STATUS_22_KEY_EXISTS;
00516                 break;
00517         case EKEXISTS:
00518                 dfltsts = COB_STATUS_22_KEY_EXISTS;
00519                 break;
00520         case ENOENT:
00521                 dfltsts = COB_STATUS_35_NOT_EXISTS;
00522                 break;
00523         case ENOCURR:
00524                 if (dfltsts != COB_STATUS_10_END_OF_FILE) {
00525                         dfltsts = COB_STATUS_21_KEY_INVALID;
00526                 }
00527                 break;
00528         case ELOCKED:
00529                 dfltsts = COB_STATUS_51_RECORD_LOCKED;
00530                 break;
00531         case EFLOCKED:
00532                 dfltsts = COB_STATUS_61_FILE_SHARING;
00533                 break;
00534         }
00535         return dfltsts;
00536 }
00537 
00538 /* Free memory for indexfile packet */
00539 
00540 static void COB_NOINLINE
00541 freefh (struct indexfile *fh)
00542 {
00543         if (fh == NULL) {
00544                 return;
00545         }
00546         if (fh->filename) {
00547                 free ((void *)fh->filename);
00548         }
00549         if (fh->savekey) {
00550                 free ((void *)fh->savekey);
00551         }
00552         if (fh->recwrk) {
00553                 free ((void *)fh->recwrk);
00554         }
00555         free ((void *)fh);
00556 }
00557 
00558 /*
00559         Restore ISAM file positioning
00560 */
00561 static void
00562 restorefileposition (cob_file *f)
00563 {
00564         struct indexfile        *fh = f->file;
00565         struct keydesc          k0;
00566 
00567         memset ((void *)&k0, 0, sizeof(k0));
00568         if (fh->saverecnum >= 0) {                      /* Switch back to index */
00569                 isrecnum = fh->saverecnum;
00570                 isstart (fh->isfd, &k0, 0, fh->recwrk, ISEQUAL); /* Switch to recnum mode */
00571                 isread (fh->isfd, fh->recwrk, ISEQUAL);         /* Read by record number */
00572                 isstart (fh->isfd, &fh->key[fh->curkey], fh->key[fh->curkey].k_leng, fh->recwrk, ISEQUAL);
00573                 isread (fh->isfd, fh->recwrk, ISEQUAL);
00574                 while (isrecnum != fh->saverecnum) {            /* Read back into position */
00575                         if (isread (fh->isfd, fh->recwrk, fh->readdir) == -1) {
00576                                 break;
00577                         }
00578                 }
00579                 if (isrecnum == fh->saverecnum) {
00580                         if (fh->readdir == ISNEXT) {            /* Back off by one so next read gets this */
00581                                 isread (fh->isfd, fh->recwrk, ISPREV);
00582                         } else {
00583                                 isread (fh->isfd, fh->recwrk, ISNEXT);
00584                         }
00585                 }
00586         } else if (fh->readdone && fh->curkey == 0) {
00587                 memcpy (fh->recwrk + fh->key[0].k_start, fh->savekey, fh->key[0].k_leng);
00588                 isstart (fh->isfd, &fh->key[fh->curkey], fh->key[fh->curkey].k_leng, fh->recwrk, ISGTEQ);
00589         }
00590 }
00591 
00592 /* Save ISAM file positioning information for later 'restorefileposition' */
00593 
00594 static void
00595 savefileposition (cob_file *f)
00596 {
00597         struct indexfile        *fh = f->file;
00598 
00599         if (fh->curkey >= 0 && fh->readdir != -1) {     /* Switch back to index */
00600                 if (fh->wrkhasrec != fh->readdir) {
00601                         fh->eofpending = 0;
00602                         fh->wrkhasrec = 0;
00603                         if (isread (fh->isfd, fh->recwrk, fh->readdir) == -1) { /* Read next record in file */
00604                                 fh->saverecnum = -1;
00605                                 fh->saveerrno = iserrno;
00606                                 if (fh->saveerrno == EENDFILE || fh->saveerrno == ENOREC)  {
00607                                         fh->eofpending = fh->readdir;
00608                                 }
00609                         } else {
00610                                 fh->saverecnum = isrecnum;
00611                                 fh->saveerrno = 0;
00612                         }
00613                         memcpy (fh->recwrk, f->record->data, f->record_max);    /* Restore saved record data */
00614                 }
00615         } else {
00616                 fh->saverecnum = -1;
00617         }
00618 }
00619 #endif /* WITH_CISAM || WITH_DISAM || WITH_VBISAM */
00620 
00621 static void COB_NOINLINE
00622 cob_sync (cob_file *f, const int mode)
00623 {
00624 #ifdef  WITH_DB
00625         struct indexed_file     *p;
00626         size_t                  i;
00627 #ifdef  USE_DB41
00628         int                     n;
00629 #endif
00630 #endif
00631 #if     defined(WITH_CISAM) || defined(WITH_DISAM) || defined(WITH_VBISAM) 
00632         struct indexfile        *fh = f->file;
00633 #endif
00634 
00635         if (f->organization == COB_ORG_INDEXED) {
00636 #ifdef  WITH_DB
00637                 p = f->file;
00638                 for (i = 0; i < f->nkeys; i++) {
00639                         if (p->db[i]) {
00640                                 DB_SYNC (p->db[i]);
00641                         }
00642                 }
00643                 if (mode == 2) {
00644                         for (i = 0; i < f->nkeys; i++) {
00645                                 if (p->db[i]) {
00646 #ifdef  USE_DB41
00647                                         fsync (p->db[i]->fd (p->db[i], &n));
00648 #else
00649                                         fsync (p->db[i]->fd (p->db[i]));
00650 #endif
00651                                 }
00652                         }
00653                 }
00654 #endif  /* WITH_DB */
00655 #if     defined(WITH_CISAM) || defined(WITH_DISAM) || defined(WITH_VBISAM) 
00656                 if (fh) {
00657                         isflush (fh->isfd);
00658                 }
00659 #endif
00660                 return;
00661         }
00662         if (f->organization != COB_ORG_SORT) {
00663                 fflush ((FILE *)f->file);
00664                 if (mode == 2) {
00665                         fsync (fileno ((FILE *)f->file));
00666                 }
00667         }
00668 }
00669 
00670 static void
00671 cob_cache_file (cob_file *f)
00672 {
00673         struct file_list        *l;
00674 
00675         for (l = file_cache; l; l = l->next) {
00676                 if (f == l->file) {
00677                         return;
00678                 }
00679         }
00680         l = cob_malloc (sizeof (struct file_list));
00681         l->file = f;
00682         l->next = file_cache;
00683         file_cache = l;
00684 }
00685 
00686 static void
00687 save_status (cob_file *f, const int status, cob_field *fnstatus)
00688 {
00689         cob_error_file = f;
00690         if (likely(status == 0)) {
00691                 f->file_status[0] = (unsigned char)'0';
00692                 f->file_status[1] = (unsigned char)'0';
00693                 if (fnstatus) {
00694                         fnstatus->data[0] = (unsigned char)'0';
00695                         fnstatus->data[1] = (unsigned char)'0';
00696                 }
00697                 cob_exception_code = 0;
00698                 return;
00699         }
00700         if (likely(status != COB_STATUS_52_EOP)) {
00701                 cob_set_exception (status_exception[status / 10]);
00702         }
00703         f->file_status[0] = cob_i2d (status / 10);
00704         f->file_status[1] = cob_i2d (status % 10);
00705         if (fnstatus) {
00706                 fnstatus->data[0] = f->file_status[0];
00707                 fnstatus->data[1] = f->file_status[1];
00708         }
00709 }
00710 
00711 /*
00712  * Regular file
00713  */
00714 
00715 static size_t COB_NOINLINE
00716 file_linage_check (cob_file *f)
00717 {
00718         struct linage_struct    *lingptr;
00719 
00720         lingptr = (struct linage_struct *)(f->linorkeyptr);
00721         lingptr->lin_lines = cob_get_int (lingptr->linage);
00722         if (lingptr->lin_lines < 1) {
00723                 goto linerr;
00724         }
00725         if (lingptr->latfoot) {
00726                 lingptr->lin_foot = cob_get_int (lingptr->latfoot);
00727                 if (lingptr->lin_foot < 1 || lingptr->lin_foot > lingptr->lin_lines) {
00728                         goto linerr;
00729                 }
00730         } else {
00731                 lingptr->lin_foot = 0;
00732         }
00733         if (lingptr->lattop) {
00734                 lingptr->lin_top = cob_get_int (lingptr->lattop);
00735                 if (lingptr->lin_top < 0) {
00736                         goto linerr;
00737                 }
00738         } else {
00739                 lingptr->lin_top = 0;
00740         }
00741         if (lingptr->latbot) {
00742                 lingptr->lin_bot = cob_get_int (lingptr->latbot);
00743                 if (lingptr->lin_bot < 0) {
00744                         goto linerr;
00745                 }
00746         } else {
00747                 lingptr->lin_bot = 0;
00748         }
00749         return 0;
00750 linerr:
00751         cob_set_int (lingptr->linage_ctr, 0);
00752         return 1;
00753 }
00754 
00755 static int
00756 dummy_rnxt_del (cob_file *f)
00757 {
00758         return COB_STATUS_91_NOT_AVAILABLE;
00759 }
00760 
00761 static int
00762 dummy_rewrite (cob_file *f, const int opt)
00763 {
00764         return COB_STATUS_91_NOT_AVAILABLE;
00765 }
00766 
00767 static int
00768 dummy_read (cob_file *f, cob_field *key, const int read_opts)
00769 {
00770         return COB_STATUS_91_NOT_AVAILABLE;
00771 }
00772 
00773 static int
00774 dummy_start (cob_file *f, const int cond, cob_field *key)
00775 {
00776         return COB_STATUS_91_NOT_AVAILABLE;
00777 }
00778 
00779 static int COB_NOINLINE
00780 cob_file_open (cob_file *f, char *filename, const int mode, const int sharing)
00781 {
00782         FILE                    *fp = NULL;
00783         struct linage_struct    *lingptr;
00784 #ifdef HAVE_FCNTL
00785         int                     ret;
00786         struct flock            lock;
00787 #endif
00788 
00789         /* open the file */
00790         switch (mode) {
00791         case COB_OPEN_INPUT:
00792 #if !defined(_WIN32) || defined(_MSC_VER)
00793                 if (f->organization == COB_ORG_LINE_SEQUENTIAL)
00794                         fp = fopen (filename, "r");
00795                 else
00796 #endif
00797                         fp = fopen (filename, "rb");
00798                 break;
00799         case COB_OPEN_OUTPUT:
00800                 if (f->organization == COB_ORG_RELATIVE)
00801                         fp = fopen (filename, "wb+");
00802 #if !defined(_WIN32) || defined(_MSC_VER)
00803                 else if (f->organization == COB_ORG_LINE_SEQUENTIAL)
00804                         fp = fopen (filename, "w");
00805 #endif
00806                 else
00807                         fp = fopen (filename, "wb");
00808                 break;
00809         case COB_OPEN_I_O:
00810 #if !defined(_WIN32) || defined(_MSC_VER)
00811                 if (f->organization == COB_ORG_LINE_SEQUENTIAL)
00812                         fp = fopen (filename, "r+");
00813                 else
00814 #endif
00815                         fp = fopen (filename, "rb+");
00816                 break;
00817         case COB_OPEN_EXTEND:
00818 #if !defined(_WIN32) || defined(_MSC_VER)
00819                 if (f->organization == COB_ORG_LINE_SEQUENTIAL)
00820                         fp = fopen (filename, "a+");
00821                 else
00822 #endif
00823                         fp = fopen (filename, "ab+");
00824                 break;
00825         }
00826         if (fp == NULL) {
00827                 return errno;
00828         }
00829 
00830         if (mode == COB_OPEN_EXTEND) {
00831                 fseek (fp, (off_t) 0, SEEK_END);
00832         }
00833 
00834 #ifdef HAVE_FCNTL
00835         /* lock the file */
00836         if (memcmp (filename, "/dev/", 5)) {
00837                 memset ((unsigned char *)&lock, 0, sizeof (struct flock));
00838                 lock.l_type = (sharing || mode == COB_OPEN_OUTPUT) ? F_WRLCK : F_RDLCK;
00839                 lock.l_whence = SEEK_SET;
00840                 lock.l_start = 0;
00841                 lock.l_len = 0;
00842                 if (fcntl (fileno (fp), F_SETLK, &lock) < 0) {
00843                         ret = errno;
00844                         fclose (fp);
00845                         return ret;
00846                 }
00847         }
00848 #endif
00849 
00850         f->file = fp;
00851         if (unlikely(f->flag_select_features & COB_SELECT_LINAGE)) {
00852                 if (file_linage_check (f)) {
00853                         return COB_LINAGE_INVALID;
00854                 }
00855                 f->flag_needs_top = 1;
00856                 lingptr = (struct linage_struct *)(f->linorkeyptr);
00857                 cob_set_int (lingptr->linage_ctr, 1);
00858         }
00859         return 0;
00860 }
00861 
00862 static int COB_NOINLINE
00863 cob_file_close (cob_file *f, const int opt)
00864 {
00865 #ifdef HAVE_FCNTL
00866         struct flock lock;
00867 #endif
00868 
00869         switch (opt) {
00870         case COB_CLOSE_NORMAL:
00871         case COB_CLOSE_LOCK:
00872         case COB_CLOSE_NO_REWIND:
00873                 if (f->organization == COB_ORG_LINE_SEQUENTIAL) {
00874                         if (f->flag_needs_nl && !(f->flag_select_features & COB_SELECT_LINAGE)) {
00875                                 f->flag_needs_nl = 0;
00876                                 putc ('\n', (FILE *)f->file);
00877                         }
00878                 }
00879 #ifdef HAVE_FCNTL
00880                 /* unlock the file */
00881                 memset ((unsigned char *)&lock, 0, sizeof (struct flock));
00882                 lock.l_type = F_UNLCK;
00883                 lock.l_whence = SEEK_SET;
00884                 lock.l_start = 0;
00885                 lock.l_len = 0;
00886                 fcntl (fileno ((FILE *)f->file), F_SETLK, &lock);
00887 #endif
00888                 /* close the file */
00889                 fclose ((FILE *)f->file);
00890                 if (opt == COB_CLOSE_NO_REWIND) {
00891                         f->open_mode = COB_OPEN_CLOSED;
00892                         return COB_STATUS_07_SUCCESS_NO_UNIT;
00893                 }
00894                 return COB_STATUS_00_SUCCESS;
00895         default:
00896                 fflush ((FILE *)f->file);
00897                 return COB_STATUS_07_SUCCESS_NO_UNIT;
00898         }
00899 }
00900 
00901 static int COB_NOINLINE
00902 cob_linage_write_opt (cob_file *f, const int opt)
00903 {
00904         struct linage_struct    *lingptr;
00905         int                     i, n;
00906 
00907         lingptr = (struct linage_struct *)(f->linorkeyptr);
00908         if (unlikely(opt & COB_WRITE_PAGE)) {
00909                 i = cob_get_int (lingptr->linage_ctr);
00910                 if (i == 0) {
00911                         return COB_STATUS_57_I_O_LINAGE;
00912                 }
00913                 n = lingptr->lin_lines;
00914                 for (; i < n; i++) {
00915                         putc ('\n', (FILE *)f->file);
00916                 }
00917                 for (i = 0; i < lingptr->lin_bot; i++) {
00918                         putc ('\n', (FILE *)f->file);
00919                 }
00920                 if (file_linage_check (f)) {
00921                         return COB_STATUS_57_I_O_LINAGE;
00922                 }
00923                 for (i = 0; i < lingptr->lin_top; i++) {
00924                         putc ('\n', (FILE *)f->file);
00925                 }
00926                 cob_set_int (lingptr->linage_ctr, 1);
00927         } else if (opt & COB_WRITE_LINES) {
00928                 n = cob_get_int (lingptr->linage_ctr);
00929                 if (n == 0) {
00930                         return COB_STATUS_57_I_O_LINAGE;
00931                 }
00932                 cob_add_int (lingptr->linage_ctr, opt & COB_WRITE_MASK);
00933                 i = cob_get_int (lingptr->linage_ctr);
00934                 if ((opt & COB_WRITE_EOP) && lingptr->lin_foot) {
00935                         if (i >= lingptr->lin_foot) {
00936                                 eop_status = 1;
00937                         }
00938                 }
00939                 if (i > lingptr->lin_lines) {
00940                         if (opt & COB_WRITE_EOP) {
00941                                 eop_status = 1;
00942                         }
00943                         for (; n < lingptr->lin_lines; n++) {
00944                                 putc ('\n', (FILE *)f->file);
00945                         }
00946                         for (i = 0; i < lingptr->lin_bot; i++) {
00947                                 putc ('\n', (FILE *)f->file);
00948                         }
00949                         if (file_linage_check (f)) {
00950                                 return COB_STATUS_57_I_O_LINAGE;
00951                         }
00952                         cob_set_int (lingptr->linage_ctr, 1);
00953                         for (i = 0; i < lingptr->lin_top; i++) {
00954                                 putc ('\n', (FILE *)f->file);
00955                         }
00956                 } else {
00957                         for (i = (opt & COB_WRITE_MASK) - 1; i > 0; i--)
00958                                 putc ('\n', (FILE *)f->file);
00959                 }
00960         }
00961         return 0;
00962 }
00963 
00964 static int
00965 cob_file_write_opt (cob_file *f, const int opt)
00966 {
00967         int     i;
00968 
00969         if (unlikely(f->flag_select_features & COB_SELECT_LINAGE)) {
00970                 return cob_linage_write_opt (f, opt);
00971         }
00972         if (opt & COB_WRITE_LINES) {
00973                 for (i = opt & COB_WRITE_MASK; i > 0; i--)
00974                         putc ('\n', (FILE *)f->file);
00975         } else if (opt & COB_WRITE_PAGE) {
00976                 putc ('\f', (FILE *)f->file);
00977         }
00978         return 0;
00979 }
00980 
00981 /*
00982  * SEQUENTIAL
00983  */
00984 
00985 static int
00986 sequential_read (cob_file *f, const int read_opts)
00987 {
00988         size_t  bytesread;
00989 
00990 #if     WITH_VARSEQ == 0 || WITH_VARSEQ == 1 || WITH_VARSEQ == 3
00991         union {
00992                 unsigned char   sbuff[4];
00993                 unsigned short  sshort[2];
00994                 unsigned int    sint;
00995         } recsize;
00996 #endif
00997 #ifdef  WITH_SEQRA_EXTFH
00998         int     extfh_ret;
00999 
01000         extfh_ret = extfh_sequential_read (f, read_opts);
01001         if (extfh_ret != COB_NOT_CONFIGURED) {
01002                 return extfh_ret;
01003         }
01004 #endif  /* WITH_SEQRA_EXTFH */
01005 
01006         SEEK_INIT (f);
01007 
01008         /* read the record size */
01009         if (f->record_min != f->record_max) {
01010 #if     WITH_VARSEQ == 2
01011                 if (unlikely(fread (&f->record->size, sizeof (f->record->size), 1, (FILE *)f->file) != 1)) {
01012 #elif   WITH_VARSEQ == 3
01013                 if (unlikely(fread (recsize.sbuff, 2, 1, (FILE *)f->file) != 1)) {
01014 #else
01015                 if (unlikely(fread (recsize.sbuff, 4, 1, (FILE *)f->file) != 1)) {
01016 #endif
01017                         if (ferror ((FILE *)f->file)) {
01018                                 return COB_STATUS_30_PERMANENT_ERROR;
01019                         } else {
01020                                 return COB_STATUS_10_END_OF_FILE;
01021                         }
01022                 }
01023 #if     WITH_VARSEQ == 0 || WITH_VARSEQ == 3
01024 #ifdef WORDS_BIGENDIAN
01025                 f->record->size = recsize.sshort[0];
01026 #else
01027                 f->record->size = COB_BSWAP_16 (recsize.sshort[0]);
01028 #endif
01029 #elif   WITH_VARSEQ == 1
01030 #ifdef WORDS_BIGENDIAN
01031                 f->record->size = recsize.sint;
01032 #else
01033                 f->record->size = COB_BSWAP_32 (recsize.sint);
01034 #endif
01035 #endif
01036         }
01037 
01038         /* read the record */
01039         bytesread = fread (f->record->data, 1, f->record->size, (FILE *)f->file);
01040         if (unlikely(bytesread != f->record->size)) {
01041                 if (ferror ((FILE *)f->file)) {
01042                         return COB_STATUS_30_PERMANENT_ERROR;
01043                 } else if (bytesread == 0) {
01044                         return COB_STATUS_10_END_OF_FILE;
01045                 } else {
01046                         return COB_STATUS_04_SUCCESS_INCOMPLETE;
01047                 }
01048         }
01049         return COB_STATUS_00_SUCCESS;
01050 }
01051 
01052 static int
01053 sequential_write (cob_file *f, const int opt)
01054 {
01055         int     ret;
01056 
01057 #if     WITH_VARSEQ == 0 || WITH_VARSEQ == 1 || WITH_VARSEQ == 3
01058         union {
01059                 unsigned char   sbuff[4];
01060                 unsigned short  sshort[2];
01061                 unsigned int    sint;
01062         } recsize;
01063 #endif
01064 
01065 #ifdef  WITH_SEQRA_EXTFH
01066         int     extfh_ret;
01067 
01068         extfh_ret = extfh_sequential_write (f, opt);
01069         if (extfh_ret != COB_NOT_CONFIGURED) {
01070                 return extfh_ret;
01071         }
01072 #endif  /* WITH_SEQRA_EXTFH */
01073 
01074         SEEK_INIT (f);
01075 
01076         /* WRITE AFTER */
01077         if (opt & COB_WRITE_AFTER) {
01078                 ret = cob_file_write_opt (f, opt);
01079                 if (ret) {
01080                         return ret;
01081                 }
01082                 f->flag_needs_nl = 1;
01083         }
01084 
01085         /* write the record size */
01086         if (f->record_min != f->record_max) {
01087 #if     WITH_VARSEQ == 2
01088                 if (unlikely(fwrite (&f->record->size, sizeof (f->record->size), 1, (FILE *)f->file) != 1)) {
01089 #else   /* VARSEQ 0, 1, 3 */
01090 #if     WITH_VARSEQ == 1
01091 #ifdef WORDS_BIGENDIAN
01092                 recsize.sint = f->record->size;
01093 #else
01094                 recsize.sint = COB_BSWAP_32 ((unsigned int)f->record->size);
01095 #endif
01096 #else   /* VARSEQ 0, 3 */
01097                 recsize.sint = 0;
01098 #ifdef WORDS_BIGENDIAN
01099                 recsize.sshort[0] = f->record->size;
01100 #else
01101                 recsize.sshort[0] = COB_BSWAP_16 ((unsigned short)f->record->size);
01102 #endif
01103 #endif  /* VARSEQ 0, 3 */
01104 #if     WITH_VARSEQ == 3
01105                 if (unlikely(fwrite (recsize.sbuff, 2, 1, (FILE *)f->file) != 1)) {
01106 #else
01107                 if (unlikely(fwrite (recsize.sbuff, 4, 1, (FILE *)f->file) != 1)) {
01108 #endif  /* VARSEQ 3 */
01109 #endif  /* VARSEQ 0, 1, 3 */
01110                         return COB_STATUS_30_PERMANENT_ERROR;
01111                 }
01112         }
01113 
01114         /* write the record */
01115         if (unlikely(fwrite (f->record->data, f->record->size, 1, (FILE *)f->file) != 1)) {
01116                 return COB_STATUS_30_PERMANENT_ERROR;
01117         }
01118 
01119         /* WRITE BEFORE */
01120         if (opt & COB_WRITE_BEFORE) {
01121                 ret = cob_file_write_opt (f, opt);
01122                 if (ret) {
01123                         return ret;
01124                 }
01125                 f->flag_needs_nl = 0;
01126         }
01127 
01128         return COB_STATUS_00_SUCCESS;
01129 }
01130 
01131 static int
01132 sequential_rewrite (cob_file *f, const int opt)
01133 {
01134 #ifdef  WITH_SEQRA_EXTFH
01135         int     extfh_ret;
01136 
01137         extfh_ret = extfh_sequential_rewrite (f, opt);
01138         if (extfh_ret != COB_NOT_CONFIGURED) {
01139                 return extfh_ret;
01140         }
01141 #endif  /* WITH_SEQRA_EXTFH */
01142         if (fseek ((FILE *)f->file, -(off_t) f->record->size, SEEK_CUR)) {
01143                 return COB_STATUS_30_PERMANENT_ERROR;
01144         }
01145         if (fwrite (f->record->data, f->record->size, 1, (FILE *)f->file) != 1) {
01146                 return COB_STATUS_30_PERMANENT_ERROR;
01147         }
01148         return COB_STATUS_00_SUCCESS;
01149 }
01150 
01151 /*
01152  * LINE SEQUENTIAL
01153  */
01154 
01155 static int
01156 lineseq_read (cob_file *f, const int read_opts)
01157 {
01158         unsigned char   *dataptr;
01159         size_t          i = 0;
01160         int             n;
01161 
01162 #ifdef  WITH_SEQRA_EXTFH
01163         int             extfh_ret;
01164 
01165         extfh_ret = extfh_sequential_read (f, read_opts);
01166         if (extfh_ret != COB_NOT_CONFIGURED) {
01167                 return extfh_ret;
01168         }
01169 #endif  /* WITH_SEQRA_EXTFH */
01170 
01171         dataptr = f->record->data;
01172         for (; ;) {
01173                 n = getc ((FILE *)f->file);
01174                 if (unlikely(n == EOF)) {
01175                         if (!i) {
01176                                 return COB_STATUS_10_END_OF_FILE;
01177                         } else {
01178                                 break;
01179                         }
01180                 }
01181                 if (unlikely(n == 0 && cob_ls_nulls != NULL)) {
01182                         n = getc ((FILE *)f->file);
01183                         if (n == EOF) {
01184                                 return COB_STATUS_30_PERMANENT_ERROR;
01185                         }
01186                 } else {
01187                         if (n == '\r') {
01188                                 continue;
01189                         }
01190                         if (n == '\n') {
01191                                 break;
01192                         }
01193                 }
01194                 if (likely(i < f->record->size)) {
01195                         *dataptr++ = n;
01196                         i++;
01197                 }
01198         }
01199         if (i < f->record->size) {
01200                 /* fill the record with spaces */
01201                 memset ((unsigned char *)f->record->data + i, ' ', f->record->size - i);
01202         }
01203         if (f->record_size) {
01204                 cob_set_int (f->record_size, (int)i);
01205         }
01206         return COB_STATUS_00_SUCCESS;
01207 }
01208 
01209 static int
01210 lineseq_write (cob_file *f, const int opt)
01211 {
01212         unsigned char           *p;
01213         struct linage_struct    *lingptr;
01214         size_t                  size;
01215         int                     i;
01216         int                     ret;
01217 
01218 #ifdef  WITH_SEQRA_EXTFH
01219         int             extfh_ret;
01220 
01221         extfh_ret = extfh_sequential_write (f, opt);
01222         if (extfh_ret != COB_NOT_CONFIGURED) {
01223                 return extfh_ret;
01224         }
01225 #endif  /* WITH_SEQRA_EXTFH */
01226 
01227 /* RXW
01228         if (opt == 0) {
01229                 opt = COB_WRITE_BEFORE | COB_WRITE_LINES | 1;
01230         }
01231 */
01232 
01233         /* determine the size to be written */
01234         if (unlikely(cob_ls_fixed != NULL)) {
01235                 size = f->record->size;
01236         } else {
01237                 for (i = (int)f->record->size - 1; i >= 0; i--) {
01238                         if (f->record->data[i] != ' ') {
01239                                 break;
01240                         }
01241                 }
01242                 size = i + 1;
01243         }
01244 
01245         if (unlikely(f->flag_select_features & COB_SELECT_LINAGE)) {
01246                 if (f->flag_needs_top) {
01247                         f->flag_needs_top = 0;
01248                         lingptr = (struct linage_struct *)(f->linorkeyptr);
01249                         for (i = 0; i < lingptr->lin_top; i++) {
01250                                 putc ('\n', (FILE *)f->file);
01251                         }
01252                 }
01253         }
01254         /* WRITE AFTER */
01255         if (opt & COB_WRITE_AFTER) {
01256                 ret = cob_file_write_opt (f, opt);
01257                 if (ret) {
01258                         return ret;
01259                 }
01260                 f->flag_needs_nl = 1;
01261         }
01262 
01263         /* write to the file */
01264         if (size) {
01265                 if (unlikely(cob_ls_nulls != NULL)) {
01266                         p = f->record->data;
01267                         for (i = 0; i < (int)size; i++, p++) {
01268                                 if (*p < ' ') {
01269                                         putc (0, (FILE *)f->file);
01270                                 }
01271                                 putc ((int)(*p), (FILE *)f->file);
01272                         }
01273                 } else {
01274                         if (unlikely(fwrite (f->record->data, size, 1,
01275                                      (FILE *)f->file) != 1)) {
01276                                 return COB_STATUS_30_PERMANENT_ERROR;
01277                         }
01278                 }
01279         }
01280 
01281         if (unlikely(f->flag_select_features & COB_SELECT_LINAGE)) {
01282                 putc ('\n', (FILE *)f->file);
01283         }
01284 
01285         /* WRITE BEFORE */
01286         if (opt & COB_WRITE_BEFORE) {
01287                 ret = cob_file_write_opt (f, opt);
01288                 if (ret) {
01289                         return ret;
01290                 }
01291                 f->flag_needs_nl = 0;
01292         }
01293 
01294         if (unlikely(eop_status)) {
01295                 eop_status = 0;
01296                 cob_exception_code = 0x0502;
01297                 return COB_STATUS_52_EOP;
01298         }
01299         return COB_STATUS_00_SUCCESS;
01300 }
01301 
01302 /*
01303  * RELATIVE
01304  */
01305 
01306 static int
01307 relative_start (cob_file *f, const int cond, cob_field *k)
01308 {
01309         int     kindex;
01310         size_t  relsize;
01311         off_t   off;
01312 #ifdef  WITH_SEQRA_EXTFH
01313         int     extfh_ret;
01314 
01315         extfh_ret = extfh_relative_start (f, cond, k);
01316         if (extfh_ret != COB_NOT_CONFIGURED) {
01317                 return extfh_ret;
01318         }
01319 #endif  /* WITH_SEQRA_EXTFH */
01320 
01321         /* get the index */
01322         kindex = cob_get_int (k) - 1;
01323         relsize = f->record_max + sizeof (f->record->size);
01324         if (cond == COB_LT) {
01325                 kindex--;
01326         } else if (cond == COB_GT) {
01327                 kindex++;
01328         }
01329 
01330         /* seek the index */
01331         while (1) {
01332                 off = kindex * relsize;
01333                 if (fseek ((FILE *)f->file, off, SEEK_SET) != 0 ||
01334                     fread (&f->record->size, sizeof (f->record->size),
01335                            1, (FILE *)f->file) != 1) {
01336                                 return COB_STATUS_23_KEY_NOT_EXISTS;
01337                 }
01338 
01339                 /* check if a valid record */
01340                 if (f->record->size > 0) {
01341                         cob_set_int (k, kindex + 1);
01342                         fseek ((FILE *)f->file, - (off_t) sizeof (f->record->size), SEEK_CUR);
01343                         return COB_STATUS_00_SUCCESS;
01344                 }
01345 
01346                 /* continue */
01347                 switch (cond) {
01348                 case COB_EQ:
01349                         return COB_STATUS_23_KEY_NOT_EXISTS;
01350                 case COB_LT:
01351                 case COB_LE:
01352                         kindex--;
01353                         break;
01354                 case COB_GT:
01355                 case COB_GE:
01356                         kindex++;
01357                         break;
01358                 }
01359         }
01360 }
01361 
01362 static int
01363 relative_read (cob_file *f, cob_field *k, const int read_opts)
01364 {
01365         int     relnum;
01366         size_t  relsize;
01367         off_t   off;
01368 #ifdef  WITH_SEQRA_EXTFH
01369         int     extfh_ret;
01370 
01371         extfh_ret = extfh_relative_read (f, k, read_opts);
01372         if (extfh_ret != COB_NOT_CONFIGURED) {
01373                 return extfh_ret;
01374         }
01375 #endif  /* WITH_SEQRA_EXTFH */
01376 
01377         SEEK_INIT (f);
01378 
01379         relnum = cob_get_int (k) - 1;
01380         relsize = f->record_max + sizeof (f->record->size);
01381         off = relnum * relsize;
01382         if (fseek ((FILE *)f->file, off, SEEK_SET) != 0 ||
01383             fread (&f->record->size, sizeof (f->record->size),
01384                    1, (FILE *)f->file) != 1) {
01385                         return COB_STATUS_23_KEY_NOT_EXISTS;
01386         }
01387 
01388         if (f->record->size == 0) {
01389                 fseek ((FILE *)f->file, - (off_t) sizeof (f->record->size), SEEK_CUR);
01390                 return COB_STATUS_23_KEY_NOT_EXISTS;
01391         }
01392 
01393         if (fread (f->record->data, f->record_max, 1, (FILE *)f->file) != 1) {
01394                 return COB_STATUS_30_PERMANENT_ERROR;
01395         }
01396         return COB_STATUS_00_SUCCESS;
01397 }
01398 
01399 static int
01400 relative_read_next (cob_file *f, const int read_opts)
01401 {
01402         off_t   off;
01403         size_t  relsize;
01404         int     relnum;
01405 #ifdef  WITH_SEQRA_EXTFH
01406         int     extfh_ret;
01407 
01408         extfh_ret = extfh_relative_read_next (f, read_opts);
01409         if (extfh_ret != COB_NOT_CONFIGURED) {
01410                 return extfh_ret;
01411         }
01412 #endif  /* WITH_SEQRA_EXTFH */
01413 
01414         SEEK_INIT (f);
01415 
01416         relsize = f->record_max + sizeof (f->record->size);
01417         while (1) {
01418                 if (fread (&f->record->size, sizeof (f->record->size), 1, (FILE *)f->file) != 1) {
01419                         if (ferror ((FILE *)f->file)) {
01420                                 return COB_STATUS_30_PERMANENT_ERROR;
01421                         } else {
01422                                 return COB_STATUS_10_END_OF_FILE;
01423                         }
01424                 }
01425 
01426                 if (f->keys[0].field) {
01427                         if (f->flag_first_read) {
01428                                 cob_set_int (f->keys[0].field, 1);
01429                                 f->flag_first_read = 0;
01430                         } else {
01431                                 off = ftell ((FILE *)f->file);
01432                                 relnum = (int)((off / relsize) + 1);
01433                                 cob_set_int (f->keys[0].field, 0);
01434                                 if (cob_add_int (f->keys[0].field, relnum) != 0) {
01435                                         fseek ((FILE *)f->file, -(off_t) sizeof (f->record->size),
01436                                                SEEK_CUR);
01437                                         return COB_STATUS_14_OUT_OF_KEY_RANGE;
01438                                 }
01439                         }
01440                 }
01441 
01442                 if (f->record->size > 0) {
01443                         if (fread (f->record->data, f->record_max, 1, (FILE *)f->file) != 1) {
01444                                 return COB_STATUS_30_PERMANENT_ERROR;
01445                         }
01446                         return COB_STATUS_00_SUCCESS;
01447                 }
01448 
01449                 fseek ((FILE *)f->file, (off_t) f->record_max, SEEK_CUR);
01450         }
01451 }
01452 
01453 static int
01454 relative_write (cob_file *f, const int opt)
01455 {
01456         size_t  size;
01457         size_t  relsize;
01458         int     i;
01459         int     kindex;
01460         off_t   off;
01461 #ifdef  WITH_SEQRA_EXTFH
01462         int     extfh_ret;
01463 
01464         extfh_ret = extfh_relative_write (f, opt);
01465         if (extfh_ret != COB_NOT_CONFIGURED) {
01466                 return extfh_ret;
01467         }
01468 #endif  /* WITH_SEQRA_EXTFH */
01469 
01470         SEEK_INIT (f);
01471 
01472         relsize = f->record_max + sizeof (f->record->size);
01473         if (f->access_mode != COB_ACCESS_SEQUENTIAL) {
01474                 kindex = cob_get_int (f->keys[0].field) - 1;
01475                 if (kindex < 0) {
01476                         return COB_STATUS_21_KEY_INVALID;
01477                 }
01478                 off = (off_t) (relsize * kindex);
01479                 if (fseek ((FILE *)f->file, off, SEEK_SET) != 0) {
01480                         return COB_STATUS_21_KEY_INVALID;
01481                 }
01482         } else {
01483                 off = ftell ((FILE *)f->file);
01484         }
01485 
01486         if (fread (&size, sizeof (size), 1, (FILE *)f->file) > 0) {
01487                 fseek ((FILE *)f->file, -(off_t) sizeof (size), SEEK_CUR);
01488                 if (size > 0) {
01489                         return COB_STATUS_22_KEY_EXISTS;
01490                 }
01491         } else {
01492                 fseek ((FILE *)f->file, off, SEEK_SET);
01493         }
01494 
01495         if (fwrite (&f->record->size, sizeof (f->record->size), 1, (FILE *)f->file) != 1) {
01496                 return COB_STATUS_30_PERMANENT_ERROR;
01497         }
01498         if (fwrite (f->record->data, f->record_max, 1, (FILE *)f->file) != 1) {
01499                 return COB_STATUS_30_PERMANENT_ERROR;
01500         }
01501 
01502         /* update RELATIVE KEY */
01503         if (f->access_mode == COB_ACCESS_SEQUENTIAL) {
01504                 if (f->keys[0].field) {
01505 /*
01506                         off = ftell ((FILE *)f->file);
01507 */
01508                         off += relsize;
01509                         i = (int)(off / relsize);
01510                         cob_set_int (f->keys[0].field, i);
01511                 }
01512         }
01513 
01514         return COB_STATUS_00_SUCCESS;
01515 }
01516 
01517 static int
01518 relative_rewrite (cob_file *f, const int opt)
01519 {
01520         size_t  relsize;
01521         int     relnum;
01522         off_t   off;
01523 #ifdef  WITH_SEQRA_EXTFH
01524         int     extfh_ret;
01525 
01526         extfh_ret = extfh_relative_rewrite (f, opt);
01527         if (extfh_ret != COB_NOT_CONFIGURED) {
01528                 return extfh_ret;
01529         }
01530 #endif  /* WITH_SEQRA_EXTFH */
01531 
01532         if (f->access_mode == COB_ACCESS_SEQUENTIAL) {
01533                 fseek ((FILE *)f->file, -(off_t) f->record_max, SEEK_CUR);
01534         } else {
01535                 relsize = f->record_max + sizeof (f->record->size);
01536                 relnum = cob_get_int (f->keys[0].field) - 1;
01537                 off = relnum * relsize;
01538                 if (fseek ((FILE *)f->file, off, SEEK_SET) != 0 ||
01539                     fread (&f->record->size, sizeof (f->record->size),
01540                            1, (FILE *)f->file) != 1) {
01541                                 return COB_STATUS_23_KEY_NOT_EXISTS;
01542                 }
01543                 SEEK_INIT (f);
01544         }
01545 
01546         if (fwrite (f->record->data, f->record_max, 1, (FILE *)f->file) != 1) {
01547                 return COB_STATUS_30_PERMANENT_ERROR;
01548         }
01549         return COB_STATUS_00_SUCCESS;
01550 }
01551 
01552 static int
01553 relative_delete (cob_file *f)
01554 {
01555         size_t  relsize;
01556         int     relnum;
01557         off_t   off;
01558 #ifdef  WITH_SEQRA_EXTFH
01559         int     extfh_ret;
01560 
01561         extfh_ret = extfh_relative_delete (f);
01562         if (extfh_ret != COB_NOT_CONFIGURED) {
01563                 return extfh_ret;
01564         }
01565 #endif  /* WITH_SEQRA_EXTFH */
01566 
01567         relnum = cob_get_int (f->keys[0].field) - 1;
01568         relsize = f->record_max + sizeof (f->record->size);
01569         off = relnum * relsize;
01570         if (fseek ((FILE *)f->file, off, SEEK_SET) != 0 ||
01571             fread (&f->record->size, sizeof (f->record->size),
01572                    1, (FILE *)f->file) != 1) {
01573                         return COB_STATUS_23_KEY_NOT_EXISTS;
01574         }
01575         fseek ((FILE *)f->file, - (off_t) sizeof (f->record->size), SEEK_CUR);
01576 
01577         f->record->size = 0;
01578         if (fwrite (&f->record->size, sizeof (f->record->size), 1, (FILE *)f->file) != 1) {
01579                 return COB_STATUS_30_PERMANENT_ERROR;
01580         }
01581         fseek ((FILE *)f->file, (off_t) f->record_max, SEEK_CUR);
01582         return COB_STATUS_00_SUCCESS;
01583 }
01584 
01585 /*
01586  * INDEXED
01587  */
01588 
01589 #if     defined(WITH_DB) || defined(WITH_INDEX_EXTFH) || defined(WITH_CISAM) || defined(WITH_DISAM) || defined(WITH_VBISAM)
01590 
01591 #ifdef  USE_DB41
01592 static void
01593 join_environment (void)
01594 {
01595         int             flags, ret;
01596 
01597         if (bdb_home == NULL) {
01598                 return;
01599         }
01600         ret = db_env_create (&bdb_env, 0);
01601         if (ret) {
01602                 cob_runtime_error ("Can't join BDB environment, env_create: %d %s\n", ret, db_strerror (ret));
01603                 cob_stop_run (1);
01604         }
01605         bdb_env->set_errfile (bdb_env, stderr);
01606 #if (DB_VERSION_MAJOR > 4) || ((DB_VERSION_MAJOR == 4) && (DB_VERSION_MINOR > 2))
01607         bdb_env->set_msgfile (bdb_env, stderr);
01608 #endif
01609         bdb_env->set_cachesize (bdb_env, 0, 2*1024*1024, 0);
01610         bdb_env->set_alloc (bdb_env, cob_malloc, realloc, free);
01611         flags = DB_CREATE | DB_INIT_MPOOL | DB_INIT_CDB;
01612         ret = bdb_env->open (bdb_env, bdb_home, flags, 0);
01613         if (ret) {
01614                 cob_runtime_error ("Can't join BDB environment, env_open: %d %s\n", ret, db_strerror (ret));
01615                 bdb_env->close (bdb_env, 0);
01616                 bdb_env = NULL;
01617                 cob_stop_run (1);
01618         }
01619 #if (DB_VERSION_MAJOR > 4) || ((DB_VERSION_MAJOR == 4) && (DB_VERSION_MINOR > 1))
01620         bdb_env->get_data_dirs (bdb_env, &bdb_data_dir);
01621 #endif
01622         bdb_env->lock_id (bdb_env, &bdb_lock_id);
01623 }
01624 
01625 static int
01626 lock_record (cob_file *f, char *key, const unsigned int keylen)
01627 {
01628         struct indexed_file     *p = f->file;
01629         size_t                  len;
01630         int                     ret;
01631         DBT                     dbt;
01632         
01633         len = keylen + p->filenamelen + 1;
01634         if (len > rlo_size) {
01635                 free (record_lock_object);
01636                 record_lock_object = cob_malloc (len);
01637                 rlo_size = len;
01638         }
01639         memcpy ((char *)record_lock_object, p->filename, (size_t)(p->filenamelen + 1));
01640         memcpy ((char *)record_lock_object + p->filenamelen + 1, key, (size_t)keylen);
01641         dbt.size = (cob_dbtsize_t) len;
01642         dbt.data = record_lock_object;
01643         ret = bdb_env->lock_get (bdb_env, p->bdb_lock_id, DB_LOCK_NOWAIT, 
01644                                 &dbt, DB_LOCK_WRITE, &p->bdb_record_lock);
01645         if (!ret) {
01646                 p->record_locked = 1;
01647         }
01648         return ret;
01649 }
01650 
01651 static int
01652 test_record_lock (cob_file *f, char *key, const unsigned int keylen)
01653 {
01654         struct indexed_file     *p = f->file;
01655         size_t                  len;
01656         int                     ret;
01657         DBT                     dbt;
01658         DB_LOCK                 test_lock;
01659         
01660         len = keylen + p->filenamelen + 1;
01661         if (len > rlo_size) {
01662                 free (record_lock_object);
01663                 record_lock_object = cob_malloc (len);
01664                 rlo_size = len;
01665         }
01666         memcpy ((char *)record_lock_object, p->filename, (size_t)(p->filenamelen + 1));
01667         memcpy ((char *)record_lock_object + p->filenamelen + 1, key, (size_t)keylen);
01668         dbt.size = (cob_dbtsize_t) len;
01669         dbt.data = record_lock_object;
01670         ret = bdb_env->lock_get (bdb_env, p->bdb_lock_id, DB_LOCK_NOWAIT, 
01671                                 &dbt, DB_LOCK_WRITE, &test_lock);
01672         if (!ret) {
01673                 bdb_env->lock_put (bdb_env, &test_lock);
01674         }
01675         return ret;
01676 }
01677 
01678 static int
01679 unlock_record (cob_file *f)
01680 {
01681         struct indexed_file     *p = f->file;
01682         int                     ret;
01683         
01684         if (p->record_locked == 0) {
01685                 return 0;
01686         }
01687         ret = bdb_env->lock_put (bdb_env, &p->bdb_record_lock);
01688         p->record_locked = 0;
01689         return ret;
01690 }
01691 #endif  /* USE_DB41 */
01692 
01693 
01694 /* OPEN the INDEXED file */
01695 
01696 static int
01697 indexed_open (cob_file *f, char *filename, const int mode, const int sharing)
01698 {
01699 #ifdef  WITH_INDEX_EXTFH
01700         return extfh_indexed_open (f, filename, mode, sharing);
01701 #elif   defined(WITH_CISAM) || defined(WITH_DISAM) || defined(WITH_VBISAM)
01702         struct indexfile        *fh;
01703         int                     ret = COB_STATUS_00_SUCCESS;
01704         int                     omode = 0;
01705         int                     lmode = 0;
01706         int                     vmode = 0;
01707         int                     dobld = 0;
01708         int                     isfd = -1;
01709         int                     k;
01710         struct dictinfo         di;                     /* defined in (c|d|vb)isam.h */
01711 
01712 #if defined(ISVARLEN)
01713         if (f->record_min != f->record_max) {
01714                 vmode = ISVARLEN;
01715                 isreclen = f->record_min;
01716         }
01717 #endif
01718         if (!f->lock_mode) {
01719                 if (mode != COB_OPEN_INPUT) {
01720                         lmode = ISEXCLLOCK;
01721                 } else {
01722                         lmode = ISMANULOCK;
01723                 }
01724         } else if ((f->lock_mode & COB_LOCK_EXCLUSIVE)) {
01725                 lmode = ISEXCLLOCK;
01726         } else if ((f->lock_mode & COB_LOCK_AUTOMATIC) && mode != COB_OPEN_INPUT) {
01727                 lmode = ISAUTOLOCK;
01728         } else {
01729                 lmode = ISMANULOCK;
01730         }
01731         switch (mode) {
01732         case COB_OPEN_INPUT:
01733                 omode = ISINPUT;
01734                 break;
01735         case COB_OPEN_OUTPUT:
01736                 lmode = ISEXCLLOCK;
01737                 omode = ISOUTPUT;
01738                 iserrno = 0;
01739                 isfd = isopen (filename, ISINPUT | ISEXCLLOCK | vmode);
01740                 if (iserrno == EFLOCKED) {
01741 #ifdef  WITH_VBISAM
01742                         isfullclose (isfd);
01743 #else
01744                         isclose (isfd);
01745 #endif
01746                         return COB_STATUS_61_FILE_SHARING;
01747                 } else {
01748                         if (isfd >= 0) {
01749 #ifdef  WITH_VBISAM
01750                                 isfullclose (isfd);
01751 #else
01752                                 isclose (isfd);
01753 #endif
01754                         }
01755                         iserase (filename);
01756                 }
01757                 iserrno = 0;
01758                 dobld = 1;
01759                 break;
01760         case COB_OPEN_I_O:
01761                 omode = ISINOUT;
01762                 break;
01763         case COB_OPEN_EXTEND:
01764                 lmode = ISEXCLLOCK;
01765                 omode = ISINOUT;
01766                 break;
01767         case COB_OPEN_LOCKED:
01768                 lmode = ISEXCLLOCK;
01769                 omode = ISINOUT;
01770                 break;
01771         }
01772         fh = cob_malloc (sizeof(struct indexfile) + ((sizeof (struct keydesc)) * (f->nkeys + 1)));
01773         /* Copy index information */
01774         for (k = 0; k < f->nkeys; k++) {
01775                 memset (&fh->key[k], 0, sizeof(struct keydesc));
01776                 fh->key[k].k_flags = f->keys[k].flag ? ISDUPS : ISNODUPS;
01777                 fh->key[k].k_nparts = 1;                /* Single field key */
01778                 fh->key[k].k_start = f->keys[k].offset;
01779                 fh->key[k].k_leng = f->keys[k].field->size;
01780                 if (fh->lenkey < fh->key[k].k_leng) {
01781                         fh->lenkey = fh->key[k].k_leng;
01782                 }
01783                 fh->key[k].k_type = CHARTYPE;
01784         }
01785         iserrno = 0;
01786         fh->lmode = 0;
01787         if (dobld) {
01788 dobuild:
01789                 isfd = isbuild (filename, f->record_max, &fh->key[0], ISINOUT | ISEXCLLOCK | vmode);
01790         } else {
01791                 if (lmode == ISAUTOLOCK) {
01792                         fh->lmode = ISLOCK;
01793                         lmode = ISMANULOCK;
01794                 }
01795                 isfd = isopen (filename, omode | lmode | vmode);
01796                 if (isfd == -1) {
01797                         if (f->flag_optional) {
01798                                 if (mode == COB_OPEN_EXTEND || mode == COB_OPEN_I_O) {
01799                                         dobld = 1;
01800                                         ret = COB_STATUS_05_SUCCESS_OPTIONAL;
01801                                         goto dobuild;
01802                                 }
01803                                 f->file = fh;
01804                                 f->open_mode = mode;
01805                                 fh->isfd = isfd;
01806                                 fh->filename = strdup (filename);
01807                                 /* Active index is unknown at this time */
01808                                 fh->curkey = -1;
01809                                 f->flag_end_of_file = 1;
01810                                 f->flag_begin_of_file = 1;
01811                                 if (f->flag_nonexistent) {
01812                                         return COB_STATUS_00_SUCCESS;
01813                                 }
01814                                 f->flag_nonexistent = 1;
01815                                 return COB_STATUS_05_SUCCESS_OPTIONAL;
01816                         }
01817                 } else {
01818                         memset(&di, 0, sizeof(di));
01819                         isindexinfo (isfd, (void *)&di, 0);
01820                         fh->nkeys = di.di_nkeys & 0x7F; /* Mask off ISVARLEN */
01821                         if (fh->nkeys > f->nkeys) {
01822                                 fh = realloc (fh, sizeof(struct indexfile) + ((sizeof (struct keydesc)) * (fh->nkeys + 1)));
01823                         }
01824                         for (k = 0; k < fh->nkeys; k++) {
01825                                 memset (&fh->key[k], 0, sizeof(struct keydesc));
01826                                 isindexinfo (isfd, &fh->key[k], k+1);
01827                                 if (fh->lenkey < fh->key[k].k_leng) {
01828                                         fh->lenkey = fh->key[k].k_leng;
01829                                 }
01830                                 /* Verify that COBOL definition matches the real ISAM file */
01831                                 if (f->keys[k].flag) {
01832                                         if (!(fh->key[k].k_flags & ISDUPS)) {
01833                                                 ret = COB_STATUS_39_CONFLICT_ATTRIBUTE;
01834                                         }
01835                                 } else {
01836                                         if (fh->key[k].k_flags & ISDUPS) {
01837                                                 ret = COB_STATUS_39_CONFLICT_ATTRIBUTE;
01838                                         }
01839                                 }
01840                                 if (fh->key[k].k_nparts != 1
01841                                 ||  fh->key[k].k_start != f->keys[k].offset
01842                                 ||  fh->key[k].k_leng != f->keys[k].field->size) {
01843                                         ret = COB_STATUS_39_CONFLICT_ATTRIBUTE;
01844                                 }
01845                         }
01846                 }
01847         }
01848         if (isfd == -1) {
01849                 ret = isretsts (COB_STATUS_35_NOT_EXISTS);
01850                 freefh (fh);
01851                 return ret;
01852         }
01853         if (ret > 9) {
01854 #ifdef  WITH_VBISAM
01855                 isfullclose (isfd);
01856 #else
01857                 isclose (isfd);
01858 #endif
01859                 freefh (fh);
01860                 return ret;
01861         }
01862         if (dobld) {
01863                 for (k = 1; k < f->nkeys; k++) {
01864                         iserrno = 0;
01865                         if (isaddindex (isfd, &fh->key[k]) == -1) {
01866                                 ret = COB_STATUS_39_CONFLICT_ATTRIBUTE;
01867                         }
01868                 }
01869                 if (ret > 9) {
01870 #ifdef  WITH_VBISAM
01871                         isfullclose (isfd);
01872 #else
01873                         isclose (isfd);
01874 #endif
01875                         iserase (filename);
01876                         freefh (fh);
01877                         return ret;
01878                 }
01879         }
01880         f->file = fh;
01881         f->open_mode = mode;
01882         fh->isfd = isfd;
01883         fh->filename = strdup (filename);
01884         fh->savekey = cob_malloc (fh->lenkey + 1);
01885         fh->recwrk = cob_malloc (f->record_max + 1);
01886         fh->curkey = -1;                /* Active index is unknown at this time */
01887         f->flag_nonexistent = 0;
01888         f->flag_end_of_file = 0;
01889         f->flag_begin_of_file = 0;
01890         return ret;
01891 #else   /* WITH_INDEX_EXTFH */
01892         size_t                  i, j;
01893 #ifdef  USE_DB41
01894         int                     flags = 0;
01895         int                     lock_mode;
01896         int                     handle_created;
01897 #else
01898         int                     flags = INITIAL_FLAGS;
01899         BTREEINFO               info;
01900 #endif
01901         int                     ret = 0;
01902         struct indexed_file     *p;
01903         size_t                  maxsize;
01904 
01905         p = cob_malloc (sizeof (struct indexed_file));
01906 #ifdef  USE_DB41
01907         if (bdb_env != NULL) {
01908                 if (mode == COB_OPEN_OUTPUT || mode == COB_OPEN_EXTEND ||
01909                     (f->lock_mode & COB_LOCK_EXCLUSIVE) ||
01910                     (mode == COB_OPEN_I_O && !f->lock_mode)) {
01911                         lock_mode = DB_LOCK_WRITE;
01912                 } else {
01913                         lock_mode = DB_LOCK_READ;
01914                 }
01915                 p->key.size = (cob_dbtsize_t) strlen (filename);
01916                 p->key.data = filename;
01917                 ret = bdb_env->lock_get (bdb_env, bdb_lock_id, DB_LOCK_NOWAIT, 
01918                                         &p->key, lock_mode, &p->bdb_file_lock);
01919                 if (ret) {
01920                         free (p);
01921                         if (ret == DB_LOCK_NOTGRANTED) {
01922                                 ret = COB_STATUS_61_FILE_SHARING;
01923                         }
01924                         return ret;
01925                 }
01926         }
01927 #endif
01928 
01929         switch (mode) {
01930         case COB_OPEN_INPUT:
01931 #ifdef  USE_DB41
01932                 flags |= DB_RDONLY;
01933 #else
01934                 flags |= O_RDONLY;
01935 #endif
01936                 break;
01937         case COB_OPEN_OUTPUT:
01938 #ifdef  USE_DB41
01939                 flags |= DB_CREATE;
01940 #else
01941                 flags |= O_RDWR | O_CREAT | O_TRUNC;
01942 #endif
01943                 break;
01944         case COB_OPEN_I_O:
01945         case COB_OPEN_EXTEND:
01946 #ifdef  USE_DB41
01947                 flags |= DB_CREATE;
01948 #else
01949                 flags |= O_RDWR | O_CREAT;
01950 #endif
01951                 break;
01952         }
01953 
01954         p->db = cob_malloc (sizeof (DB *) * f->nkeys);
01955 #ifdef  USE_DB41
01956         p->cursor = cob_malloc (sizeof (DBC *) * f->nkeys);
01957         p->filenamelen = (int) strlen (filename);
01958 #endif
01959         p->last_readkey = cob_malloc (sizeof (unsigned char *) * 2 * f->nkeys);
01960         p->last_dupno = cob_malloc (sizeof (unsigned int) * f->nkeys);
01961         p->rewrite_sec_key = cob_malloc (sizeof (int) * f->nkeys);
01962         maxsize = 0;
01963         for (i = 0; i < f->nkeys; i++) {
01964                 if (f->keys[i].field->size > maxsize) {
01965                         maxsize = f->keys[i].field->size;
01966                 }
01967         }
01968         for (i = 0; i < f->nkeys; i++) {
01969                 /* file name */
01970                 memset (runtime_buffer, 0, COB_SMALL_BUFF);
01971                 if (i == 0) {
01972                         strncpy (runtime_buffer, filename, COB_SMALL_MAX);
01973                 } else {
01974                         snprintf (runtime_buffer, COB_SMALL_MAX, "%s.%d",
01975                                  filename, (int)i);
01976                 }
01977 
01978                 /* btree info */
01979 #ifdef  USE_DB41
01980                 ret = db_create (&p->db[i], bdb_env, 0);
01981                 if (!ret) {
01982                         handle_created = 1;
01983                         if (mode == COB_OPEN_OUTPUT) {
01984                                 if (bdb_env) {
01985                                         bdb_env->dbremove (bdb_env, NULL, runtime_buffer, NULL, 0);
01986                                 } else {
01987                                         p->db[i]->remove (p->db[i], runtime_buffer, NULL, 0);
01988                                         ret = db_create (&p->db[i], bdb_env, 0);
01989                                 }
01990                         }
01991                         if (!ret) {
01992                                 if (f->keys[i].flag) {
01993                                         p->db[i]->set_flags (p->db[i], DB_DUP);
01994                                 }
01995                         }
01996                 } else {
01997                         handle_created = 0;
01998                 }
01999 #else
02000                 memset ((unsigned char *)&info, 0, sizeof (info));
02001                 if (f->keys[i].flag) {
02002                         info.flags = R_DUP;
02003                 }
02004 #endif
02005 
02006                 /* open db */
02007 #ifdef  USE_DB41
02008                 if (!ret) {
02009                         ret = p->db[i]->open (p->db[i], NULL, runtime_buffer, NULL,
02010                                                 DB_BTREE, flags, COB_FILE_MODE);
02011                 }
02012 #else
02013                 p->db[i] = dbopen (runtime_buffer, flags, COB_FILE_MODE, DB_BTREE, &info);
02014                 if (p->db[i] == 0) {
02015                         ret = errno;
02016                 }
02017 #endif
02018                 if (ret) {
02019                         for (j = 0; j < i; j++) {
02020                                 DB_CLOSE (p->db[j]);
02021                         }
02022 #ifdef  USE_DB41
02023                         if (handle_created) {
02024                                 DB_CLOSE (p->db[i]);
02025                         }
02026 #endif
02027                         free (p->db);
02028                         free (p->last_readkey);
02029                         free (p->last_dupno);
02030 #ifdef  USE_DB41
02031                         free (p->cursor);
02032                         if (bdb_env != NULL) {
02033                                 bdb_env->lock_put (bdb_env, &p->bdb_file_lock);
02034                         }
02035 #endif
02036                         free (p);
02037                         return ret;
02038 
02039                 }
02040 
02041                 p->last_readkey[i] = cob_malloc (maxsize);
02042                 p->last_readkey[f->nkeys + i] = cob_malloc (maxsize);
02043         }
02044 
02045         p->temp_key = cob_malloc (maxsize + sizeof(unsigned int));
02046         f->file = p;
02047         p->key_index = 0;
02048         p->last_key = NULL;
02049 
02050         memset ((unsigned char *)&p->key, 0, sizeof (DBT));
02051         memset ((unsigned char *)&p->data, 0, sizeof (DBT));
02052 #ifdef  USE_DB41
02053         p->filename = cob_malloc (strlen (filename) + 1);
02054         strcpy (p->filename, filename);
02055         p->write_cursor_open = 0;
02056         p->record_locked = 0;
02057         if (bdb_env != NULL) {
02058                 bdb_env->lock_id (bdb_env, &p->bdb_lock_id);
02059         }
02060 
02061         DBT_SET (p->key, f->keys[0].field);
02062         p->db[0]->cursor (p->db[0], NULL, &p->cursor[0], 0);
02063         ret = DB_SEQ (p->cursor[0], DB_FIRST);
02064         p->cursor[0]->c_close (p->cursor[0]);
02065         p->cursor[0] = NULL;
02066 #else
02067         ret = DB_SEQ (p->db[p->key_index], R_FIRST);
02068 #endif
02069         if (!ret) {
02070                 memcpy (p->last_readkey[0], p->key.data, p->key.size);
02071         } else {
02072                 p->data.data = NULL;
02073         }
02074 
02075         return 0;
02076 #endif  /* WITH_INDEX_EXTFH */
02077 }
02078 
02079 /* Close the INDEXED file */
02080 
02081 static int
02082 indexed_close (cob_file *f, const int opt)
02083 {
02084 #ifdef  WITH_INDEX_EXTFH
02085         return extfh_indexed_close (f, opt);
02086 #elif   defined(WITH_CISAM) || defined(WITH_DISAM) || defined(WITH_VBISAM)
02087         struct indexfile        *fh = f->file;
02088 
02089         if (fh == NULL) {
02090                 return COB_STATUS_00_SUCCESS;
02091         }
02092         if (fh->isfd >= 0) {
02093 #ifdef  WITH_VBISAM
02094                 isfullclose (fh->isfd);
02095 #else
02096                 isclose (fh->isfd);
02097 #endif
02098         }
02099         freefh (fh);
02100         f->file = NULL;
02101         return COB_STATUS_00_SUCCESS;
02102 #else   /* WITH_INDEX_EXTFH */
02103         struct indexed_file     *p = f->file;
02104         int                     i;
02105 
02106         /* close DB's */
02107 #ifdef  USE_DB41
02108         for (i = 0; i < (int)f->nkeys; i++) {
02109                 if (p->cursor[i]) {
02110                         p->cursor[i]->c_close (p->cursor[i]);
02111                 }
02112         }
02113 #endif
02114         for (i = f->nkeys - 1; i >= 0; i--) {
02115                 if (p->db[i]) {
02116                         DB_CLOSE (p->db[i]);
02117                 }
02118                 free (p->last_readkey[i]);
02119                 free (p->last_readkey[f->nkeys + i]);
02120         }
02121 
02122         if (p->last_key) {
02123                 free (p->last_key);
02124         }
02125         free (p->temp_key);
02126         free (p->db);
02127         free (p->last_readkey);
02128         free (p->last_dupno);
02129         free (p->rewrite_sec_key);
02130 #ifdef  USE_DB41
02131         free (p->filename);
02132         free (p->cursor);
02133         if (bdb_env != NULL) {
02134                 unlock_record (f);
02135                 bdb_env->lock_put (bdb_env, &p->bdb_file_lock);
02136                 bdb_env->lock_id_free (bdb_env, p->bdb_lock_id);
02137         }
02138 #endif
02139         free (p);
02140 
02141         return COB_STATUS_00_SUCCESS;
02142 #endif  /* WITH_INDEX_EXTFH */
02143 }
02144 
02145 #if     !defined(WITH_INDEX_EXTFH) && !defined(WITH_CISAM) && !defined(WITH_DISAM) && !defined(WITH_VBISAM)
02146 static int
02147 indexed_start_internal (cob_file *f, const int cond, cob_field *key, const int read_opts,
02148                         const int test_lock)
02149 {
02150         int                     ret;
02151         unsigned int            dupno;
02152         struct indexed_file     *p = f->file;
02153 
02154         /* look up for the key */
02155         for (p->key_index = 0; p->key_index < f->nkeys; p->key_index++) {
02156                 if (f->keys[p->key_index].field->data == key->data) {
02157                         break;
02158                 }
02159         }
02160 /* RXW - Removed
02161         if (unlikely(p->key_index == f->nkeys)) {
02162                 cob_runtime_error ("cob_start_indexed: key not found "
02163                                    "(should have been detected by cobc)");
02164                 return 99;
02165         }
02166 */
02167 
02168         /* search */
02169         DBT_SET (p->key, key);
02170 #ifdef  USE_DB41
02171         /* the open cursor makes this function atomic */
02172         if (p->key_index != 0) {
02173                 p->db[0]->cursor (p->db[0], NULL, &p->cursor[0], 0);
02174         }
02175         p->db[p->key_index]->cursor (p->db[p->key_index], NULL, &p->cursor[p->key_index], 0);
02176         ret = DB_SEQ (p->cursor[p->key_index], DB_SET_RANGE);
02177 #else
02178         ret = DB_SEQ (p->db[p->key_index], R_CURSOR);
02179 #endif
02180         switch (cond) {
02181         case COB_EQ:
02182                 if (ret == 0) {
02183                         ret = memcmp (p->key.data, key->data, key->size);
02184                 }
02185                 break;
02186         case COB_LT:
02187                 if (ret != 0) {
02188 #ifdef  USE_DB41
02189                         ret = DB_SEQ (p->cursor[p->key_index], DB_LAST);
02190 #else
02191                         ret = DB_SEQ (p->db[p->key_index], R_LAST);
02192 #endif
02193                 } else {
02194 #ifdef  USE_DB41
02195                         ret = DB_SEQ (p->cursor[p->key_index], DB_PREV);
02196 #else
02197                         ret = DB_SEQ (p->db[p->key_index], R_PREV);
02198 #endif
02199                 }
02200                 break;
02201         case COB_LE:
02202                 if (ret != 0) {
02203 #ifdef  USE_DB41
02204                         ret = DB_SEQ (p->cursor[p->key_index], DB_LAST);
02205 #else
02206                         ret = DB_SEQ (p->db[p->key_index], R_LAST);
02207 #endif
02208                 } else if (memcmp (p->key.data, key->data, key->size) != 0) {
02209 #ifdef  USE_DB41
02210                         ret = DB_SEQ (p->cursor[p->key_index], DB_PREV);
02211 #else
02212                         ret = DB_SEQ (p->db[p->key_index], R_PREV);
02213 #endif
02214                 } else if (f->keys[p->key_index].flag) {
02215 #ifdef  USE_DB41
02216                         ret = DB_SEQ (p->cursor[p->key_index], DB_NEXT_NODUP);
02217 #else
02218                         while (!ret && memcmp (p->key.data, key->data, key->size) == 0) {
02219                                 ret = DB_SEQ (p->db[p->key_index], R_NEXT);
02220                         }
02221 #endif
02222                         if (ret != 0) {
02223 #ifdef  USE_DB41
02224                                 ret = DB_SEQ (p->cursor[p->key_index], DB_LAST);
02225 #else
02226                                 ret = DB_SEQ (p->db[p->key_index], R_LAST);
02227 #endif
02228                         } else {
02229 #ifdef  USE_DB41
02230                                 ret = DB_SEQ (p->cursor[p->key_index], DB_PREV);
02231 #else
02232                                 ret = DB_SEQ (p->db[p->key_index], R_PREV);
02233 #endif
02234                         }
02235                 }
02236                 break;
02237         case COB_GT:
02238                 while (ret == 0 && memcmp (p->key.data, key->data, key->size) == 0) {
02239 #ifdef  USE_DB41
02240                         ret = DB_SEQ (p->cursor[p->key_index], DB_NEXT);
02241 #else
02242                         ret = DB_SEQ (p->db[p->key_index], R_NEXT);
02243 #endif
02244                 }
02245                 break;
02246         case COB_GE:
02247                 /* nothing */
02248                 break;
02249         }
02250 
02251         if (ret == 0 && p->key_index > 0) {
02252                 /* temporarily save alternate key */
02253                 memcpy (p->temp_key, p->key.data, f->keys[p->key_index].field->size);
02254                 if (f->keys[p->key_index].flag) {
02255                         memcpy (&dupno, (ucharptr)p->data.data + f->keys[0].field->size, sizeof(unsigned int));
02256                 }
02257                 p->key.data = p->data.data;
02258                 p->key.size = f->keys[0].field->size;
02259                 ret = DB_GET (p->db[0], 0);
02260         }
02261 
02262 #ifdef  USE_DB41
02263         if (ret == 0 && test_lock) {
02264                 if (!(read_opts & COB_READ_IGNORE_LOCK)) {
02265                         ret = test_record_lock (f, p->key.data, p->key.size);
02266                         if (ret) {
02267                                 p->cursor[p->key_index]->c_close (p->cursor[p->key_index]);
02268                                 p->cursor[p->key_index] = NULL;
02269                                 if (p->key_index != 0) {
02270                                         p->cursor[0]->c_close (p->cursor[0]);
02271                                         p->cursor[0] = NULL;
02272                                 }
02273                                 return COB_STATUS_51_RECORD_LOCKED;
02274                         }
02275                 }
02276                 if (read_opts & COB_READ_LOCK) {
02277                         ret = lock_record (f, p->key.data, p->key.size);
02278                         if (ret) {
02279                                 p->cursor[p->key_index]->c_close (p->cursor[p->key_index]);
02280                                 p->cursor[p->key_index] = NULL;
02281                                 if (p->key_index != 0) {
02282                                         p->cursor[0]->c_close (p->cursor[0]);
02283                                         p->cursor[0] = NULL;
02284                                 }
02285                                 return COB_STATUS_51_RECORD_LOCKED;
02286                         }
02287                 }
02288         }
02289 #endif
02290 
02291         if (ret == 0) {
02292                 if (p->key_index == 0) {
02293                         memcpy (p->last_readkey[0], p->key.data, f->keys[0].field->size);
02294                 } else {
02295                         memcpy (p->last_readkey[p->key_index],
02296                                     p->temp_key, f->keys[p->key_index].field->size);
02297                         memcpy (p->last_readkey[p->key_index + f->nkeys], p->key.data, f->keys[0].field->size);
02298                         if (f->keys[p->key_index].flag) {
02299                                 p->last_dupno[p->key_index] = dupno;
02300                         }
02301                 }
02302         }
02303 
02304 #ifdef  USE_DB41
02305         p->cursor[p->key_index]->c_close (p->cursor[p->key_index]);
02306         p->cursor[p->key_index] = NULL;
02307         if (p->key_index != 0) {
02308                 p->cursor[0]->c_close (p->cursor[0]);
02309                 p->cursor[0] = NULL;
02310         }
02311 #endif
02312 
02313         return (ret == 0) ? COB_STATUS_00_SUCCESS : COB_STATUS_23_KEY_NOT_EXISTS;
02314 }
02315 #endif  /* WITH_INDEX_EXTFH */
02316 
02317 /* START the INDEXED file with positioning */
02318 
02319 static int
02320 indexed_start (cob_file *f, const int cond, cob_field *key)
02321 {
02322 #ifdef  WITH_INDEX_EXTFH
02323         return extfh_indexed_start (f, cond, key);
02324 #elif   defined(WITH_CISAM) || defined(WITH_DISAM) || defined(WITH_VBISAM)
02325         struct indexfile        *fh = f->file;
02326         int                     k;
02327         int                     mode;
02328         int                     klen;
02329         int                     ret = COB_STATUS_00_SUCCESS;
02330 
02331         f->flag_read_done = 0;
02332         f->flag_first_read = 0;
02333         fh->readdone = 0;
02334         fh->eofpending = 0;
02335         fh->startiscur = 0;
02336         fh->wrkhasrec = 0;
02337         fh->keyhasdups = 0;
02338         if (f->flag_nonexistent) {
02339                 return COB_STATUS_23_KEY_NOT_EXISTS;
02340         }
02341         for (k = 0; k < f->nkeys; k++) {
02342                 if (f->keys[k].field->data == key->data) {
02343                         if (fh->key[k].k_flags & ISDUPS) {
02344                                 fh->keyhasdups = 1;
02345                         }
02346                         break;
02347                 }
02348         }
02349         /* Use size of data field; This may indicate a partial key */
02350         klen = key->size;
02351         if (klen < 1 || klen > fh->key[k].k_leng) {
02352                 klen = fh->key[k].k_leng;       /* Max key length for this index */
02353         }
02354         mode = ISGTEQ;
02355         fh->startiscur = 1;
02356         switch (cond) {
02357         case COB_EQ:
02358                 mode = ISEQUAL;
02359                 fh->readdir = ISNEXT;
02360                 break;
02361         case COB_GE:
02362                 mode = ISGTEQ;
02363                 fh->readdir = ISNEXT;
02364                 break;
02365         case COB_GT:
02366                 mode = ISGREAT;
02367                 fh->readdir = ISNEXT;
02368                 break;
02369         case COB_LE:
02370                 fh->readdir = ISPREV;
02371                 mode = ISGTEQ;
02372                 break;
02373         case COB_LT:
02374                 fh->readdir = ISPREV;
02375                 mode = ISGTEQ;
02376                 break;
02377         default:
02378                 return COB_STATUS_21_KEY_INVALID;
02379                 break;
02380         }
02381         if ((isstart (fh->isfd, &fh->key[k], klen, (void *)f->record->data, mode)) == -1) {
02382                 ret = isretsts (COB_STATUS_10_END_OF_FILE);
02383                 fh->curkey = -1;
02384                 fh->keyhasdups = 0;
02385                 fh->startcond = -1;
02386                 fh->readdir = -1;
02387                 fh->startiscur = 0;
02388         } else {
02389                 if (ret == COB_STATUS_00_SUCCESS) {
02390                         fh->startcond = cond;
02391                         memcpy (fh->savekey, f->record->data + fh->key[k].k_start, fh->key[k].k_leng);
02392                         fh->curkey = k;
02393                         f->flag_end_of_file = 0;
02394                         f->flag_begin_of_file = 0;
02395                         f->flag_first_read = 1;
02396                 } else {
02397                         fh->curkey = -1;
02398                         fh->keyhasdups = 0;
02399                         fh->startcond = -1;
02400                         fh->readdir = -1;
02401                 }
02402         }
02403         return ret;
02404 #else   /* WITH_INDEX_EXTFH */
02405         return indexed_start_internal (f, cond, key, 0, 0);
02406 #endif  /* WITH_INDEX_EXTFH */
02407 }
02408 
02409 /* Random READ of the INDEXED file  */
02410 
02411 static int
02412 indexed_read (cob_file *f, cob_field *key, const int read_opts)
02413 {
02414 #ifdef  WITH_INDEX_EXTFH
02415         return extfh_indexed_read (f, key, read_opts);
02416 #elif   defined(WITH_CISAM) || defined(WITH_DISAM) || defined(WITH_VBISAM)
02417         struct indexfile        *fh = f->file;
02418         int                     k;
02419         int                     ret = COB_STATUS_00_SUCCESS;
02420         int                     lmode = 0;
02421 
02422         fh->eofpending = 0;
02423         fh->startiscur = 0;
02424         fh->wrkhasrec = 0;
02425         if (f->flag_nonexistent) {
02426                 return COB_STATUS_23_KEY_NOT_EXISTS;
02427         }
02428         for (k = 0; k < f->nkeys; k++) {
02429                 if (f->keys[k].field->data == key->data) {
02430                         break;
02431                 }
02432         }
02433         if (fh->curkey != k) {                          /* Switch to this index */
02434                 isstart (fh->isfd, &fh->key[k], fh->key[0].k_leng, (void *)f->record->data, ISEQUAL);
02435                 fh->curkey = k;
02436                 fh->wrkhasrec = 0;
02437                 if (fh->key[k].k_flags & ISDUPS) {
02438                         fh->keyhasdups = 1;
02439                 } else {
02440                         fh->keyhasdups = 0;
02441                 }
02442         }
02443         fh->startcond = -1;
02444         if (read_opts & COB_READ_LOCK) {
02445                 lmode = ISLOCK;
02446         } else if (read_opts & COB_READ_WAIT_LOCK) {
02447                 lmode = ISLCKW;
02448         } else if ((f->lock_mode & COB_LOCK_AUTOMATIC)) {
02449                 if (f->open_mode != COB_OPEN_INPUT) {
02450                         if (!(read_opts & COB_READ_IGNORE_LOCK)) {
02451                                 lmode = ISLOCK;
02452                         }
02453                 }
02454         }
02455 #ifdef ISSKIPLOCK
02456         if (read_opts & COB_READ_IGNORE_LOCK) {
02457                 lmode = ISSKIPLOCK;
02458         }
02459 #endif
02460         iserrno = 0;
02461         if ((fh->lmode & ISLOCK) && !(f->lock_mode & COB_LOCK_MULTIPLE)) {
02462                 isrelease (fh->isfd);
02463         }
02464         switch (read_opts & 0x0F) {
02465         case COB_READ_NEXT:
02466                 fh->readdir = ISNEXT;
02467                 if (isread (fh->isfd, (void *)f->record->data, ISNEXT | lmode) == -1) {
02468                         ret = isretsts (COB_STATUS_10_END_OF_FILE);
02469                         f->flag_end_of_file = 1;
02470                 }
02471                 break;
02472         case COB_READ_PREVIOUS:
02473                 fh->readdir = ISPREV;
02474                 if (isread (fh->isfd, (void *)f->record->data, ISPREV | lmode) == -1) {
02475                         ret = isretsts (COB_STATUS_10_END_OF_FILE);
02476                         f->flag_begin_of_file = 1;
02477                 }
02478                 break;
02479         case COB_READ_FIRST:
02480                 fh->readdir = ISNEXT;
02481                 if (isread (fh->isfd, (void *)f->record->data, ISFIRST | lmode) == -1) {
02482                         ret = isretsts (COB_STATUS_10_END_OF_FILE);
02483                 }
02484                 break;
02485         case COB_READ_LAST:
02486                 fh->readdir = ISPREV;
02487                 if (isread (fh->isfd, (void *)f->record->data, ISLAST | lmode) == -1) {
02488                         ret = isretsts (COB_STATUS_10_END_OF_FILE);
02489                 }
02490                 break;
02491         default:
02492                 fh->readdir = -1;
02493                 if (isread (fh->isfd, (void *)f->record->data, ISEQUAL | lmode) == -1) {
02494                         ret = isretsts (COB_STATUS_21_KEY_INVALID);
02495                 }
02496                 break;
02497         }
02498         if (ret == 0) {
02499                 f->flag_first_read = 0;
02500                 f->flag_read_done = 1;
02501                 fh->readdone = 1;
02502                 f->flag_end_of_file = 0;
02503                 f->flag_begin_of_file = 0;
02504                 memcpy (fh->savekey, f->record->data + fh->key[0].k_start, fh->key[0].k_leng);
02505                 fh->recnum = isrecnum;
02506 #if defined(ISVARLEN)
02507                 if (f->record_min != f->record_max) {
02508                         f->record->size = isreclen;
02509                 }
02510 #endif
02511         } else {
02512                 memset (fh->savekey, 0, fh->key[0].k_leng);
02513                 fh->recnum = 0;
02514                 fh->readdone = 0;
02515         }
02516         return ret;
02517 #else   /* WITH_INDEX_EXTFH */
02518         struct indexed_file     *p = f->file;
02519         int                     ret;
02520         int                     test_lock = 0;
02521 
02522 #ifdef  USE_DB41
02523         if (bdb_env != NULL) {
02524                 unlock_record (f);
02525                 test_lock = 1;
02526         }
02527 #endif
02528 
02529         ret = indexed_start_internal (f, COB_EQ, key, read_opts, test_lock);
02530         if (ret != COB_STATUS_00_SUCCESS) {
02531                 return ret;
02532         }
02533 
02534         f->record->size = p->data.size;
02535         memcpy (f->record->data, p->data.data, p->data.size);
02536 
02537         return COB_STATUS_00_SUCCESS;
02538 #endif  /* WITH_INDEX_EXTFH */
02539 }
02540 
02541 /* Sequential READ of the INDEXED file */
02542 
02543 static int
02544 indexed_read_next (cob_file *f, const int read_opts)
02545 {
02546 #ifdef  WITH_INDEX_EXTFH
02547         return extfh_indexed_read_next (f, read_opts);
02548 #elif   defined(WITH_CISAM) || defined(WITH_DISAM) || defined(WITH_VBISAM)
02549         struct indexfile        *fh = f->file;
02550         int                     ret = COB_STATUS_00_SUCCESS;
02551         int                     lmode = 0;
02552         int                     domoveback;
02553 
02554         if (f->flag_nonexistent) {
02555                 if (f->flag_first_read == 0) {
02556                         return COB_STATUS_23_KEY_NOT_EXISTS;
02557                 }
02558                 f->flag_first_read = 0; 
02559                 return COB_STATUS_10_END_OF_FILE;
02560         }
02561 
02562         if (fh->curkey == -1) {                         /* Switch to this index */
02563                 isstart (fh->isfd, &fh->key[0], 0, (void *)f->record->data, ISFIRST);
02564                 fh->curkey = 0;
02565                 fh->readdir = ISNEXT;
02566                 fh->startcond = -1;
02567                 fh->startiscur = 0;
02568                 fh->wrkhasrec = 0;
02569                 fh->keyhasdups = 0;
02570         }
02571         if (read_opts & COB_READ_LOCK) {
02572                 lmode = ISLOCK;
02573         } else if (read_opts & COB_READ_WAIT_LOCK) {
02574                 lmode = ISLCKW;
02575         } else if ((f->lock_mode & COB_LOCK_AUTOMATIC) && f->open_mode != COB_OPEN_INPUT) {
02576                 if (!(read_opts & COB_READ_IGNORE_LOCK)) {
02577                         lmode = ISLOCK;
02578                 }
02579         }
02580 #ifdef ISSKIPLOCK
02581         if (read_opts & COB_READ_IGNORE_LOCK) {
02582                 lmode |= ISSKIPLOCK;
02583         }
02584 #endif
02585         if ((fh->lmode & ISLOCK) && !(f->lock_mode & COB_LOCK_MULTIPLE)) {
02586                 isrelease (fh->isfd);
02587         }
02588         iserrno = 0;
02589         switch (read_opts & 0x0F) {
02590         case COB_READ_NEXT:
02591                 fh->readdir = ISNEXT;
02592                 if (fh->eofpending == ISNEXT) {
02593                         fh->eofpending = 0;
02594                         fh->wrkhasrec = 0;
02595                         return COB_STATUS_10_END_OF_FILE;
02596                 }
02597                 if (fh->startiscur) {
02598                         if (isread (fh->isfd, (void *)f->record->data, ISCURR) == -1) {
02599                                 ret = isretsts (COB_STATUS_10_END_OF_FILE);
02600                         } else {
02601                                 switch (fh->startcond) {
02602                                 case COB_GE:
02603                                         domoveback = 0;
02604                                         while (iserrno == 0
02605                                         && memcmp (f->record->data + fh->key[fh->curkey].k_start, fh->savekey, fh->key[fh->curkey].k_leng) == 0) {
02606                                                 isread (fh->isfd, (void *)f->record->data, ISPREV);
02607                                                 domoveback = 1;
02608                                         }
02609                                         if (domoveback) {
02610                                                 isread (fh->isfd, (void *)f->record->data, iserrno == 0 ? ISNEXT : ISFIRST);
02611                                         }
02612                                         break;
02613                                 case COB_LE:
02614                                         domoveback = 0;
02615                                         while (iserrno == 0
02616                                         && memcmp (f->record->data + fh->key[fh->curkey].k_start, fh->savekey, fh->key[fh->curkey].k_leng) == 0) {
02617                                                 isread (fh->isfd, (void *)f->record->data, ISNEXT);
02618                                                 domoveback = 1;
02619                                         }
02620                                         if (domoveback) {
02621                                                 isread (fh->isfd, (void *)f->record->data, iserrno == 0 ? ISPREV : ISLAST);
02622                                         }
02623                                         break;
02624                                 case COB_LT:
02625                                         while (iserrno == 0
02626                                         && memcmp (f->record->data + fh->key[fh->curkey].k_start, fh->savekey, fh->key[fh->curkey].k_leng) >= 0) {
02627                                                 isread (fh->isfd, (void *)f->record->data, ISPREV);
02628                                         }
02629                                         break;
02630                                 case COB_GT:
02631                                         while (iserrno == 0
02632                                         && memcmp (f->record->data + fh->key[fh->curkey].k_start, fh->savekey, fh->key[fh->curkey].k_leng)<=0) {
02633                                                 isread (fh->isfd, (void *)f->record->data, ISNEXT);
02634                                         }
02635                                         break;
02636                                 }
02637                                 if (isread (fh->isfd, (void *)f->record->data, ISCURR | lmode) == -1) {
02638                                         ret = isretsts (COB_STATUS_10_END_OF_FILE);
02639                                 }
02640                         }
02641                         fh->startcond = -1;
02642                         fh->startiscur = 0;
02643                 } else if (fh->wrkhasrec == ISNEXT) {
02644                         memcpy (f->record->data, fh->recwrk, f->record_max);
02645                         if (fh->lmode & ISLOCK) {
02646                                 /* now lock 'peek ahead' record */
02647                                 if (isread (fh->isfd, (void *)f->record->data,
02648                                     ISCURR | fh->lmode) == -1) {
02649                                         ret = isretsts (COB_STATUS_10_END_OF_FILE);
02650                                 }
02651                         }
02652                 } else {
02653                         if (fh->wrkhasrec == ISPREV) {
02654                                 isread (fh->isfd, (void *)f->record->data, ISNEXT);
02655                                 fh->wrkhasrec = 0;
02656                         }
02657                         if (isread (fh->isfd, (void *)f->record->data, ISNEXT | lmode) == -1) {
02658                                 ret = isretsts (COB_STATUS_10_END_OF_FILE);
02659                         }
02660                 }
02661                 break;
02662         case COB_READ_PREVIOUS:
02663                 fh->readdir = ISPREV;
02664                 if (fh->eofpending == ISPREV) {
02665                         fh->eofpending = 0;
02666                         fh->wrkhasrec = 0;
02667                         return COB_STATUS_10_END_OF_FILE;
02668                 }
02669                 if (fh->startiscur) {
02670                         if (isread (fh->isfd, (void *)f->record->data, ISCURR | lmode) == -1) {
02671                                 ret = isretsts (COB_STATUS_10_END_OF_FILE);
02672                         } else {
02673                                 switch (fh->startcond) {
02674                                 case COB_LE:
02675                                         domoveback = 0;
02676                                         while (iserrno == 0
02677                                         && memcmp (f->record->data + fh->key[fh->curkey].k_start, fh->savekey, fh->key[fh->curkey].k_leng) == 0) {
02678                                                 isread (fh->isfd, (void *)f->record->data, ISNEXT);
02679                                                 domoveback = 1;
02680                                         }
02681                                         if (domoveback) {
02682                                                 isread (fh->isfd, (void *)f->record->data, ISPREV);
02683                                         }
02684                                         break;
02685                                 case COB_LT:
02686                                         while (iserrno == 0
02687                                         && memcmp (f->record->data + fh->key[fh->curkey].k_start, fh->savekey, fh->key[fh->curkey].k_leng) >= 0) {
02688                                                 isread (fh->isfd, (void *)f->record->data, ISPREV);
02689                                         }
02690                                         break;
02691                                 case COB_GT:
02692                                         while (iserrno == 0
02693                                         && memcmp (f->record->data + fh->key[fh->curkey].k_start, fh->savekey, fh->key[fh->curkey].k_leng) <= 0) {
02694                                                 isread (fh->isfd, (void *)f->record->data, ISNEXT);
02695                                         }
02696                                         break;
02697                                 case COB_GE:
02698                                         while (iserrno == 0
02699                                         && memcmp (f->record->data + fh->key[fh->curkey].k_start, fh->savekey, fh->key[fh->curkey].k_leng) < 0) {
02700                                                 isread (fh->isfd, (void *)f->record->data, ISNEXT);
02701                                         }
02702                                         break;
02703                                 }
02704                                 if (isread (fh->isfd, (void *)f->record->data, ISCURR | lmode) == -1) {
02705                                         ret = isretsts (COB_STATUS_10_END_OF_FILE);
02706                                 }
02707                         }
02708                         fh->startcond = -1;
02709                         fh->startiscur = 0;
02710                 } else if (fh->wrkhasrec == ISPREV) {
02711                         memcpy (f->record->data, fh->recwrk, f->record_max);
02712                         if (fh->lmode & ISLOCK) {
02713                                 /* now lock 'peek ahead' record */
02714                                 if (isread (fh->isfd, (void *)f->record->data,
02715                                     ISCURR | fh->lmode) == -1) {
02716                                         ret = isretsts (COB_STATUS_10_END_OF_FILE);
02717                                 }
02718                         }
02719                 } else {
02720                         if (fh->wrkhasrec == ISNEXT) {
02721                                 isread (fh->isfd, (void *)f->record->data, ISPREV);
02722                                 fh->wrkhasrec = 0;
02723                         }
02724                         if (isread (fh->isfd, (void *)f->record->data, ISPREV | lmode) == -1) {
02725                                 ret = isretsts (COB_STATUS_10_END_OF_FILE);
02726                         }
02727                 }
02728                 break;
02729         case COB_READ_FIRST:
02730                 fh->readdir = ISNEXT;
02731                 if (isread (fh->isfd, (void *)f->record->data, ISFIRST | lmode) == -1) {
02732                         ret = isretsts (COB_STATUS_10_END_OF_FILE);
02733                 }
02734                 break;
02735         case COB_READ_LAST:
02736                 fh->readdir = ISPREV;
02737                 if (isread (fh->isfd, (void *)f->record->data, ISLAST | lmode) == -1) {
02738                         ret = isretsts (COB_STATUS_10_END_OF_FILE);
02739                 }
02740                 break;
02741         default:
02742                 fh->readdir = ISNEXT;
02743                 if (isread (fh->isfd, (void *)f->record->data, ISNEXT | lmode) == -1) {
02744                         ret = isretsts (COB_STATUS_10_END_OF_FILE);
02745                 }
02746                 break;
02747         }
02748         if (ret == 0) {
02749                 fh->eofpending = 0;
02750                 f->flag_first_read = 0;
02751                 f->flag_read_done = 1;
02752                 fh->readdone = 1;
02753                 f->flag_end_of_file = 0;
02754                 f->flag_begin_of_file = 0;
02755                 memcpy (fh->savekey, f->record->data + fh->key[0].k_start, fh->key[0].k_leng);
02756                 fh->recnum = isrecnum;
02757 #if defined(ISVARLEN)
02758                 if (f->record_min != f->record_max) {
02759                         f->record->size = isreclen;
02760                 }
02761 #endif
02762 #if defined(WITH_COBSTATUS02) 
02763                 if (fh->keyhasdups) {
02764                         if (isread (fh->isfd, (void *)fh->recwrk, fh->readdir) == -1) {
02765                                 fh->eofpending = fh->readdir;
02766                                 fh->wrkhasrec = 0;
02767                                 fh->saverecnum = -1;
02768                         } else {
02769                                 fh->wrkhasrec = fh->readdir;
02770                                 fh->saverecnum = isrecnum;
02771                                 if (memcmp (f->record->data + fh->key[fh->curkey].k_start, 
02772                                     fh->recwrk + fh->key[fh->curkey].k_start,
02773                                     fh->key[fh->curkey].k_leng) == 0) {
02774                                         ret = COB_STATUS_02_SUCCESS_DUPLICATE;
02775                                 }
02776                         }
02777                 }
02778 #elif defined(WITH_DISAM)
02779                 if((isstat1 == '0') && (isstat2 == '2')) {
02780                         ret = COB_STATUS_02_SUCCESS_DUPLICATE;
02781                 }
02782 #endif
02783         } else {
02784                 memset (fh->savekey, 0, fh->key[0].k_leng);
02785                 fh->recnum = 0;
02786                 fh->readdone = 0;
02787                 fh->wrkhasrec = 0;
02788         }
02789         return ret;
02790 #else   /* WITH_INDEX_EXTFH */
02791         struct indexed_file     *p = f->file;
02792         int                     ret;
02793         int                     read_nextprev;
02794         int                     nextprev = DB_NEXT;
02795         int                     file_changed = 0;
02796         unsigned int            dupno;
02797 
02798 #ifdef  USE_DB41
02799         if (bdb_env != NULL) {
02800                 unlock_record (f);
02801         }
02802 #endif
02803 
02804         if (unlikely(read_opts & COB_READ_PREVIOUS)) {
02805                 if (f->flag_end_of_file) {
02806                         nextprev = DB_LAST;
02807                 } else {
02808                         nextprev = DB_PREV;
02809                 }
02810         } else if (f->flag_begin_of_file) {
02811                 nextprev = DB_FIRST;
02812         }
02813 #ifdef  USE_DB41
02814         /* the open cursor makes this function atomic */
02815         if (p->key_index != 0) {
02816                 p->db[0]->cursor (p->db[0], NULL, &p->cursor[0], 0);
02817         }
02818         p->db[p->key_index]->cursor (p->db[p->key_index], NULL, &p->cursor[p->key_index], 0);
02819 #endif
02820 
02821         if (f->flag_first_read) {
02822                 /* data is read in indexed_open or indexed_start */
02823                 if (p->data.data == NULL || (f->flag_first_read == 2 &&
02824                     nextprev == DB_PREV)) {
02825 #ifdef  USE_DB41
02826                         p->cursor[p->key_index]->c_close (p->cursor[p->key_index]);
02827                         p->cursor[p->key_index] = NULL;
02828                         if (p->key_index != 0) {
02829                                 p->cursor[0]->c_close (p->cursor[0]);
02830                                 p->cursor[0] = NULL;
02831                         }
02832 #endif
02833                         return COB_STATUS_10_END_OF_FILE;
02834                 }
02835                 /* check if previously read data still exists */
02836                 p->key.size = (cob_dbtsize_t) f->keys[p->key_index].field->size;
02837                 p->key.data = p->last_readkey[p->key_index];
02838 #ifdef  USE_DB41
02839                 ret = DB_SEQ (p->cursor[p->key_index], DB_SET);
02840 #else
02841                 ret = DB_GET (p->db[p->key_index], 0);
02842 #endif
02843                 if (!ret && p->key_index > 0) {
02844                         if (f->keys[p->key_index].flag) {
02845                                 memcpy (&dupno, (ucharptr)p->data.data + f->keys[0].field->size, sizeof(unsigned int));
02846                                 while (ret == 0 &&
02847                                       memcmp (p->key.data, p->last_readkey[p->key_index], p->key.size) == 0 &&
02848                                       dupno < p->last_dupno[p->key_index]) {
02849 #ifdef  USE_DB41
02850                                         ret = DB_SEQ (p->cursor[p->key_index], DB_NEXT);
02851 #else
02852                                         ret = DB_SEQ (p->db[p->key_index], R_NEXT); 
02853 #endif
02854                                         memcpy (&dupno, (ucharptr)p->data.data + f->keys[0].field->size, sizeof(unsigned int));
02855                                 }
02856                                 if (ret == 0 &&
02857                                    memcmp (p->key.data, p->last_readkey[p->key_index], p->key.size) == 0 &&
02858                                    dupno == p->last_dupno[p->key_index]) {
02859                                         ret = memcmp (p->last_readkey[p->key_index + f->nkeys], p->data.data, f->keys[0].field->size);
02860                                 } else {
02861                                         ret = 1;
02862                                 }
02863                         } else {
02864                                 ret = memcmp (p->last_readkey[p->key_index + f->nkeys], p->data.data, f->keys[0].field->size);
02865                         }
02866                         if (!ret) {
02867                                 p->key.size = (cob_dbtsize_t) f->keys[0].field->size;
02868                                 p->key.data = p->last_readkey[p->key_index + f->nkeys];
02869                                 ret = DB_GET (p->db[0], 0);
02870                         }
02871                 }
02872                 file_changed = ret;     
02873 #ifdef  USE_DB41
02874                 if (bdb_env != NULL && !file_changed) {
02875                         if (!(read_opts & COB_READ_IGNORE_LOCK)) {
02876                                 ret = test_record_lock (f, p->key.data, p->key.size);
02877                                 if (ret) {
02878                                         p->cursor[p->key_index]->c_close (p->cursor[p->key_index]);
02879                                         p->cursor[p->key_index] = NULL;
02880                                         if (p->key_index != 0) {
02881                                                 p->cursor[0]->c_close (p->cursor[0]);
02882                                                 p->cursor[0] = NULL;
02883                                         }
02884                                         return COB_STATUS_51_RECORD_LOCKED;
02885                                 }
02886                         }
02887                         if (read_opts & COB_READ_LOCK) {
02888                                 ret = lock_record (f, p->key.data, p->key.size);
02889                                 if (ret) {
02890                                         p->cursor[p->key_index]->c_close (p->cursor[p->key_index]);
02891                                         p->cursor[p->key_index] = NULL;
02892                                         if (p->key_index != 0) {
02893                                                 p->cursor[0]->c_close (p->cursor[0]);
02894                                                 p->cursor[0] = NULL;
02895                                         }
02896                                         return COB_STATUS_51_RECORD_LOCKED;
02897                                 }
02898                         }
02899                 }
02900 #endif
02901         }
02902         if (!f->flag_first_read || file_changed) {
02903                 if (nextprev == DB_FIRST || nextprev == DB_LAST) {
02904                         read_nextprev = 1;
02905                 } else {
02906                         p->key.size = (cob_dbtsize_t) f->keys[p->key_index].field->size;
02907                         p->key.data = p->last_readkey[p->key_index];
02908 #ifdef  USE_DB41
02909                         ret = DB_SEQ (p->cursor[p->key_index], DB_SET_RANGE); 
02910 #else
02911                         ret = DB_SEQ (p->db[p->key_index], R_CURSOR); 
02912 #endif
02913                         /* ret != 0 possible, records may be deleted since last read */
02914                         if (ret != 0) {
02915                                 if (nextprev == DB_PREV) {
02916                                         nextprev = DB_LAST;
02917                                         read_nextprev = 1;
02918                                 } else {
02919 #ifdef  USE_DB41
02920                                         p->cursor[p->key_index]->c_close (p->cursor[p->key_index]);
02921                                         p->cursor[p->key_index] = NULL;
02922                                         if (p->key_index != 0) {
02923                                                 p->cursor[0]->c_close (p->cursor[0]);
02924                                                 p->cursor[0] = NULL;
02925                                         }
02926 #endif
02927                                         return COB_STATUS_10_END_OF_FILE;
02928                                 }
02929                         } else {
02930                                 if (memcmp (p->key.data, p->last_readkey[p->key_index], p->key.size) == 0) {
02931                                         if (p->key_index > 0 && f->keys[p->key_index].flag) {
02932                                                 memcpy (&dupno, (ucharptr)p->data.data + f->keys[0].field->size, sizeof(unsigned int));
02933                                                 while (ret == 0 &&
02934                                                 memcmp (p->key.data, p->last_readkey[p->key_index], p->key.size) == 0 &&
02935                                                 dupno < p->last_dupno[p->key_index]) {
02936 #ifdef  USE_DB41
02937                                                         ret = DB_SEQ (p->cursor[p->key_index], DB_NEXT);
02938 #else
02939                                                         ret = DB_SEQ (p->db[p->key_index], R_NEXT); 
02940 #endif
02941                                                         memcpy (&dupno, (ucharptr)p->data.data + f->keys[0].field->size, sizeof(unsigned int));
02942                                                 }
02943                                                 if (ret != 0) {
02944                                                         if (nextprev == DB_PREV) {
02945                                                                 nextprev = DB_LAST;
02946                                                                 read_nextprev = 1;
02947                                                         } else {
02948 #ifdef  USE_DB41
02949                                                                 p->cursor[p->key_index]->c_close (p->cursor[p->key_index]);
02950                                                                 p->cursor[p->key_index] = NULL;
02951                                                                 if (p->key_index != 0) {
02952                                                                         p->cursor[0]->c_close (p->cursor[0]);
02953                                                                         p->cursor[0] = NULL;
02954                                                                 }
02955 #endif
02956                                                                 return COB_STATUS_10_END_OF_FILE;
02957                                                         }
02958                                                 } else {
02959                                                         if (memcmp (p->key.data, p->last_readkey[p->key_index], p->key.size) == 0 &&
02960                                                                 dupno == p->last_dupno[p->key_index]) {
02961                                                                 read_nextprev = 1;
02962                                                         } else {
02963                                                                 if (nextprev == DB_PREV) {
02964                                                                         read_nextprev = 1;
02965                                                                 } else {
02966                                                                         read_nextprev = 0;
02967                                                                 }
02968                                                         }
02969                                                 }
02970                                         } else {
02971                                                 read_nextprev = 1;
02972                                         }
02973                                 } else {
02974                                         if (nextprev == DB_PREV) {
02975                                                 read_nextprev = 1;
02976                                         } else {
02977                                                 read_nextprev = 0;
02978                                         }
02979                                 }
02980                         }
02981                 }
02982                 if (read_nextprev) {
02983 #ifdef  USE_DB41
02984                         ret = DB_SEQ (p->cursor[p->key_index], nextprev);
02985 #else
02986                         ret = DB_SEQ (p->db[p->key_index], nextprev);
02987 #endif
02988                         if (ret != 0) {
02989 #ifdef  USE_DB41
02990                                 p->cursor[p->key_index]->c_close (p->cursor[p->key_index]);
02991                                 p->cursor[p->key_index] = NULL;
02992                                 if (p->key_index != 0) {
02993                                         p->cursor[0]->c_close (p->cursor[0]);
02994                                         p->cursor[0] = NULL;
02995                                 }
02996 #endif
02997                                 return COB_STATUS_10_END_OF_FILE;
02998                         }
02999                 }
03000 
03001                 if (p->key_index > 0) {
03002                         /* temporarily save alternate key */
03003                         memcpy (p->temp_key, p->key.data, p->key.size);
03004                         if (f->keys[p->key_index].flag) {
03005                                 memcpy (&dupno, (ucharptr)p->data.data + f->keys[0].field->size, sizeof(unsigned int));
03006                         }
03007                         p->key.data = p->data.data;
03008                         p->key.size = f->keys[0].field->size;
03009                         if (DB_GET (p->db[0], 0) != 0) {
03010 #ifdef  USE_DB41
03011                                 p->cursor[p->key_index]->c_close (p->cursor[p->key_index]);
03012                                 p->cursor[p->key_index] = NULL;
03013                                 p->cursor[0]->c_close (p->cursor[0]);
03014                                 p->cursor[0] = NULL;
03015 #endif
03016                                 return COB_STATUS_23_KEY_NOT_EXISTS;
03017                         }
03018                 }
03019 #ifdef  USE_DB41
03020                 if (bdb_env != NULL) {
03021                         if (!(read_opts & COB_READ_IGNORE_LOCK)) {
03022                                 ret = test_record_lock (f, p->key.data, p->key.size);
03023                                 if (ret) {
03024                                         p->cursor[p->key_index]->c_close (p->cursor[p->key_index]);
03025                                         p->cursor[p->key_index] = NULL;
03026                                         if (p->key_index != 0) {
03027                                                 p->cursor[0]->c_close (p->cursor[0]);
03028                                                 p->cursor[0] = NULL;
03029                                         }
03030                                         return COB_STATUS_51_RECORD_LOCKED;
03031                                 }
03032                         }
03033                         if (read_opts & COB_READ_LOCK) {
03034                                 ret = lock_record (f, p->key.data, p->key.size);
03035                                 if (ret) {
03036                                         p->cursor[p->key_index]->c_close (p->cursor[p->key_index]);
03037                                         p->cursor[p->key_index] = NULL;
03038                                         if (p->key_index != 0) {
03039                                                 p->cursor[0]->c_close (p->cursor[0]);
03040                                                 p->cursor[0] = NULL;
03041                                         }
03042                                         return COB_STATUS_51_RECORD_LOCKED;
03043                                 }
03044                         }
03045                 }
03046 #endif
03047                 if (p->key_index == 0) {
03048                         memcpy (p->last_readkey[0], p->key.data, p->key.size);
03049                 } else {
03050                         memcpy (p->last_readkey[p->key_index], p->temp_key,
03051                                     f->keys[p->key_index].field->size);
03052                         memcpy (p->last_readkey[p->key_index + f->nkeys], p->key.data, f->keys[0].field->size);
03053                         if (f->keys[p->key_index].flag) {
03054                                 p->last_dupno[p->key_index] = dupno;
03055                         }
03056                 }
03057         }
03058 
03059 #ifdef  USE_DB41
03060         p->cursor[p->key_index]->c_close (p->cursor[p->key_index]);
03061         p->cursor[p->key_index] = NULL;
03062         if (p->key_index != 0) {
03063                 p->cursor[0]->c_close (p->cursor[0]);
03064                 p->cursor[0] = NULL;
03065         }
03066 #endif
03067 
03068         f->record->size = p->data.size;
03069         memcpy (f->record->data, p->data.data, p->data.size);
03070 
03071         return COB_STATUS_00_SUCCESS;
03072 #endif  /* WITH_INDEX_EXTFH */
03073 }
03074 
03075 #if     !defined(WITH_INDEX_EXTFH) && !defined(WITH_CISAM) && !defined(WITH_DISAM) && !defined(WITH_VBISAM)
03076 /* get the next number in a set of duplicates */
03077 static unsigned int
03078 get_dupno (cob_file *f, const int i)
03079 {
03080         int                     ret;
03081         unsigned int            dupno =  0;
03082         struct indexed_file     *p = f->file;
03083 
03084         DBT_SET (p->key, f->keys[i].field);
03085         memcpy (p->temp_key, p->key.data, p->key.size);
03086 #ifdef  USE_DB41
03087         p->db[i]->cursor (p->db[i], NULL, &p->cursor[i], 0);
03088         ret = DB_SEQ (p->cursor[i], DB_SET_RANGE); 
03089 #else
03090         ret = DB_SEQ (p->db[i], R_CURSOR); 
03091 #endif
03092         while (ret == 0 && memcmp (p->key.data, p->temp_key, p->key.size) == 0) {
03093                 memcpy (&dupno, (ucharptr)p->data.data + f->keys[0].field->size, sizeof(unsigned int));
03094 #ifdef  USE_DB41
03095                 ret = DB_SEQ (p->cursor[i], DB_NEXT); 
03096 #else
03097                 ret = DB_SEQ (p->db[i], R_NEXT); 
03098 #endif
03099         }
03100 #ifdef  USE_DB41
03101         p->cursor[i]->c_close (p->cursor[i]);
03102         p->cursor[i] = NULL;
03103 #endif
03104         return ++dupno;
03105 }
03106 
03107 static int
03108 check_alt_keys (cob_file *f, const int rewrite)
03109 {
03110         size_t          i;
03111         int                     ret;
03112         struct indexed_file     *p = f->file;
03113 
03114         for (i = 1; i < f->nkeys; i++) {
03115                 if (!f->keys[i].flag) {
03116                         DBT_SET (p->key, f->keys[i].field);
03117                         ret = DB_GET (p->db[i], 0);
03118                         if (ret == 0) {
03119                                 if (rewrite) {
03120                                         if (memcmp (p->data.data, f->keys[0].field->data, f->keys[0].field->size)) {
03121                                                 return 1;
03122                                         }
03123                                 } else {
03124                                         return 1;
03125                                 }
03126                         }
03127                 }
03128         }
03129         return 0;
03130 }
03131 
03132 static int
03133 indexed_write_internal (cob_file *f, const int rewrite, const int opt)
03134 {
03135         size_t                  i;
03136         struct indexed_file     *p = f->file;
03137         int                     flags;
03138         unsigned int            dupno;
03139 #ifdef  USE_DB41
03140         int                     close_cursor;
03141 
03142         if (bdb_env) {
03143                 flags = DB_WRITECURSOR;
03144         } else {
03145                 flags = 0;
03146         }
03147         if (p->write_cursor_open) {
03148                 close_cursor = 0;
03149         } else {
03150                 p->db[0]->cursor (p->db[0], NULL, &p->cursor[0], flags);
03151                 p->write_cursor_open = 1; 
03152                 close_cursor = 1;
03153         }
03154 #endif
03155 
03156         /* check duplicate alternate keys */
03157         if (f->nkeys > 1 && !rewrite) {
03158                 if (check_alt_keys (f, 0)) {
03159 #ifdef  USE_DB41
03160                         if (close_cursor) {
03161                                 p->cursor[0]->c_close (p->cursor[0]);
03162                                 p->cursor[0] = NULL;
03163                                 p->write_cursor_open = 0; 
03164                         }
03165 #endif
03166                         return COB_STATUS_22_KEY_EXISTS;
03167                 }
03168                 DBT_SET (p->key, f->keys[0].field);
03169         }
03170 
03171         /* write data */
03172 #ifdef  USE_DB41
03173         if (p->cursor[0]->c_get (p->cursor[0], &p->key, &p->data, DB_SET) == 0) {
03174                 if (close_cursor) {
03175                         p->cursor[0]->c_close (p->cursor[0]);
03176                         p->cursor[0] = NULL;
03177                         p->write_cursor_open = 0; 
03178                 }
03179                 return COB_STATUS_22_KEY_EXISTS;
03180         }
03181         p->data.data = f->record->data;
03182         p->data.size = (cob_dbtsize_t) f->record->size;
03183         p->cursor[0]->c_put (p->cursor[0], &p->key, &p->data, DB_KEYFIRST);
03184 #else
03185         p->data.data = f->record->data;
03186         p->data.size = (cob_dbtsize_t) f->record->size;
03187         if (DB_PUT (p->db[0], R_NOOVERWRITE) != 0) {
03188                 return COB_STATUS_22_KEY_EXISTS;
03189         }
03190 #endif
03191 
03192         /* write secondary keys */
03193         p->data = p->key;
03194         for (i = 1; i < f->nkeys; i++) {
03195                 if (rewrite && ! p->rewrite_sec_key[i]) {
03196                         continue;
03197                 }
03198                 if (f->keys[i].flag) {
03199                         flags =  0;
03200                         dupno = get_dupno(f, i);
03201                         memcpy (p->temp_key, f->keys[0].field->data,
03202                                    f->keys[0].field->size);
03203                         memcpy (p->temp_key + f->keys[0].field->size, &dupno,
03204                                    sizeof(unsigned int));
03205                         p->data.data = p->temp_key;
03206                         p->data.size = f->keys[0].field->size + sizeof(unsigned int);;
03207                 } else {
03208 #ifdef  USE_DB41
03209                         flags = DB_NOOVERWRITE;
03210 #else
03211                         flags =  R_NOOVERWRITE;
03212 #endif
03213                 }
03214 
03215                 DBT_SET (p->key, f->keys[i].field);
03216                 if (DB_PUT (p->db[i], flags) != 0) {
03217 #ifdef  USE_DB41
03218                         if (close_cursor) {
03219                                 p->cursor[0]->c_close (p->cursor[0]);
03220                                 p->cursor[0] = NULL;
03221                                 p->write_cursor_open = 0; 
03222                         }
03223 #endif
03224                         return COB_STATUS_22_KEY_EXISTS;
03225                 }
03226         }
03227 
03228 #ifdef  USE_DB41
03229         if (opt & COB_WRITE_LOCK) {
03230                 if (bdb_env != NULL) {
03231                         DBT_SET (p->key, f->keys[0].field);
03232                         if (lock_record (f, p->key.data, p->key.size)) {
03233                                 if (close_cursor) {
03234                                         p->cursor[0]->c_close (p->cursor[0]);
03235                                         p->cursor[0] = NULL;
03236                                         p->write_cursor_open = 0; 
03237                                 }
03238                                 return COB_STATUS_51_RECORD_LOCKED;
03239                         }
03240                 }
03241         }
03242         if (close_cursor) {
03243                 p->cursor[0]->c_close (p->cursor[0]);
03244                 p->cursor[0] = NULL;
03245                 p->write_cursor_open = 0; 
03246         }
03247 #endif
03248         return COB_STATUS_00_SUCCESS;
03249 }
03250 #endif  /* WITH_INDEX_EXTFH */
03251 
03252 /* WRITE to the INDEXED file  */
03253 
03254 static int
03255 indexed_write (cob_file *f, const int opt)
03256 {
03257 #ifdef  WITH_INDEX_EXTFH
03258         return extfh_indexed_write (f, opt);
03259 #elif   defined(WITH_CISAM) || defined(WITH_DISAM) || defined(WITH_VBISAM)
03260         struct indexfile        *fh = f->file;
03261         int                     ret = COB_STATUS_00_SUCCESS;
03262 
03263         if (f->flag_nonexistent) {
03264                 return COB_STATUS_30_PERMANENT_ERROR;
03265         }
03266 #if defined(ISVARLEN)
03267         if (f->record_min != f->record_max) {
03268                 isreclen = f->record->size;
03269         }
03270 #endif
03271         if (iswrite (fh->isfd, (void *)f->record->data) == -1) {
03272                 ret = isretsts (COB_STATUS_49_I_O_DENIED);
03273                 if (iserrno == EDUPL) {
03274                         if (f->open_mode == COB_OPEN_OUTPUT) {
03275                                 ret = COB_STATUS_21_KEY_INVALID;
03276                         }
03277                 }
03278         } else {
03279                 memcpy (fh->savekey, f->record->data + fh->key[0].k_start, fh->key[0].k_leng);
03280         }
03281         return ret;
03282 #else   /* WITH_INDEX_EXTFH */
03283         struct indexed_file     *p = f->file;
03284 
03285 #ifdef  USE_DB41
03286         if (bdb_env != NULL) {
03287                 unlock_record (f);
03288         }
03289 #endif
03290 
03291         /* check record key */
03292         DBT_SET (p->key, f->keys[0].field);
03293         if (!p->last_key) {
03294                 p->last_key = cob_malloc (p->key.size);
03295         } else if (f->access_mode == COB_ACCESS_SEQUENTIAL
03296                  && memcmp (p->last_key, p->key.data, p->key.size) > 0) {
03297                 return COB_STATUS_21_KEY_INVALID;
03298         }
03299         memcpy (p->last_key, p->key.data, p->key.size);
03300 
03301         return indexed_write_internal (f, 0, opt);
03302 #endif  /* WITH_INDEX_EXTFH */
03303 }
03304 
03305 #if     !defined(WITH_INDEX_EXTFH) && !defined(WITH_CISAM) && !defined(WITH_DISAM) && !defined(WITH_VBISAM)
03306 static int
03307 indexed_delete_internal (cob_file *f, const int rewrite)
03308 {
03309         size_t                  i;
03310         size_t                  offset;
03311         struct indexed_file     *p = f->file;
03312         DBT                     prim_key;
03313 #ifdef  USE_DB41
03314         int                     ret, flags, close_cursor;
03315 
03316         if (bdb_env) {
03317                 flags = DB_WRITECURSOR;
03318         } else {
03319                 flags = 0;
03320         }
03321         if (p->write_cursor_open) {
03322                 close_cursor = 0;
03323         } else {
03324                 p->db[0]->cursor (p->db[0], NULL, &p->cursor[0], flags);
03325                 p->write_cursor_open = 1; 
03326                 close_cursor = 1;
03327         }
03328         if (bdb_env != NULL) {
03329                 unlock_record (f);
03330         }
03331 #endif
03332         /* find the primary key */
03333 #ifdef  USE_DB41
03334         if (f->access_mode != COB_ACCESS_SEQUENTIAL) {
03335                 DBT_SET (p->key, f->keys[0].field);
03336         }
03337         ret = DB_SEQ (p->cursor[0], DB_SET);
03338         if (ret != 0 && f->access_mode != COB_ACCESS_SEQUENTIAL) {
03339                 if (close_cursor) {
03340                         p->cursor[0]->c_close (p->cursor[0]);
03341                         p->cursor[0] = NULL;
03342                         p->write_cursor_open = 0; 
03343                 }
03344                 return COB_STATUS_23_KEY_NOT_EXISTS;
03345         }
03346         if (bdb_env != NULL) {
03347                 ret = test_record_lock (f, p->key.data, p->key.size);
03348                 if (ret) {
03349                         if (close_cursor) {
03350                                 p->cursor[0]->c_close (p->cursor[0]);
03351                                 p->cursor[0] = NULL;
03352                                 p->write_cursor_open = 0; 
03353                         }
03354                         return COB_STATUS_51_RECORD_LOCKED;
03355                 }
03356         }
03357 #else
03358         if (f->access_mode != COB_ACCESS_SEQUENTIAL) {
03359                 DBT_SET (p->key, f->keys[0].field);
03360                 if (DB_GET (p->db[0], 0) != 0) {
03361                         return COB_STATUS_23_KEY_NOT_EXISTS;
03362                 }
03363         }
03364 #endif
03365         prim_key = p->key;
03366 
03367         /* delete the secondary keys */
03368         offset = (char *) p->data.data - (char *) f->record->data;
03369         for (i = 1; i < f->nkeys; i++) {
03370                 DBT_SET (p->key, f->keys[i].field);
03371                 p->key.data = (char *)p->key.data + offset;
03372                 /* rewrite: no delete if secondary key is unchanged */
03373                 if (rewrite) {
03374                         p->rewrite_sec_key[i] = memcmp (p->key.data, f->keys[i].field->data, p->key.size);
03375                         if (!p->rewrite_sec_key[i]) {
03376                                 continue;
03377                         }
03378                 }
03379                 if (!f->keys[i].flag) {
03380                         DB_DEL (p->db[i], &p->key, 0);
03381                 } else {
03382                         DBT     sec_key = p->key;
03383 
03384 #ifdef  USE_DB41
03385                         p->db[i]->cursor (p->db[i], NULL, &p->cursor[i], flags);
03386                         if (DB_SEQ (p->cursor[i], DB_SET_RANGE) == 0) {
03387 #else
03388                         if (DB_SEQ (p->db[i], R_CURSOR) == 0) {
03389 #endif
03390                                 while (sec_key.size == p->key.size
03391                                 && memcmp (p->key.data, sec_key.data,
03392                                 sec_key.size) == 0) {
03393                                         if (memcmp (p->data.data, prim_key.data,
03394                                         prim_key.size) == 0) {
03395 #ifdef  USE_DB41
03396                                                 p->cursor[i]->c_del (p->cursor[i], 0);
03397 #else
03398                                                 DB_DEL (p->db[i], &p->key, R_CURSOR);
03399 #endif
03400                                         }
03401 #ifdef  USE_DB41
03402                                         if (DB_SEQ (p->cursor[i], DB_NEXT) != 0) {
03403 #else
03404                                         if (DB_SEQ (p->db[i], R_NEXT) != 0) {
03405 #endif
03406                                                 break;
03407                                         }
03408                                 }
03409                         }
03410 #ifdef  USE_DB41
03411                         p->cursor[i]->c_close (p->cursor[i]);
03412                         p->cursor[i] = NULL;
03413 #endif
03414                 }
03415         }
03416 
03417         /* delete the record */
03418 #ifdef  USE_DB41
03419         p->cursor[0]->c_del (p->cursor[0], 0);
03420 #else
03421         DB_DEL (p->db[0], &prim_key, 0);
03422 #endif
03423 
03424 #ifdef  USE_DB41
03425         if (close_cursor) {
03426                 p->cursor[0]->c_close (p->cursor[0]);
03427                 p->cursor[0] = NULL;
03428                 p->write_cursor_open = 0; 
03429         }
03430 #endif
03431         return COB_STATUS_00_SUCCESS;
03432 }
03433 #endif  /* !WITH_INDEX_EXTFH && !WITH_CISAM && !WITH_DISAM && !WITH_VBISAM */
03434 
03435 /* DELETE record from the INDEXED file  */
03436 
03437 static int
03438 indexed_delete (cob_file *f)
03439 {
03440 #ifdef  WITH_INDEX_EXTFH
03441         return extfh_indexed_delete (f);
03442 #elif   defined(WITH_CISAM) || defined(WITH_DISAM) || defined(WITH_VBISAM)
03443         struct indexfile        *fh = f->file;
03444         int                     ret = COB_STATUS_00_SUCCESS;
03445 
03446         if (f->flag_nonexistent) {
03447                 return COB_STATUS_30_PERMANENT_ERROR;
03448         }
03449         if (fh->curkey == -1) {                         /* Switch to prime index */
03450                 isstart (fh->isfd, &fh->key[0], fh->key[0].k_leng, (void *)f->record->data, ISEQUAL);
03451                 fh->curkey = 0;
03452                 fh->readdir = ISNEXT;
03453         } else {
03454                 savefileposition (f);
03455                 if (fh->curkey != 0) {                  /* Switch to prime index */
03456                         isstart (fh->isfd, &fh->key[0], fh->key[0].k_leng, (void *)f->record->data, ISEQUAL);
03457                 }
03458         }
03459         if (isread (fh->isfd, (void *)f->record->data, ISEQUAL | ISLOCK) == -1) {
03460                 ret = isretsts (COB_STATUS_21_KEY_INVALID);
03461         } else if (isdelete (fh->isfd, (void *)f->record->data) == -1) {
03462                 ret = isretsts (COB_STATUS_49_I_O_DENIED);
03463         }
03464         restorefileposition (f);
03465         return ret;
03466 #else   /* WITH_INDEX_EXTFH */
03467         return indexed_delete_internal (f, 0);
03468 #endif  /* WITH_INDEX_EXTFH */
03469 }
03470 
03471 /* REWRITE record to the INDEXED file  */
03472 
03473 static int
03474 indexed_rewrite (cob_file *f, const int opt)
03475 {
03476 #ifdef  WITH_INDEX_EXTFH
03477         return extfh_indexed_rewrite (f, opt);
03478 #elif   defined(WITH_CISAM) || defined(WITH_DISAM) || defined(WITH_VBISAM)
03479         struct indexfile        *fh = f->file;
03480         int                     ret = COB_STATUS_00_SUCCESS;
03481         int                     k;
03482 
03483         if (f->flag_nonexistent) {
03484                 return COB_STATUS_30_PERMANENT_ERROR;
03485         }
03486 
03487         if (f->access_mode == COB_ACCESS_SEQUENTIAL
03488         && memcmp (fh->savekey, f->record->data + fh->key[0].k_start, fh->key[0].k_leng) != 0) {
03489                 return COB_STATUS_21_KEY_INVALID;
03490         }
03491         if (fh->curkey >= 0) {          /* Index is active */
03492                 /* Save record data */
03493                 memcpy (fh->recwrk, f->record->data, f->record_max);
03494                 savefileposition (f);
03495                 memcpy (fh->recwrk, f->record->data, f->record_max);
03496                 if (fh->curkey != 0) {          /* Activate Prime index */
03497                         isstart (fh->isfd, &fh->key[0], 0, (void *)fh->recwrk, ISEQUAL);
03498                 }
03499                 /* Verify record exists */
03500                 if (isread (fh->isfd, fh->recwrk, ISEQUAL) == -1) {
03501                         restorefileposition (f);                                
03502                         return COB_STATUS_21_KEY_INVALID;
03503                 }
03504                 for (k = 1; k < f->nkeys && ret == COB_STATUS_00_SUCCESS; k++) {
03505                         if (fh->key[k].k_flags & ISDUPS) {
03506                                 continue;
03507                         }
03508                         memcpy (fh->recwrk, f->record->data, f->record_max);
03509                         isstart (fh->isfd, &fh->key[k], fh->key[k].k_leng, (void *)fh->recwrk, ISEQUAL);
03510                         if (isread (fh->isfd, (void *)fh->recwrk, ISEQUAL) != -1
03511                         && isrecnum != fh->recnum) {
03512                                 ret = COB_STATUS_22_KEY_EXISTS;
03513                                 break;
03514                         }
03515                 }
03516                 if (ret == COB_STATUS_00_SUCCESS) {
03517                         memcpy (fh->recwrk, f->record->data, f->record_max);
03518                         isstart (fh->isfd, &fh->key[0], 0, (void *)fh->recwrk, ISEQUAL);
03519                         if (isread (fh->isfd, (void *)fh->recwrk, ISEQUAL | ISLOCK) == -1) {
03520                                 ret = isretsts (COB_STATUS_49_I_O_DENIED);
03521                         } else if (isrewcurr (fh->isfd, (void *)f->record->data) == -1) {
03522                                 ret = isretsts (COB_STATUS_49_I_O_DENIED);
03523                         }
03524                 }
03525                 restorefileposition (f);
03526                 return ret;
03527         }
03528 
03529         memcpy (fh->recwrk, f->record->data, f->record_max);
03530         if (isread (fh->isfd, (void *)fh->recwrk, ISEQUAL | ISLOCK) == -1) {
03531                 ret = isretsts (COB_STATUS_49_I_O_DENIED);
03532         } else if (isrewrite (fh->isfd, (void *)f->record->data) == -1) {
03533                 ret = isretsts (COB_STATUS_49_I_O_DENIED);
03534         }
03535 /* RXW */
03536         if (!ret) {
03537                 if ((f->lock_mode & COB_LOCK_AUTOMATIC) &&
03538                     !(f->lock_mode & COB_LOCK_MULTIPLE)) {
03539                         isrelease (fh->isfd);
03540                 }
03541         }
03542         return ret;
03543 #else   /* WITH_INDEX_EXTFH */
03544         struct indexed_file *p = f->file;
03545         int                     ret;
03546 #ifdef  USE_DB41
03547         int                     flags;
03548 
03549         if (bdb_env) {
03550                 flags = DB_WRITECURSOR;
03551         } else {
03552                 flags = 0;
03553         }
03554         p->db[0]->cursor (p->db[0], NULL, &p->cursor[0], flags);
03555         p->write_cursor_open = 1; 
03556         if (bdb_env != NULL) {
03557                 unlock_record (f);
03558         }
03559 #endif
03560 
03561         /* check duplicate alternate keys */
03562         if (check_alt_keys (f, 1)) {
03563 #ifdef  USE_DB41
03564                 p->cursor[0]->c_close (p->cursor[0]);
03565                 p->cursor[0] = NULL;
03566                 p->write_cursor_open = 0; 
03567 #endif
03568                 return COB_STATUS_22_KEY_EXISTS;
03569         }
03570 
03571         /* delete the current record */
03572         ret = indexed_delete_internal (f, 1);
03573 
03574         if (ret != COB_STATUS_00_SUCCESS) {
03575 #ifdef  USE_DB41
03576                 p->cursor[0]->c_close (p->cursor[0]);
03577                 p->cursor[0] = NULL;
03578                 p->write_cursor_open = 0; 
03579 #endif
03580                 return ret;
03581         }
03582 
03583         /* write data */
03584         DBT_SET (p->key, f->keys[0].field);
03585         ret = indexed_write_internal (f, 1, opt);
03586 
03587 #ifdef  USE_DB41
03588         p->cursor[0]->c_close (p->cursor[0]);
03589         p->cursor[0] = NULL;
03590         p->write_cursor_open = 0; 
03591 #endif
03592         return ret;
03593 #endif  /* WITH_INDEX_EXTFH */
03594 }
03595 
03596 #ifdef  USE_DB41
03597 /* 
03598  * check if a file exists in bdb data dirs
03599  */
03600 static int
03601 is_absolute (const char *filename)
03602 {
03603 #ifdef _WIN32
03604         if (filename[0] == '/' || filename[0] == '\\') {
03605                 return 1;
03606         } else {
03607                 if (isalpha (filename[0]) && filename[1] == ':' &&
03608                   (filename[2] == '/' || filename[2] == '\\')) {
03609                         return 1;
03610                 } else {
03611                         return 0;
03612                 }
03613         }
03614 #else
03615         if (filename[0] == '/') {
03616                 return 1;
03617         } else {
03618                 return 0;
03619         }
03620 #endif
03621 }
03622 
03623 static int
03624 bdb_nofile (char *filename)
03625 {
03626         int             i;
03627         struct  stat    st;
03628 
03629         if (is_absolute (filename)) {
03630                 if (stat (filename, &st) == -1 && errno == ENOENT) {
03631                         return 1;
03632                 } else {
03633                         return 0;
03634                 }
03635         }
03636 
03637         for (i = 0; bdb_data_dir && bdb_data_dir[i]; ++i) {
03638                 bdb_buff[COB_SMALL_MAX] = 0;
03639                 if (is_absolute (bdb_data_dir[i])) {
03640                         snprintf (bdb_buff, COB_SMALL_MAX, "%s/%s",
03641                                   bdb_data_dir[i], filename);
03642                 } else {
03643                         snprintf (bdb_buff, COB_SMALL_MAX, "%s/%s/%s",
03644                                   bdb_home, bdb_data_dir[i], filename);
03645                 }
03646                 if (stat (bdb_buff, &st) == 0 || errno != ENOENT) {
03647                         return 0;
03648                 }
03649         }
03650         if (i == 0) {
03651                 bdb_buff[COB_SMALL_MAX] = 0;
03652                 snprintf (bdb_buff, COB_SMALL_MAX, "%s/%s", bdb_home, filename);
03653                 if (stat (bdb_buff, &st) == 0 || errno != ENOENT) {
03654                         return 0;
03655                 }
03656         }
03657         return 1;
03658 }
03659 #endif
03660 
03661 #endif  /* WITH_DB */
03662 
03663 static void COB_NOINLINE
03664 cob_file_unlock (cob_file *f)
03665 {
03666 #ifdef  WITH_DB
03667 #ifdef  USE_DB41
03668         struct indexed_file     *p;
03669 #endif
03670 #endif
03671 #if     defined(WITH_CISAM) || defined(WITH_DISAM) || defined(WITH_VBISAM)
03672         struct indexfile        *fh;
03673 #endif
03674 #ifdef HAVE_FCNTL
03675         struct flock            lock;
03676 #endif
03677 
03678         if (f->open_mode != COB_OPEN_CLOSED &&
03679             f->open_mode != COB_OPEN_LOCKED) {
03680                 if (f->organization == COB_ORG_SORT) {
03681                         return;
03682                 }
03683                 if (f->organization != COB_ORG_INDEXED) {
03684 #ifdef  WITH_SEQRA_EXTFH
03685 #else   /* WITH_SEQRA_EXTFH */
03686                         fflush ((FILE *)f->file);
03687                         fsync (fileno ((FILE *)f->file));
03688 #ifdef HAVE_FCNTL
03689                         if (!(f->lock_mode & COB_LOCK_EXCLUSIVE)) {
03690                                 /* unlock the file */
03691                                 memset ((unsigned char *)&lock, 0, sizeof (struct flock));
03692                                 lock.l_type = F_UNLCK;
03693                                 lock.l_whence = SEEK_SET;
03694                                 lock.l_start = 0;
03695                                 lock.l_len = 0;
03696                                 fcntl (fileno ((FILE *)f->file), F_SETLK, &lock);
03697                         }
03698 #endif
03699 #endif  /* WITH_SEQRA_EXTFH */
03700                 } else {
03701 #ifdef  WITH_INDEX_EXTFH
03702                         extfh_indexed_unlock (f);
03703 #else   /* WITH_INDEX_EXTFH */
03704 #ifdef  WITH_DB
03705 #ifdef  USE_DB41
03706                         p = f->file;
03707                         if (bdb_env != NULL) {
03708                                 unlock_record (f);
03709                                 bdb_env->lock_put (bdb_env, &p->bdb_file_lock);
03710                         }
03711 #endif
03712 #endif
03713 #if     defined(WITH_CISAM) || defined(WITH_DISAM) || defined(WITH_VBISAM)
03714                         fh = f->file;
03715                         isrelease (fh->isfd);
03716 #endif
03717 #endif  /* WITH_INDEX_EXTFH */
03718                 }
03719         }
03720 }
03721 
03722 /*
03723  * Public interface
03724  */
03725 
03726 void
03727 cob_unlock_file (cob_file *f, cob_field *fnstatus)
03728 {
03729         cob_file_unlock (f);
03730         RETURN_STATUS (COB_STATUS_00_SUCCESS);
03731 }
03732 
03733 void
03734 cob_open (cob_file *f, const int mode, const int sharing, cob_field *fnstatus)
03735 {
03736         char            *p;
03737         char            *src;
03738         char            *dst;
03739         size_t          i;
03740         size_t          simple;
03741         int             was_not_exist = 0;
03742         struct stat     st;
03743 
03744         f->flag_read_done = 0;
03745 
03746         /* file was previously closed with lock */
03747         if (f->open_mode == COB_OPEN_LOCKED) {
03748                 RETURN_STATUS (COB_STATUS_38_CLOSED_WITH_LOCK);
03749         }
03750 
03751         /* file is already open */
03752         if (f->open_mode != COB_OPEN_CLOSED) {
03753                 RETURN_STATUS (COB_STATUS_41_ALREADY_OPEN);
03754         }
03755 
03756         f->last_open_mode = mode;
03757         f->flag_nonexistent = 0;
03758         f->flag_end_of_file = 0;
03759         f->flag_begin_of_file = 0;
03760         f->flag_first_read = 2;
03761 
03762         if (f->special) {
03763                 if (f->special == 1) {
03764                         if (mode != COB_OPEN_INPUT) {
03765                                 RETURN_STATUS (COB_STATUS_30_PERMANENT_ERROR);
03766                         }
03767                         f->file = stdin;
03768                         f->open_mode = mode;
03769                         RETURN_STATUS (COB_STATUS_00_SUCCESS);
03770                 } else {
03771                         if (mode != COB_OPEN_OUTPUT) {
03772                                 RETURN_STATUS (COB_STATUS_30_PERMANENT_ERROR);
03773                         }
03774                         f->file = stdout;
03775                         f->open_mode = mode;
03776                         RETURN_STATUS (COB_STATUS_00_SUCCESS);
03777                 }
03778         }
03779 
03780         /* obtain the file name */
03781         cob_field_to_string (f->assign, file_open_name);
03782 
03783 #ifdef  WITH_INDEX_EXTFH
03784         if (f->organization == COB_ORG_INDEXED) {
03785                 int     ret;
03786 
03787                 ret = extfh_indexed_locate (f, file_open_name);
03788                 switch (ret) {
03789                 case COB_NOT_CONFIGURED:
03790                         /* EXTFH requires OC to process the filename */
03791                         break;
03792                 case COB_STATUS_00_SUCCESS:
03793                         /* EXTFH recognized the file */
03794                         goto file_available;
03795                 default:
03796                         /* EXTFH detected an error */
03797                         RETURN_STATUS (ret);
03798                 }
03799         }
03800 #endif  /* WITH_INDEX_EXTFH */
03801 
03802 #ifdef  WITH_SEQRA_EXTFH
03803         if (f->organization != COB_ORG_INDEXED) {
03804                 int     ret;
03805 
03806                 ret = extfh_seqra_locate (f, file_open_name);
03807                 switch (ret) {
03808                 case COB_NOT_CONFIGURED:
03809                         /* EXTFH requires OC to process the filename */
03810                         break;
03811                 case COB_STATUS_00_SUCCESS:
03812                         /* EXTFH recognized the file */
03813                         goto file_available;
03814                 default:
03815                         /* EXTFH detected an error */
03816                         RETURN_STATUS (ret);
03817                 }
03818         }
03819 #endif  /* WITH_SEQRA_EXTFH */
03820 
03821         if (cob_current_module->flag_filename_mapping) {
03822                 src = file_open_name;
03823                 dst = file_open_buff;
03824                 simple = 1;
03825                 /* expand envoronment variables */
03826                 /* ex. "$TMPDIR/foo" -> "/tmp/foo" */
03827                 while (*src) {
03828                         if (!isalnum (*src) && *src != '_' && *src != '-') {
03829                                 simple = 0;
03830                         }
03831                         if (*src == '$') {
03832                                 for (i = 1; ; i++) {
03833                                         if (!isalnum (src[i]) && src[i] != '_' && *src != '-') {
03834                                                 break;
03835                                         }
03836                                 }
03837                                 memcpy (file_open_env, src + 1, i - 1);
03838                                 file_open_env[i - 1] = 0;
03839                                 if ((p = getenv (file_open_env)) != NULL) {
03840                                         strcpy (dst, p);
03841                                         dst += strlen (p);
03842                                 }
03843                                 src += i;
03844                         } else {
03845                                 *dst++ = *src++;
03846                         }
03847                 }
03848                 *dst = 0;
03849                 strncpy (file_open_name, file_open_buff, COB_SMALL_MAX);
03850 
03851                 /* resolve by environment variables */
03852                 /* ex. "TMPFILE" -> DD_TMPFILE, dd_TMPFILE, or TMPFILE */
03853                 if (simple) {
03854                         for (i = 0; i < NUM_PREFIX; i++) {
03855                                 snprintf (file_open_buff, COB_SMALL_MAX, "%s%s",
03856                                           prefix[i], file_open_name);
03857                                 if ((p = getenv (file_open_buff)) != NULL) {
03858                                         strncpy (file_open_name, p, COB_SMALL_MAX);
03859                                         break;
03860                                 }
03861                         }
03862                         if (i == NUM_PREFIX && cob_file_path) {
03863                                 snprintf (file_open_buff, COB_SMALL_MAX, "%s/%s",
03864                                           cob_file_path, file_open_name);
03865                                 strncpy (file_open_name, file_open_buff,
03866                                          COB_SMALL_MAX);
03867                         }
03868                 }
03869         }
03870         /* check if the file exists */
03871 #ifdef  USE_DB41
03872         if (f->organization == COB_ORG_INDEXED) {
03873                 if ((bdb_env && bdb_nofile (file_open_name)) ||
03874                      (!bdb_env && stat (file_open_name, &st) == -1 && errno == ENOENT)) {
03875                         was_not_exist = 1;
03876                         if (mode != COB_OPEN_OUTPUT && f->flag_optional == 0) {
03877                                 RETURN_STATUS (COB_STATUS_35_NOT_EXISTS);
03878                         }
03879                 }
03880         } else if (stat (file_open_name, &st) == -1 && errno == ENOENT) {
03881 #else   /* USE_DB41 */
03882 
03883 #if     defined(WITH_CISAM) || defined(WITH_DISAM) || defined(WITH_VBISAM)
03884         if (f->organization == COB_ORG_INDEXED) {
03885                 strncpy (file_open_buff, file_open_name, COB_SMALL_MAX);
03886                 strcat (file_open_buff, ".idx");
03887                 if (stat (file_open_buff, &st) == -1 && errno == ENOENT) {
03888                         was_not_exist = 1;
03889                         if (mode != COB_OPEN_OUTPUT && f->flag_optional == 0) {
03890                                 RETURN_STATUS (COB_STATUS_35_NOT_EXISTS);
03891                         }
03892                 }
03893                 strncpy (file_open_buff, file_open_name, COB_SMALL_MAX);
03894                 strcat (file_open_buff, ".dat");
03895                 if (stat (file_open_buff, &st) == -1 && errno == ENOENT) {
03896                         was_not_exist = 1;
03897                         if (mode != COB_OPEN_OUTPUT && f->flag_optional == 0) {
03898                                 RETURN_STATUS (COB_STATUS_35_NOT_EXISTS);
03899                         }
03900                 }
03901         } else if (stat (file_open_name, &st) == -1 && errno == ENOENT) {
03902 #else   /* WITH_CISAM || WITH_DISAM || WITH_VBISAM */
03903         if (stat (file_open_name, &st) == -1 && errno == ENOENT) {
03904 #endif  /* WITH_CISAM || WITH_DISAM || WITH_VBISAM */
03905 
03906 #endif  /* USE_DB41 */
03907 
03908                 was_not_exist = 1;
03909                 if (mode != COB_OPEN_OUTPUT && f->flag_optional == 0) {
03910                         RETURN_STATUS (COB_STATUS_35_NOT_EXISTS);
03911                 }
03912         }
03913 
03914 #if     defined(WITH_INDEX_EXTFH) || defined(WITH_SEQRA_EXTFH)
03915 file_available:
03916 #endif  /* WITH_INDEX_EXTFH || WITH_SEQRA_EXTFH */
03917 
03918         cob_cache_file (f);
03919 
03920         /* open the file */
03921 #ifdef  WITH_SEQRA_EXTFH
03922         if (f->organization != COB_ORG_INDEXED) {
03923                 int     ret;
03924 
03925                 ret = extfh_cob_file_open (f, file_open_name, mode, sharing);
03926                 switch (ret) {
03927                 case COB_STATUS_00_SUCCESS:
03928                         f->open_mode = mode;
03929                         break;
03930                 case COB_STATUS_35_NOT_EXISTS:
03931                         if (f->flag_optional) {
03932                                 f->open_mode = mode;
03933                                 f->flag_nonexistent = 1;
03934                                 f->flag_end_of_file = 1;
03935                                 f->flag_begin_of_file = 1;
03936                                 RETURN_STATUS (COB_STATUS_05_SUCCESS_OPTIONAL);
03937                         }
03938                         break;
03939                 }
03940                 RETURN_STATUS (ret);
03941         }
03942 #endif
03943 #if     defined(WITH_CISAM) || defined(WITH_DISAM) || defined(WITH_VBISAM)
03944         if (f->organization == COB_ORG_INDEXED) {
03945                 /* Do this here to avoid mangling of the status in the 'switch' below */
03946                 RETURN_STATUS (fileio_funcs[(int)f->organization]->open (f, file_open_name, mode, sharing));
03947         }
03948 #endif
03949         switch (fileio_funcs[(int)f->organization]->open (f, file_open_name, mode, sharing)) {
03950         case 0:
03951                 f->open_mode = mode;
03952                 if (f->flag_optional && was_not_exist) {
03953                         RETURN_STATUS (COB_STATUS_05_SUCCESS_OPTIONAL);
03954                 } else {
03955                         RETURN_STATUS (COB_STATUS_00_SUCCESS);
03956                 }
03957         case ENOENT:
03958                 if (mode == COB_OPEN_EXTEND || mode == COB_OPEN_OUTPUT) {
03959                         RETURN_STATUS (COB_STATUS_30_PERMANENT_ERROR);
03960                 }
03961                 if (f->flag_optional) {
03962                         f->open_mode = mode;
03963                         f->flag_nonexistent = 1;
03964                         f->flag_end_of_file = 1;
03965                         f->flag_begin_of_file = 1;
03966                         RETURN_STATUS (COB_STATUS_05_SUCCESS_OPTIONAL);
03967                 } else {
03968                         RETURN_STATUS (COB_STATUS_35_NOT_EXISTS);
03969                 }
03970         case EACCES:
03971         case EISDIR:
03972         case EROFS:
03973                 RETURN_STATUS (COB_STATUS_37_PERMISSION_DENIED);
03974         case EAGAIN:
03975         case COB_STATUS_61_FILE_SHARING:
03976                 RETURN_STATUS (COB_STATUS_61_FILE_SHARING);
03977         case COB_STATUS_91_NOT_AVAILABLE:
03978                 RETURN_STATUS (COB_STATUS_91_NOT_AVAILABLE);
03979         case COB_LINAGE_INVALID:
03980                 RETURN_STATUS (COB_STATUS_57_I_O_LINAGE);
03981         default:
03982                 RETURN_STATUS (COB_STATUS_30_PERMANENT_ERROR);
03983         }
03984 }
03985 
03986 void
03987 cob_close (cob_file *f, const int opt, cob_field *fnstatus)
03988 {
03989         int     ret;
03990 
03991         f->flag_read_done = 0;
03992 
03993         if (f->special) {
03994                 f->open_mode = COB_OPEN_CLOSED;
03995                 RETURN_STATUS (COB_STATUS_00_SUCCESS);
03996         }
03997         if (f->open_mode == COB_OPEN_CLOSED) {
03998                 RETURN_STATUS (COB_STATUS_42_NOT_OPEN);
03999         }
04000 
04001         if (f->flag_nonexistent) {
04002                 ret = COB_STATUS_00_SUCCESS;
04003         } else {
04004 #ifdef  WITH_SEQRA_EXTFH
04005                 if (f->organization != COB_ORG_INDEXED) {
04006                         ret = extfh_cob_file_close (f, opt);
04007                 } else {
04008 #endif
04009                         ret = fileio_funcs[(int)f->organization]->close (f, opt);
04010 #ifdef  WITH_SEQRA_EXTFH
04011                 }
04012 #endif
04013         }
04014 
04015         if (ret == COB_STATUS_00_SUCCESS) {
04016                 switch (opt) {
04017                 case COB_CLOSE_LOCK:
04018                         f->open_mode = COB_OPEN_LOCKED;
04019                         break;
04020                 default:
04021                         f->open_mode = COB_OPEN_CLOSED;
04022                         break;
04023                 }
04024         }
04025 
04026         RETURN_STATUS (ret);
04027 }
04028 
04029 #if 0
04030 void
04031 cob_unlock (cob_file *f)
04032 {
04033         int     ret;
04034 
04035         f->flag_read_done = 0;
04036 
04037         if (f->open_mode == COB_OPEN_CLOSED) {
04038                 RETURN_STATUS (COB_STATUS_42_NOT_OPEN);
04039         }
04040 
04041         if (f->flag_nonexistent) {
04042                 ret = COB_STATUS_00_SUCCESS;
04043         } else {
04044                 ret = fileio_funcs[(int)f->organization]->close (f, opt);
04045         }
04046 
04047         RETURN_STATUS (ret);
04048 }
04049 #endif
04050 
04051 void
04052 cob_start (cob_file *f, const int cond, cob_field *key, cob_field *fnstatus)
04053 {
04054         int     ret;
04055 
04056         f->flag_read_done = 0;
04057         f->flag_first_read = 0;
04058 
04059         if (f->flag_nonexistent) {
04060                 RETURN_STATUS (COB_STATUS_23_KEY_NOT_EXISTS);
04061         }
04062 
04063         if (f->open_mode == COB_OPEN_CLOSED
04064             || f->open_mode == COB_OPEN_OUTPUT
04065             || f->open_mode == COB_OPEN_EXTEND
04066             || f->access_mode == COB_ACCESS_RANDOM) {
04067                 RETURN_STATUS (COB_STATUS_47_INPUT_DENIED);
04068         }
04069 
04070         ret = fileio_funcs[(int)f->organization]->start (f, cond, key);
04071         if (ret == COB_STATUS_00_SUCCESS) {
04072                 f->flag_end_of_file = 0;
04073                 f->flag_begin_of_file = 0;
04074                 f->flag_first_read = 1;
04075         }
04076 
04077         RETURN_STATUS (ret);
04078 }
04079 
04080 void
04081 cob_read (cob_file *f, cob_field *key, cob_field *fnstatus, int read_opts)
04082 {
04083         int     ret;
04084 
04085         f->flag_read_done = 0;
04086 
04087         if (unlikely(f->flag_nonexistent)) {
04088                 if (f->flag_first_read == 0) {
04089                         RETURN_STATUS (COB_STATUS_23_KEY_NOT_EXISTS);
04090                 }
04091                 f->flag_first_read = 0;
04092                 RETURN_STATUS (COB_STATUS_10_END_OF_FILE);
04093         }
04094 
04095         /* sequential read at the end of file is an error */
04096         if (key == NULL) {
04097                 if (f->flag_end_of_file && !(read_opts & COB_READ_PREVIOUS)) {
04098                         RETURN_STATUS (COB_STATUS_46_READ_ERROR);
04099                 }
04100                 if (f->flag_begin_of_file && (read_opts & COB_READ_PREVIOUS)) {
04101                         RETURN_STATUS (COB_STATUS_46_READ_ERROR);
04102                 }
04103         }
04104 
04105         if (unlikely(f->open_mode == COB_OPEN_CLOSED
04106             || f->open_mode == COB_OPEN_OUTPUT
04107             || f->open_mode == COB_OPEN_EXTEND)) {
04108                 RETURN_STATUS (COB_STATUS_47_INPUT_DENIED);
04109         }
04110 
04111 #ifdef  USE_DB41
04112         if (f->organization == COB_ORG_INDEXED && bdb_env != NULL) {
04113                 if (f->open_mode != COB_OPEN_I_O  ||
04114                     (f->lock_mode & COB_LOCK_EXCLUSIVE)) {
04115                         read_opts &= ~COB_READ_LOCK;
04116                 } else if ((f->lock_mode & COB_LOCK_AUTOMATIC) &&
04117                    !(read_opts & COB_READ_NO_LOCK)) {
04118                         read_opts |= COB_READ_LOCK; 
04119                 }
04120         } else {
04121                 read_opts &= ~COB_READ_LOCK;
04122         }
04123 #endif
04124         if (key) {
04125                 ret = fileio_funcs[(int)f->organization]->read (f, key, read_opts);
04126         } else {
04127                 ret = fileio_funcs[(int)f->organization]->read_next (f, read_opts);
04128         }
04129 
04130         switch (ret) {
04131         case COB_STATUS_00_SUCCESS:
04132                 f->flag_first_read = 0;
04133                 f->flag_read_done = 1;
04134                 f->flag_end_of_file = 0;
04135                 f->flag_begin_of_file = 0;
04136                 if (f->record_size && f->organization != COB_ORG_LINE_SEQUENTIAL) {
04137                         cob_set_int (f->record_size, (int) f->record->size);
04138                 }
04139                 break;
04140         case COB_STATUS_10_END_OF_FILE:
04141                 if (read_opts & COB_READ_PREVIOUS) {
04142                         f->flag_begin_of_file = 1;
04143                 } else {
04144                         f->flag_end_of_file = 1;
04145                 }
04146                 break;
04147         }
04148 
04149         RETURN_STATUS (ret);
04150 }
04151 
04152 void
04153 cob_write (cob_file *f, cob_field *rec, const int opt, cob_field *fnstatus)
04154 {
04155         int     ret;
04156 
04157         f->flag_read_done = 0;
04158 
04159         if (f->access_mode == COB_ACCESS_SEQUENTIAL) {
04160                 if (f->open_mode == COB_OPEN_CLOSED
04161                     || f->open_mode == COB_OPEN_INPUT
04162                     || f->open_mode == COB_OPEN_I_O) {
04163                         RETURN_STATUS (COB_STATUS_48_OUTPUT_DENIED);
04164                 }
04165         } else {
04166                 if (f->open_mode == COB_OPEN_CLOSED
04167                     || f->open_mode == COB_OPEN_INPUT
04168                     || f->open_mode == COB_OPEN_EXTEND) {
04169                         RETURN_STATUS (COB_STATUS_48_OUTPUT_DENIED);
04170                 }
04171         }
04172 
04173         if (f->record_size) {
04174                 f->record->size = cob_get_int (f->record_size);
04175         } else {
04176                 f->record->size = rec->size;
04177         }
04178 
04179         if (f->record->size < f->record_min || f->record_max < f->record->size) {
04180                 RETURN_STATUS (COB_STATUS_44_RECORD_OVERFLOW);
04181         }
04182 
04183 /* RXW
04184 #ifdef  USE_DB41
04185         if (f->organization != COB_ORG_INDEXED || bdb_env == NULL) {
04186                 opt &= ~COB_WRITE_LOCK;
04187         }
04188 #endif
04189 */
04190 
04191         ret = fileio_funcs[(int)f->organization]->write (f, opt);
04192 
04193         if (unlikely(cob_do_sync && ret == 0)) {
04194                 cob_sync (f, cob_do_sync);
04195         }
04196 
04197         RETURN_STATUS (ret);
04198 }
04199 
04200 void
04201 cob_rewrite (cob_file *f, cob_field *rec, const int opt, cob_field *fnstatus)
04202 {
04203         int     ret;
04204         int     read_done = f->flag_read_done;
04205 
04206         f->flag_read_done = 0;
04207 
04208         if (unlikely(f->open_mode == COB_OPEN_CLOSED ||
04209             f->open_mode != COB_OPEN_I_O)) {
04210                 RETURN_STATUS (COB_STATUS_49_I_O_DENIED);
04211         }
04212 
04213         if (f->access_mode == COB_ACCESS_SEQUENTIAL && !read_done) {
04214                 RETURN_STATUS (COB_STATUS_43_READ_NOT_DONE);
04215         }
04216 
04217         if (f->organization == COB_ORG_SEQUENTIAL) {
04218                 if (f->record->size != rec->size) {
04219                         RETURN_STATUS (COB_STATUS_44_RECORD_OVERFLOW);
04220                 }
04221 
04222                 if (f->record_size) {
04223                         if (f->record->size != (size_t)cob_get_int (f->record_size)) {
04224                                 RETURN_STATUS (COB_STATUS_44_RECORD_OVERFLOW);
04225                         }
04226                 }
04227         }
04228 
04229 /* RXW
04230 #ifdef  USE_DB41
04231         if (f->organization != COB_ORG_INDEXED || bdb_env == NULL) {
04232                 opt &= ~COB_WRITE_LOCK;
04233         }
04234 #endif
04235 */
04236 
04237         ret = fileio_funcs[(int)f->organization]->rewrite (f, opt);
04238 
04239         if (unlikely(cob_do_sync && ret == 0)) {
04240                 cob_sync (f, cob_do_sync);
04241         }
04242 
04243         RETURN_STATUS (ret);
04244 }
04245 
04246 void
04247 cob_delete (cob_file *f, cob_field *fnstatus)
04248 {
04249         int     ret;
04250         int     read_done = f->flag_read_done;
04251 
04252         f->flag_read_done = 0;
04253 
04254         if (unlikely(f->open_mode == COB_OPEN_CLOSED ||
04255             f->open_mode != COB_OPEN_I_O)) {
04256                 RETURN_STATUS (COB_STATUS_49_I_O_DENIED);
04257         }
04258 
04259         if (f->access_mode == COB_ACCESS_SEQUENTIAL && !read_done) {
04260                 RETURN_STATUS (COB_STATUS_43_READ_NOT_DONE);
04261         }
04262 
04263         ret = fileio_funcs[(int)f->organization]->fdelete (f);
04264 
04265         if (unlikely(cob_do_sync && ret == 0)) {
04266                 cob_sync (f, cob_do_sync);
04267         }
04268 
04269         RETURN_STATUS (ret);
04270 }
04271 
04272 void
04273 cob_commit (void)
04274 {
04275         struct file_list        *l;
04276 
04277         for (l = file_cache; l; l = l->next) {
04278                 cob_file_unlock (l->file);
04279         }
04280 }
04281 
04282 void
04283 cob_rollback (void)
04284 {
04285         struct file_list        *l;
04286 
04287         for (l = file_cache; l; l = l->next) {
04288                 cob_file_unlock (l->file);
04289         }
04290 }
04291 
04292 void
04293 cob_default_error_handle (void)
04294 {
04295         const char      *msg;
04296         unsigned char   *file_status;
04297         char            *filename;
04298         int             status;
04299 
04300         file_status = cob_error_file->file_status;
04301         status = cob_d2i(file_status[0]) * 10 + cob_d2i(file_status[1]);
04302         switch (status) {
04303         case COB_STATUS_10_END_OF_FILE:
04304                 msg = "End of file";
04305                 break;
04306         case COB_STATUS_14_OUT_OF_KEY_RANGE:
04307                 msg = "Key out of range";
04308                 break;
04309         case COB_STATUS_21_KEY_INVALID:
04310                 msg = "Key order not ascending";
04311                 break;
04312         case COB_STATUS_22_KEY_EXISTS:
04313                 msg = "Record key already exists";
04314                 break;
04315         case COB_STATUS_23_KEY_NOT_EXISTS:
04316                 msg = "Record key does not exist";
04317                 break;
04318         case COB_STATUS_30_PERMANENT_ERROR:
04319                 msg = "Permanent file error";
04320                 break;
04321         case COB_STATUS_35_NOT_EXISTS:
04322                 msg = "File does not exist";
04323                 break;
04324         case COB_STATUS_37_PERMISSION_DENIED:
04325                 msg = "Permission denied";
04326                 break;
04327         case COB_STATUS_41_ALREADY_OPEN:
04328                 msg = "File already open";
04329                 break;
04330         case COB_STATUS_42_NOT_OPEN:
04331                 msg = "File not open";
04332                 break;
04333         case COB_STATUS_43_READ_NOT_DONE:
04334                 msg = "READ must be executed first";
04335                 break;
04336         case COB_STATUS_44_RECORD_OVERFLOW:
04337                 msg = "Record overflow";
04338                 break;
04339         case COB_STATUS_46_READ_ERROR:
04340                 msg = "Failed to read";
04341                 break;
04342         case COB_STATUS_47_INPUT_DENIED:
04343                 msg = "READ/START not allowed";
04344                 break;
04345         case COB_STATUS_48_OUTPUT_DENIED:
04346                 msg = "WRITE not allowed";
04347                 break;
04348         case COB_STATUS_49_I_O_DENIED:
04349                 msg = "DELETE/REWRITE not allowed";
04350                 break;
04351         case COB_STATUS_51_RECORD_LOCKED:
04352                 msg = "Record locked by another file connector";
04353                 break;
04354         case COB_STATUS_52_EOP:
04355                 msg = "A page overflow condition occurred";
04356                 break;
04357         case COB_STATUS_57_I_O_LINAGE:
04358                 msg = "LINAGE values invalid";
04359                 break;
04360         case COB_STATUS_61_FILE_SHARING:
04361                 msg = "File sharing conflict";
04362                 break;
04363         case COB_STATUS_91_NOT_AVAILABLE:
04364                 msg = "Runtime library is not configured for this operation";
04365                 break;
04366         default:
04367                 msg = "Unknown file error";
04368                 break;
04369         }
04370 
04371         filename = cob_malloc (COB_MEDIUM_BUFF);
04372         cob_field_to_string (cob_error_file->assign, filename);
04373         cob_runtime_error ("%s (STATUS = %02d) File : '%s'", msg,
04374                                 status, filename);
04375         free (filename);
04376 }
04377 
04378 void
04379 cob_init_fileio (void)
04380 {
04381         char    *s;
04382         int     n;
04383 
04384         if ((s = getenv ("COB_SYNC")) != NULL) {
04385                 if (*s == 'Y' || *s == 'y') {
04386                         cob_do_sync = 1;
04387                 }
04388                 if (*s == 'P' || *s == 'p') {
04389                         cob_do_sync = 2;
04390                 }
04391         }
04392         if ((s = getenv ("COB_SORT_MEMORY")) != NULL) {
04393                 n = atoi (s);
04394                 if (n >= 1024*1024) {
04395                         cob_sort_memory = n;
04396                 }
04397         }
04398         cob_file_path = getenv ("COB_FILE_PATH");
04399         if (cob_file_path) {
04400                 if (!*cob_file_path || *cob_file_path == ' ') {
04401                         cob_file_path = NULL;
04402                 }
04403         }
04404         cob_ls_nulls = getenv ("COB_LS_NULLS");
04405         cob_ls_fixed = getenv ("COB_LS_FIXED");
04406 
04407         file_open_env = cob_malloc (COB_SMALL_BUFF);
04408         file_open_name = cob_malloc (COB_SMALL_BUFF);
04409         file_open_buff = cob_malloc (COB_SMALL_BUFF);
04410 
04411 #ifdef  USE_DB41
04412         bdb_home = getenv ("DB_HOME");
04413         join_environment ();
04414         record_lock_object = cob_malloc (1024);
04415         bdb_buff = cob_malloc (COB_SMALL_BUFF);
04416         rlo_size = 1024;
04417 #endif
04418 
04419 #if     defined(WITH_INDEX_EXTFH) || defined(WITH_SEQRA_EXTFH)
04420         extfh_cob_init_fileio (&sequential_funcs, &lineseq_funcs, &relative_funcs, &cob_file_write_opt);
04421 #endif
04422 
04423 }
04424 
04425 void
04426 cob_exit_fileio (void)
04427 {
04428         struct file_list        *l;
04429 
04430         for (l = file_cache; l; l = l->next) {
04431                 if (l->file->open_mode != COB_OPEN_CLOSED &&
04432                      l->file->open_mode != COB_OPEN_LOCKED) {
04433                         cob_field_to_string (l->file->assign, runtime_buffer);
04434                         cob_close (l->file, 0, NULL);
04435                         fprintf (stderr, "WARNING - Implicit CLOSE of %s (\"%s\")\n",
04436                                 l->file->select_name, runtime_buffer);
04437                         fflush (stderr);
04438                 }
04439         }
04440 #ifdef  USE_DB41
04441         free (record_lock_object);
04442         if (bdb_env) {
04443                 bdb_env->lock_id_free (bdb_env, bdb_lock_id);
04444                 bdb_env->close (bdb_env, 0);
04445         }
04446 #endif
04447 #if     defined(WITH_INDEX_EXTFH) || defined(WITH_SEQRA_EXTFH)
04448         extfh_cob_exit_fileio ();
04449 #endif
04450 }
04451 
04452 /* System routines */
04453 
04454 static void * COB_NOINLINE
04455 cob_str_from_fld (const cob_field *f)
04456 {
04457         void            *mptr;
04458         unsigned char   *s;
04459         int             i;
04460         int             n;
04461         int             quote_switch;
04462 
04463         if (!f) {
04464                 return cob_malloc (1);
04465         }
04466         for (i = (int) f->size - 1; i >= 0; i--) {
04467                 if (f->data[i] != ' ' && f->data[i] != 0) {
04468                         break;
04469                 }
04470         }
04471         i++;
04472         /* i is 0 or > 0 */
04473         mptr = cob_malloc ((size_t)(i + 1));
04474         quote_switch = 0;
04475         s = mptr;
04476         for (n = 0; n < i; n++) {
04477                 if (f->data[n] == '"') {
04478                         quote_switch = !quote_switch;
04479                         continue;
04480                 }
04481                 s[n] = f->data[n];
04482                 if (quote_switch) {
04483                         continue;
04484                 }
04485                 if (s[n] == ' ' || s[n] == 0) {
04486                         s[n] = 0;
04487                         break;
04488                 }
04489                 
04490         }
04491         return mptr;
04492 }
04493 
04494 static int COB_NOINLINE
04495 open_cbl_file (unsigned char *file_name, unsigned char *file_access,
04496                unsigned char *file_handle, const int file_flags)
04497 {
04498         char    *fn;
04499 #ifdef  O_BINARY
04500         int     flag = O_BINARY;
04501 #else
04502         int     flag = 0;
04503 #endif
04504         int     fd;
04505 
04506         if (!cob_current_module->cob_procedure_parameters[0]) {
04507                 memset (file_handle, -1, 4);
04508                 return -1;
04509         }
04510         flag |= file_flags;
04511         switch (*file_access & 0x3f) {
04512                 case 1:
04513                         flag |= O_RDONLY;
04514                         break;
04515                 case 2:
04516                         flag |= O_CREAT | O_TRUNC | O_WRONLY;
04517                         break;
04518                 case 3:
04519                         flag |= O_RDWR;
04520                         break;
04521                 default:
04522                         memset (file_handle, -1, 4);
04523                         return -1;
04524         }
04525         fn = cob_str_from_fld (cob_current_module->cob_procedure_parameters[0]);
04526         fd = open (fn, flag, 0660);
04527         if (fd < 0) {
04528                 free (fn);
04529                 memset (file_handle, -1, 4);
04530                 return 35;
04531         }
04532         free (fn);
04533         memcpy (file_handle, &fd, 4);
04534         return 0;
04535 }
04536 
04537 int
04538 CBL_OPEN_FILE (unsigned char *file_name, unsigned char *file_access,
04539                unsigned char *file_lock, unsigned char *file_dev,
04540                unsigned char *file_handle)
04541 {
04542         COB_CHK_PARMS (CBL_OPEN_FILE, 5);
04543 
04544         return open_cbl_file (file_name, file_access, file_handle, 0);
04545 }
04546 
04547 int
04548 CBL_CREATE_FILE (unsigned char *file_name, unsigned char *file_access,
04549                  unsigned char *file_lock, unsigned char *file_dev,
04550                  unsigned char *file_handle)
04551 {
04552         COB_CHK_PARMS (CBL_CREATE_FILE, 5);
04553 
04554         return open_cbl_file (file_name, file_access, file_handle, O_CREAT | O_TRUNC);
04555 }
04556 
04557 int
04558 CBL_READ_FILE (unsigned char *file_handle, unsigned char *file_offset,
04559                unsigned char *file_len, unsigned char *flags, unsigned char *buf)
04560 {
04561         long long       off;
04562         int             fd;
04563         int             len;
04564         int             rc = 0;
04565         struct stat     st;
04566 
04567         COB_CHK_PARMS (CBL_READ_FILE, 5);
04568 
04569         memcpy (&fd, file_handle, 4);
04570         memcpy (&off, file_offset, 8);
04571         memcpy (&len, file_len, 4);
04572 #ifndef WORDS_BIGENDIAN
04573         off = COB_BSWAP_64 (off);
04574         len = COB_BSWAP_32 (len);
04575 #endif
04576         if (lseek (fd, (off_t)off, SEEK_SET) < 0) {
04577                 return -1;
04578         }
04579         if (len > 0) {
04580                 rc = read (fd, buf, (size_t)len);
04581                 if (rc < 0) {
04582                         rc = -1;
04583                 } else if (rc == 0) {
04584                         rc = 10;
04585                 } else {
04586                         rc = 0;
04587                 }
04588         }
04589         if ((*flags & 0x80) != 0) {
04590                 if (fstat (fd, &st) < 0) {
04591                         return -1;
04592                 }
04593                 off = st.st_size;
04594 #ifndef WORDS_BIGENDIAN
04595                 off = COB_BSWAP_64 (off);
04596 #endif
04597                 memcpy (file_offset, &off, 8);
04598         }
04599         return rc;
04600 }
04601 
04602 int
04603 CBL_WRITE_FILE (unsigned char *file_handle, unsigned char *file_offset,
04604                 unsigned char *file_len, unsigned char *flags, unsigned char *buf)
04605 {
04606         long long       off;
04607         int             fd;
04608         int             len;
04609         int             rc;
04610 
04611         COB_CHK_PARMS (CBL_WRITE_FILE, 5);
04612 
04613         memcpy (&fd, file_handle, 4);
04614         memcpy (&off, file_offset, 8);
04615         memcpy (&len, file_len, 4);
04616 #ifndef WORDS_BIGENDIAN
04617         off = COB_BSWAP_64 (off);
04618         len = COB_BSWAP_32 (len);
04619 #endif
04620         if (lseek (fd, (off_t)off, SEEK_SET) < 0) {
04621                 return -1;
04622         }
04623         rc = write (fd, buf, (size_t)len);
04624         if (rc < 0) {
04625                 return 30;
04626         }
04627         return 0;
04628 }
04629 
04630 int
04631 CBL_CLOSE_FILE (unsigned char *file_handle)
04632 {
04633         int     fd;
04634 
04635         COB_CHK_PARMS (CBL_CLOSE_FILE, 1);
04636 
04637         memcpy (&fd, file_handle, 4);
04638         return close (fd);
04639 }
04640 
04641 int
04642 CBL_FLUSH_FILE (unsigned char *file_handle)
04643 {
04644         COB_CHK_PARMS (CBL_FLUSH_FILE, 1);
04645 
04646         return 0;
04647 }
04648 
04649 int
04650 CBL_DELETE_FILE (unsigned char *file_name)
04651 {
04652         char    *fn;
04653         int     ret;
04654 
04655         COB_CHK_PARMS (CBL_DELETE_FILE, 1);
04656 
04657         if (!cob_current_module->cob_procedure_parameters[0]) {
04658                 return -1;
04659         }
04660         fn = cob_str_from_fld (cob_current_module->cob_procedure_parameters[0]);
04661         ret = unlink (fn);
04662         free (fn);
04663         if (ret) {
04664                 return 128;
04665         }
04666         return 0;
04667 }
04668 
04669 int
04670 CBL_COPY_FILE (unsigned char *fname1, unsigned char *fname2)
04671 {
04672         char    *fn1;
04673         char    *fn2;
04674 #ifdef  O_BINARY
04675         int     flag = O_BINARY;
04676 #else
04677         int     flag = 0;
04678 #endif
04679         int     ret;
04680         int     i;
04681         int     fd1, fd2;
04682 
04683         COB_CHK_PARMS (CBL_COPY_FILE, 2);
04684 
04685         if (!cob_current_module->cob_procedure_parameters[0]) {
04686                 return -1;
04687         }
04688         if (!cob_current_module->cob_procedure_parameters[1]) {
04689                 return -1;
04690         }
04691         fn1 = cob_str_from_fld (cob_current_module->cob_procedure_parameters[0]);
04692         flag |= O_RDONLY;
04693         fd1 = open (fn1, flag, 0);
04694         if (fd1 < 0) {
04695                 free (fn1);
04696                 return -1;
04697         }
04698         free (fn1);
04699         fn2 = cob_str_from_fld (cob_current_module->cob_procedure_parameters[1]);
04700         flag &= ~O_RDONLY;
04701         flag |= O_CREAT | O_TRUNC | O_WRONLY;
04702         fd2 = open (fn2, flag, 0660);
04703         if (fd2 < 0) {
04704                 close (fd1);
04705                 free (fn2);
04706                 return -1;
04707         }
04708         free (fn2);
04709         ret = 0;
04710         while ((i = read (fd1, fn1, sizeof(fn1))) > 0) {
04711                 if (write (fd2, fn1, (size_t)i) < 0) {
04712                         ret = -1;
04713                         break;
04714                 }
04715         }
04716         close (fd1);
04717         close (fd2);
04718         return ret;
04719 }
04720 
04721 int
04722 CBL_CHECK_FILE_EXIST (unsigned char *file_name, unsigned char *file_info)
04723 {
04724         char            *fn;
04725         struct tm       *tm;
04726         long long       sz;
04727         struct stat     st;
04728         short           y;
04729         char            d, m, hh, mm, ss;
04730 
04731         COB_CHK_PARMS (CBL_CHECK_FILE_EXIST, 2);
04732 
04733         if (!cob_current_module->cob_procedure_parameters[0]) {
04734                 return -1;
04735         }
04736         fn = cob_str_from_fld (cob_current_module->cob_procedure_parameters[0]);
04737         if (stat (fn, &st) < 0) {
04738                 free (fn);
04739                 return 35;
04740         }
04741         free (fn);
04742         sz = st.st_size;
04743         tm = localtime (&st.st_mtime);
04744         d = (char) tm->tm_mday;
04745         m = (char) tm->tm_mon + 1;
04746         y = tm->tm_year + 1900;
04747         hh = (char) tm->tm_hour;
04748         mm = (char) tm->tm_min;
04749         ss = (char) tm->tm_sec;
04750 
04751 #ifndef WORDS_BIGENDIAN
04752         sz = COB_BSWAP_64 (sz);
04753         y = COB_BSWAP_16 (y);
04754 #endif
04755         memcpy (file_info, &sz, 8);
04756         file_info[8] = d;
04757         file_info[9] = m;
04758         memcpy (file_info+10, &y, 2);
04759         file_info[12] = hh;
04760         file_info[13] = mm;
04761         file_info[14] = ss;
04762         file_info[15] = 0;
04763         return 0;
04764 }
04765 
04766 int
04767 CBL_RENAME_FILE (unsigned char *fname1, unsigned char *fname2)
04768 {
04769         char    *fn1;
04770         char    *fn2;
04771         int     ret;
04772 
04773         COB_CHK_PARMS (CBL_RENAME_FILE, 2);
04774 
04775         if (!cob_current_module->cob_procedure_parameters[0]) {
04776                 return -1;
04777         }
04778         if (!cob_current_module->cob_procedure_parameters[1]) {
04779                 return -1;
04780         }
04781         fn1 = cob_str_from_fld (cob_current_module->cob_procedure_parameters[0]);
04782         fn2 = cob_str_from_fld (cob_current_module->cob_procedure_parameters[1]);
04783         ret = rename (fn1, fn2);
04784         free (fn1);
04785         free (fn2);
04786         if (ret) {
04787                 return 128;
04788         }
04789         return 0;
04790 }
04791 
04792 int
04793 CBL_GET_CURRENT_DIR (const int flags, const int dir_length, unsigned char *dir)
04794 {
04795         char    *dirname;
04796         int     dir_size;
04797         int     has_space;
04798 
04799         COB_CHK_PARMS (CBL_GET_CURRENT_DIR, 3);
04800 
04801         if (dir_length < 1) {
04802                 return 128;
04803         }
04804         if (flags) {
04805                 return 129;
04806         }
04807         memset (dir, ' ', (size_t)dir_length);
04808         dirname = getcwd (NULL, 0);
04809         if (dirname == NULL) {
04810                 return 128;
04811         }
04812         dir_size = (int) strlen (dirname);
04813         has_space = 0;
04814         if (strchr (dirname, ' ')) {
04815                 has_space = 2;
04816         }
04817         if (dir_size + has_space > dir_length) {
04818                 free (dirname);
04819                 return 128;
04820         }
04821         if (has_space) {
04822                 *dir = '"';
04823                 memcpy (&dir[1], dirname, (size_t)dir_size);
04824                 dir[dir_size + 1] = '"';
04825         } else {
04826                 memcpy (dir, dirname, (size_t)dir_size);
04827         }
04828         free (dirname);
04829         return 0;
04830 }
04831 
04832 int
04833 CBL_CREATE_DIR (unsigned char *dir)
04834 {
04835         char    *fn;
04836         int     ret;
04837 
04838         COB_CHK_PARMS (CBL_CREATE_DIR, 1);
04839 
04840         if (!cob_current_module->cob_procedure_parameters[0]) {
04841                 return -1;
04842         }
04843         fn = cob_str_from_fld (cob_current_module->cob_procedure_parameters[0]);
04844 #ifdef  _WIN32
04845         ret = mkdir (fn);
04846 #else
04847         ret = mkdir (fn, 0770);
04848 #endif
04849         free (fn);
04850         if (ret) {
04851                 return 128;
04852         }
04853         return 0;
04854 }
04855 
04856 int
04857 CBL_CHANGE_DIR (unsigned char *dir)
04858 {
04859         char    *fn;
04860         int     ret;
04861 
04862         COB_CHK_PARMS (CBL_CHANGE_DIR, 1);
04863 
04864         if (!cob_current_module->cob_procedure_parameters[0]) {
04865                 return -1;
04866         }
04867         fn = cob_str_from_fld (cob_current_module->cob_procedure_parameters[0]);
04868         ret = chdir (fn);
04869         free (fn);
04870         if (ret) {
04871                 return 128;
04872         }
04873         return 0;
04874 }
04875 
04876 int
04877 CBL_DELETE_DIR (unsigned char *dir)
04878 {
04879         char    *fn;
04880         int     ret;
04881 
04882         COB_CHK_PARMS (CBL_DELETE_DIR, 1);
04883 
04884         if (!cob_current_module->cob_procedure_parameters[0]) {
04885                 return -1;
04886         }
04887         fn = cob_str_from_fld (cob_current_module->cob_procedure_parameters[0]);
04888         ret = rmdir (fn);
04889         free (fn);
04890         if (ret) {
04891                 return 128;
04892         }
04893         return 0;
04894 }
04895 
04896 int
04897 cob_acuw_mkdir (unsigned char *dir)
04898 {
04899         int             ret;
04900 
04901         COB_CHK_PARMS (C$MAKEDIR, 1);
04902 
04903         ret = CBL_CREATE_DIR (dir);
04904         if (ret < 0) {
04905                 ret = 128;
04906         }
04907         return ret;
04908 }
04909 
04910 int
04911 cob_acuw_chdir (unsigned char *dir, unsigned char *status)
04912 {
04913         int             ret;
04914 
04915         COB_CHK_PARMS (C$CHDIR, 2);
04916 
04917         ret = CBL_CHANGE_DIR (dir);
04918         if (ret < 0) {
04919                 ret = 128;
04920         }
04921         cob_set_int (cob_current_module->cob_procedure_parameters[1], ret);
04922         return ret;
04923 }
04924 
04925 int
04926 cob_acuw_copyfile (unsigned char *fname1, unsigned char *fname2, unsigned char *file_type)
04927 {
04928         int             ret = 128;
04929 
04930         /* RXW - Type is not yet evaluated */
04931 
04932         COB_CHK_PARMS (C$COPY, 3);
04933 
04934         if (cob_call_params < 3) {
04935                 return 128;
04936         }
04937         ret = CBL_COPY_FILE (fname1, fname2);
04938         if (ret < 0) {
04939                 ret = 128;
04940         }
04941         return ret;
04942 }
04943 
04944 int
04945 cob_acuw_file_info (unsigned char *file_name, unsigned char *file_info)
04946 {
04947         char                    *fn;
04948         struct tm               *tm;
04949         unsigned long long      sz;
04950         unsigned int            dt;
04951         short                   y;
04952         short                   d, m, hh, mm, ss;
04953         struct stat             st;
04954 
04955         COB_CHK_PARMS (C$FILEINFO, 2);
04956 
04957         if (cob_call_params < 2 || !cob_current_module->cob_procedure_parameters[0]) {
04958                 return 128;
04959         }
04960         fn = cob_str_from_fld (cob_current_module->cob_procedure_parameters[0]);
04961         if (stat (fn, &st) < 0) {
04962                 free (fn);
04963                 return 35;
04964         }
04965         free (fn);
04966         sz = st.st_size;
04967         tm = localtime (&st.st_mtime);
04968         d = tm->tm_mday;
04969         m = tm->tm_mon + 1;
04970         y = tm->tm_year + 1900;
04971         hh = tm->tm_hour;
04972         mm = tm->tm_min;
04973         ss = tm->tm_sec;
04974 
04975 #ifndef WORDS_BIGENDIAN
04976         sz = COB_BSWAP_64 (sz);
04977 #endif
04978         memcpy (file_info, &sz, 8);
04979         dt = (y * 10000) + (m * 100) + d;
04980 #ifndef WORDS_BIGENDIAN
04981         dt = COB_BSWAP_32 (dt);
04982 #endif
04983         memcpy (file_info + 8, &dt, 4);
04984         dt = (hh * 1000000) + (mm * 10000) + (ss * 100);
04985 #ifndef WORDS_BIGENDIAN
04986         dt = COB_BSWAP_32 (dt);
04987 #endif
04988         memcpy (file_info + 12, &dt, 4);
04989         return 0;
04990 }
04991 
04992 int
04993 cob_acuw_file_delete (unsigned char *file_name, unsigned char *file_type)
04994 {
04995         int     ret;
04996 
04997         /* RXW - Type is not yet evaluated */
04998         COB_CHK_PARMS (C$DELETE, 2);
04999 
05000         if (cob_call_params < 2 || !cob_current_module->cob_procedure_parameters[0]) {
05001                 return 128;
05002         }
05003         ret = CBL_DELETE_FILE (file_name);
05004         if (ret < 0) {
05005                 ret = 128;
05006         }
05007         return ret;
05008 }
05009 
05010 /* SORT */
05011 
05012 static int
05013 sort_cmps (const unsigned char *s1, const unsigned char *s2, const size_t size,
05014                 const unsigned char *col)
05015 {
05016         size_t                  i;
05017         int                     ret;
05018 
05019         if (unlikely(col)) {
05020                 for (i = 0; i < size; i++) {
05021                         if ((ret = col[s1[i]] - col[s2[i]]) != 0) {
05022                                 return ret;
05023                         }
05024                 }
05025         } else {
05026                 for (i = 0; i < size; i++) {
05027                         if ((ret = s1[i] - s2[i]) != 0) {
05028                                 return ret;
05029                         }
05030                 }
05031         }
05032         return 0;
05033 }
05034 
05035 static COB_INLINE void
05036 unique_copy (unsigned char *s1, unsigned char *s2)
05037 {
05038         size_t  size = sizeof(size_t);
05039 
05040         do {
05041                 *s1++ = *s2++;
05042         } while (--size);
05043 }
05044 
05045 static int
05046 cob_file_sort_compare (struct cobitem *k1, struct cobitem *k2, void *pointer)
05047 {
05048         cob_file        *f;
05049         size_t          i;
05050         int             cmp;
05051         size_t          u1;
05052         size_t          u2;
05053         cob_field       f1;
05054         cob_field       f2;
05055 
05056         f = pointer;
05057         for (i = 0; i < f->nkeys; i++) {
05058                 f1 = f2 = *(f->keys[i].field);
05059                 f1.data = k1->item + f->keys[i].offset;
05060                 f2.data = k2->item + f->keys[i].offset;
05061                 if (COB_FIELD_IS_NUMERIC(&f1)) {
05062                         cmp = cob_numeric_cmp (&f1, &f2);
05063                 } else {
05064                         cmp = sort_cmps (f1.data, f2.data, f1.size, f->sort_collating);
05065                 }
05066                 if (cmp != 0) {
05067                         return (f->keys[i].flag == COB_ASCENDING) ? cmp : -cmp;
05068                 }
05069         }
05070         unique_copy ((unsigned char *)&u1, k1->unique);
05071         unique_copy ((unsigned char *)&u2, k2->unique);
05072         if (u1 < u2) {
05073                 return -1;
05074         }
05075         return 1;
05076 }
05077 
05078 static void
05079 cob_free_list (struct cobitem *q)
05080 {
05081         struct cobitem  *next;
05082 
05083         while (q != NULL) {
05084                 next = q->next;
05085                 free (q);
05086                 q = next;
05087         }
05088 }
05089 
05090 static struct cobitem *
05091 cob_new_item (struct cobsort *hp, size_t size)
05092 {
05093         struct cobitem *q;
05094 
05095         if (hp->empty != NULL) {
05096                 q = hp->empty;
05097                 hp->empty = q->next;
05098         } else {
05099                 q = cob_malloc (size);
05100         }
05101         return q;
05102 }
05103 
05104 static FILE * COB_NOINLINE
05105 cob_tmpfile (void)
05106 {
05107         FILE            *fp;
05108         const char      *s;
05109         int             fd;
05110         char            *filename;
05111 #ifdef _WIN32
05112         char            *tmpdir;
05113 #endif
05114 
05115         filename = cob_malloc (COB_MEDIUM_BUFF);
05116 
05117 #ifdef _WIN32
05118         /* get temporary directory */
05119         tmpdir = cob_malloc (COB_MEDIUM_BUFF);
05120         if ((s = getenv ("TMPDIR")) != NULL ||
05121             (s = getenv ("TMP")) != NULL ||
05122             (s = getenv ("TEMP")) != NULL) {
05123                 strncpy (tmpdir, s, COB_MEDIUM_MAX);
05124         } else {
05125                 GetTempPath (COB_MEDIUM_BUFF, tmpdir);
05126         }
05127         /* get temporary file name */
05128         GetTempFileName (tmpdir, "cob", 0, filename);
05129         DeleteFile (filename);
05130         free (tmpdir);
05131         fd = _open (filename, _O_CREAT | _O_TRUNC | _O_RDWR | _O_BINARY, 0660);
05132 #else
05133         if ((s = getenv ("TMPDIR")) == NULL &&
05134             (s = getenv ("TMP")) == NULL &&
05135             (s = getenv ("TEMP")) == NULL) {
05136                 s = "/tmp";
05137         }
05138         if (cob_process_id == 0) {
05139                 cob_process_id = getpid ();
05140         }
05141         snprintf (filename, COB_MEDIUM_MAX, "%s/cobsort%d_%d",
05142                   s, cob_process_id, cob_iteration);
05143         cob_iteration++;
05144         fd = open (filename, O_CREAT | O_TRUNC | O_RDWR | O_BINARY | O_LARGEFILE, 0660);
05145 #endif
05146         if (fd < 0) {
05147                 free (filename);
05148                 return NULL;
05149         }
05150 #ifdef _WIN32
05151         _unlink (filename);
05152         fp = _fdopen (fd, "w+b");
05153         if (!fp) {
05154                 _close (fd);
05155         }
05156 #else
05157         unlink (filename);
05158         fp = fdopen (fd, "w+b");
05159         if (!fp) {
05160                 close (fd);
05161         }
05162 #endif
05163         free (filename);
05164         return fp;
05165 }
05166 
05167 static int COB_NOINLINE
05168 cob_get_temp_file (struct cobsort *hp, const int n)
05169 {
05170         if (hp->file[n].fp == NULL) {
05171                 hp->file[n].fp = cob_tmpfile ();
05172                 if (hp->file[n].fp == NULL) {
05173                         cob_runtime_error ("SORT is unable to acquire temporary file");
05174                         cob_stop_run (1);
05175                 }
05176         } else {
05177                 rewind (hp->file[n].fp);
05178         }
05179         hp->file[n].count = 0;
05180         return hp->file[n].fp == NULL;
05181 }
05182 
05183 static int
05184 cob_sort_queues (struct cobsort *hp)
05185 {
05186         struct cobitem  *q;
05187         int             source = 0;
05188         int             destination;
05189         int             move;
05190         int             n;
05191         int             end_of_block[2];
05192 
05193         while (hp->queue[source + 1].count != 0) {
05194                 destination = source ^ 2;
05195                 hp->queue[destination].count = hp->queue[destination + 1].count = 0;
05196                 hp->queue[destination].first = hp->queue[destination + 1].first = NULL;
05197                 while (1) {
05198                         end_of_block[0] = hp->queue[source].count == 0;
05199                         end_of_block[1] = hp->queue[source + 1].count == 0;
05200                         if (end_of_block[0] && end_of_block[1]) {
05201                                 break;
05202                         }
05203                         while (!end_of_block[0] || !end_of_block[1]) {
05204                                 if (end_of_block[0]) {
05205                                         move = 1;
05206                                 } else if (end_of_block[1]) {
05207                                         move = 0;
05208                                 } else {
05209                                         n = cob_file_sort_compare
05210                                                 (hp->queue[source].first,
05211                                                 hp->queue[source + 1].first,
05212                                                 hp->pointer);
05213                                         move = n < 0 ? 0 : 1;
05214                                 }
05215                                 q = hp->queue[source + move].first;
05216                                 if (q->end_of_block) {
05217                                         end_of_block[move] = 1;
05218                                 }
05219                                 hp->queue[source + move].first = q->next;
05220                                 if (hp->queue[destination].first == NULL) {
05221                                         hp->queue[destination].first = q;
05222                                 } else {
05223                                         hp->queue[destination].last->next = q;
05224                                 }
05225                                 hp->queue[destination].last = q;
05226                                 hp->queue[source + move].count--;
05227                                 hp->queue[destination].count++;
05228                                 q->next = NULL;
05229                                 q->end_of_block = 0;
05230                         }
05231                         hp->queue[destination].last->end_of_block = 1;
05232                         destination ^= 1;
05233                 }
05234                 source = destination & 2;
05235         }
05236         return source;
05237 }
05238 
05239 static int
05240 cob_read_item (struct cobsort *hp, const int n)
05241 {
05242         FILE    *fp = hp->file[n].fp;
05243 
05244         if (getc (fp) != 0) {
05245                 hp->queue[n].first->end_of_block = 1;
05246         } else {
05247                 hp->queue[n].first->end_of_block = 0;
05248                 if (unlikely(fread (hp->queue[n].first->unique, hp->r_size, 1, fp) != 1)) {
05249                         return 1;
05250                 }
05251         }
05252         return 0;
05253 }
05254 
05255 static int
05256 cob_write_block (struct cobsort *hp, const int n)
05257 {
05258         struct cobitem  *q;
05259         FILE            *fp = hp->file[hp->destination_file].fp;
05260 
05261         while (1) {
05262                 q = hp->queue[n].first;
05263                 if (q == NULL) {
05264                         break;
05265                 }
05266                 if (unlikely(fwrite (&(q->block_byte), hp->w_size, 1, fp) != 1)) {
05267                         return 1;
05268                 }
05269                 hp->queue[n].first = q->next;
05270                 q->next = hp->empty;
05271                 hp->empty = q;
05272         }
05273         hp->queue[n].count = 0;
05274         hp->file[hp->destination_file].count++;
05275         if (putc (1, fp) != 1) {
05276                 return 1;
05277         }
05278         return 0;
05279 }
05280 
05281 static void
05282 cob_copy_check (cob_file *to, cob_file *from)
05283 {
05284         unsigned char   *toptr;
05285         unsigned char   *fromptr;
05286         size_t          tosize;
05287         size_t          fromsize;
05288 
05289         toptr = to->record->data;
05290         fromptr = from->record->data;
05291         tosize = to->record->size;
05292         fromsize = from->record->size;
05293         if (unlikely(tosize > fromsize)) {
05294                 memcpy (toptr, fromptr, fromsize);
05295                 memset (toptr + fromsize, ' ', tosize - fromsize);
05296         } else {
05297                 memcpy (toptr, fromptr, tosize);
05298         }
05299 }
05300 
05301 static int
05302 cob_file_sort_process (struct cobsort *hp)
05303 {
05304         int     i;
05305         int     source;
05306         int     destination;
05307         int     n;
05308         int     move;
05309         int     res;
05310 
05311         hp->retrieving = 1;
05312         n = cob_sort_queues (hp);
05313 /* RXW - Cannot be true
05314         if (unlikely(n < 0)) {
05315                 return COBSORTABORT;
05316         }
05317 */
05318         if (likely(!hp->files_used)) {
05319                 hp->retrieval_queue = n;
05320                 return 0;
05321         }
05322         if (unlikely(cob_write_block (hp, n))) {
05323                 return COBSORTFILEERR;
05324         }
05325         for (i = 0; i < 4; i++) {
05326                 hp->queue[i].first = hp->empty;
05327                 hp->empty = hp->empty->next;
05328                 hp->queue[i].first->next = NULL;
05329         }
05330         rewind (hp->file[0].fp);
05331         rewind (hp->file[1].fp);
05332         if (unlikely(cob_get_temp_file (hp, 2))) {
05333                 return COBSORTFILEERR;
05334         }
05335         if (unlikely(cob_get_temp_file (hp, 3))) {
05336                 return COBSORTFILEERR;
05337         }
05338         source = 0;
05339         while (hp->file[source].count > 1) {
05340                 destination = source ^ 2;
05341                 hp->file[destination].count = 0;
05342                 hp->file[destination + 1].count = 0;
05343                 while (hp->file[source].count > 0) {
05344                         if (unlikely(cob_read_item (hp, source))) {
05345                                 return COBSORTFILEERR;
05346                         }
05347                         if (hp->file[source + 1].count > 0) {
05348                                 if (unlikely(cob_read_item (hp, source + 1))) {
05349                                         return COBSORTFILEERR;
05350                                 }
05351                         } else {
05352                                 hp->queue[source + 1].first->end_of_block = 1;
05353                         }
05354                         while (!hp->queue[source].first->end_of_block
05355                                || !hp->queue[source + 1].first->end_of_block) {
05356                                 if (hp->queue[source].first->end_of_block) {
05357                                         move = 1;
05358                                 } else if (hp->queue[source + 1].first->end_of_block) {
05359                                         move = 0;
05360                                 } else {
05361                                         res = cob_file_sort_compare
05362                                                 (hp->queue[source].first,
05363                                                 hp->queue[source + 1].first,
05364                                                 hp->pointer);
05365                                         move = res < 0 ? 0 : 1;
05366                                 }
05367                                 if (unlikely(fwrite (
05368                                     &(hp->queue[source + move].first->block_byte),
05369                                     hp->w_size, 1,
05370                                     hp->file[destination].fp) != 1)) {
05371                                         return COBSORTFILEERR;
05372                                 }
05373                                 if (unlikely(cob_read_item (hp, source + move))) {
05374                                         return COBSORTFILEERR;
05375                                 }
05376                         }
05377                         hp->file[destination].count++;
05378                         if (unlikely(putc (1, hp->file[destination].fp) != 1)) {
05379                                 return COBSORTFILEERR;
05380                         }
05381                         hp->file[source].count--;
05382                         hp->file[source + 1].count--;
05383                         destination ^= 1;
05384                 }
05385                 source = destination & 2;
05386                 rewind (hp->file[0].fp);
05387                 rewind (hp->file[1].fp);
05388                 rewind (hp->file[2].fp);
05389                 rewind (hp->file[3].fp);
05390         }
05391         hp->retrieval_queue = source;
05392         if (unlikely(cob_read_item (hp, source))) {
05393                 return COBSORTFILEERR;
05394         }
05395         if (unlikely(cob_read_item (hp, source + 1))) {
05396                 return COBSORTFILEERR;
05397         }
05398         return 0;
05399 }
05400 
05401 static int
05402 cob_file_sort_submit (cob_file *f, const unsigned char *p)
05403 {
05404         struct cobsort          *hp;
05405 /* RXW - See comment lines below
05406         size_t                  i;
05407 */
05408         struct cobitem          *q;
05409         struct memory_struct    *z;
05410         int                     n;
05411 
05412         hp = f->file;
05413         if (unlikely(!hp)) {
05414                 return COBSORTNOTOPEN;
05415         }
05416         if (unlikely(hp->retrieving)) {
05417                 return COBSORTABORT;
05418 /* RXW - This was a facility to submit new items after retrieval had begun
05419                 for (i = 0; i < 4; i++) {
05420                         if (hp->queue[i].first != NULL) {
05421                                 hp->queue[i].last->next = hp->empty;
05422                                 hp->empty = hp->queue[i].first;
05423                                 hp->queue[i].first = NULL;
05424                         }
05425                 }
05426                 hp->queue[0].count = hp->queue[1].count = 0;
05427                 hp->destination_file = -1;
05428                 hp->retrieving = 0;
05429                 hp->files_used = 0;
05430 */
05431         }
05432         if (hp->queue[0].count + hp->queue[1].count >= hp->memory) {
05433                 if (!hp->files_used) {
05434                         if (unlikely(cob_get_temp_file (hp, 0))) {
05435                                 return COBSORTFILEERR;
05436                         }
05437                         if (unlikely(cob_get_temp_file (hp, 1))) {
05438                                 return COBSORTFILEERR;
05439                         }
05440                         hp->files_used = 1;
05441                         hp->destination_file = 0;
05442                 }
05443                 n = cob_sort_queues (hp);
05444 /* RXW - Cannot be true
05445                 if (unlikely(n < 0)) {
05446                         return COBSORTABORT;
05447                 }
05448 */
05449                 if (unlikely(cob_write_block (hp, n))) {
05450                         return COBSORTFILEERR;
05451                 }
05452                 hp->destination_file ^= 1;
05453         }
05454         q = cob_new_item (hp, sizeof (struct cobitem) + hp->size);
05455         q->end_of_block = 1;
05456         unique_copy (q->unique, (unsigned char *)&(hp->unique));
05457         hp->unique++;
05458         memcpy (q->item, p, hp->size);
05459         if (hp->queue[0].count <= hp->queue[1].count) {
05460                 z = &hp->queue[0];
05461         } else {
05462                 z = &hp->queue[1];
05463         }
05464         q->next = z->first;
05465         z->first = q;
05466         z->count++;
05467         return 0;
05468 }
05469 
05470 static int
05471 cob_file_sort_retrieve (cob_file *f, unsigned char *p)
05472 {
05473         struct cobsort          *hp;
05474         struct cobitem          *next;
05475         struct memory_struct    *z;
05476         int                     move;
05477         int                     source;
05478         int                     res;
05479 
05480         hp = f->file;
05481         if (unlikely(!hp)) {
05482                 return COBSORTNOTOPEN;
05483         }
05484         if (unlikely(!hp->retrieving)) {
05485                 res = cob_file_sort_process (hp);
05486                 if (res) {
05487                         return res;
05488                 }
05489         }
05490         if (unlikely(hp->files_used)) {
05491                 source = hp->retrieval_queue;
05492                 if (hp->queue[source].first->end_of_block) {
05493                         if (hp->queue[source + 1].first->end_of_block) {
05494                                 return COBSORTEND;
05495                         }
05496                         move = 1;
05497                 } else if (hp->queue[source + 1].first->end_of_block) {
05498                         move = 0;
05499                 } else {
05500                         res = cob_file_sort_compare (hp->queue[source].first,
05501                                                 hp->queue[source + 1].first,
05502                                                 hp->pointer);
05503                         move = res < 0 ? 0 : 1;
05504                 }
05505                 memcpy (p, hp->queue[source + move].first->item, hp->size);
05506                 if (unlikely(cob_read_item (hp, source + move))) {
05507                         return COBSORTFILEERR;
05508                 }
05509         } else {
05510                 z = &hp->queue[hp->retrieval_queue];
05511                 if (z->first == NULL) {
05512                         return COBSORTEND;
05513                 }
05514                 memcpy (p, z->first->item, hp->size);
05515                 next = z->first->next;
05516                 z->first->next = hp->empty;
05517                 hp->empty = z->first;
05518                 z->first = next;
05519         }
05520         return 0;
05521 }
05522 
05523 void
05524 cob_file_sort_using (cob_file *sort_file, cob_file *data_file)
05525 {
05526         int             ret;
05527 
05528         cob_open (data_file, COB_OPEN_INPUT, 0, NULL);
05529         while (1) {
05530                 cob_read (data_file, NULL, NULL, COB_READ_NEXT);
05531                 if (data_file->file_status[0] != '0') {
05532                         break;
05533                 }
05534                 cob_copy_check (sort_file, data_file);
05535                 ret = cob_file_sort_submit (sort_file, sort_file->record->data);
05536                 if (ret) {
05537                         break;
05538                 }
05539         }
05540         cob_close (data_file, COB_CLOSE_NORMAL, NULL);
05541 }
05542 
05543 void
05544 cob_file_sort_giving (cob_file *sort_file, const size_t varcnt, ...)
05545 {
05546         cob_file        **fbase;
05547         struct cobsort  *hp;
05548         size_t          i;
05549         int             ret;
05550         int             opt;
05551         va_list         args;
05552 
05553         fbase = cob_malloc (varcnt * sizeof(cob_file *));
05554         va_start (args, varcnt);
05555         for (i = 0; i < varcnt; i++) {
05556                 fbase[i] = va_arg (args, cob_file *);
05557         }
05558         va_end (args);
05559         for (i = 0; i < varcnt; i++) {
05560                 cob_open (fbase[i], COB_OPEN_OUTPUT, 0, NULL);
05561         }
05562         while (1) {
05563                 ret = cob_file_sort_retrieve (sort_file, sort_file->record->data);
05564                 if (ret) {
05565                         if (ret == COBSORTEND) {
05566                                 sort_file->file_status[0] = '1';
05567                                 sort_file->file_status[1] = '0';
05568                         } else {
05569                                 hp = sort_file->file;
05570                                 *(int *)(hp->sort_return) = 16;
05571                                 sort_file->file_status[0] = '3';
05572                                 sort_file->file_status[1] = '0';
05573                         }
05574                         break;
05575                 }
05576                 for (i = 0; i < varcnt; i++) {
05577                         if (fbase[i]->special ||
05578                             fbase[i]->organization == COB_ORG_LINE_SEQUENTIAL) {
05579                                 opt = COB_WRITE_BEFORE | COB_WRITE_LINES | 1;
05580                         } else {
05581                                 opt = 0;
05582                         }
05583                         cob_copy_check (fbase[i], sort_file);
05584                         cob_write (fbase[i], fbase[i]->record, opt, NULL);
05585                 }
05586         }
05587         for (i = 0; i < varcnt; i++) {
05588                 cob_close (fbase[i], COB_CLOSE_NORMAL, NULL);
05589         }
05590         free (fbase);
05591 }
05592 
05593 void
05594 cob_file_sort_init (cob_file *f, const int nkeys,
05595                     const unsigned char *collating_sequence,
05596                     void *sort_return, cob_field *fnstatus)
05597 {
05598         struct cobsort  *p;
05599 
05600         p = cob_malloc (sizeof (struct cobsort));
05601         p->fnstatus = fnstatus;
05602         p->size = f->record_max;
05603         p->r_size = f->record_max + sizeof(size_t);
05604         p->w_size = f->record_max + sizeof(size_t) + 1;
05605         p->pointer = f;
05606         p->sort_return = sort_return;
05607         *(int *)sort_return = 0;
05608         p->memory = (size_t)cob_sort_memory / (p->size + sizeof(struct cobitem));
05609         f->file = p;
05610         f->keys = cob_malloc (sizeof (struct cob_file_key) * nkeys);
05611         f->nkeys = 0;
05612         if (collating_sequence) {
05613                 f->sort_collating = collating_sequence;
05614         } else {
05615                 f->sort_collating = cob_current_module->collating_sequence;
05616         }
05617         RETURN_STATUS (COB_STATUS_00_SUCCESS);
05618 }
05619 
05620 void
05621 cob_file_sort_init_key (cob_file *f, const int flag, cob_field *field,
05622                         size_t offset)
05623 {
05624         f->keys[f->nkeys].flag = flag;
05625         f->keys[f->nkeys].field = field;
05626         f->keys[f->nkeys].offset = offset;
05627         f->nkeys++;
05628 }
05629 
05630 void
05631 cob_file_sort_close (cob_file *f)
05632 {
05633         struct cobsort  *hp;
05634         cob_field       *fnstatus = NULL;
05635         size_t          i;
05636 
05637         hp = f->file;
05638         if (likely(hp)) {
05639                 fnstatus = hp->fnstatus;
05640                 cob_free_list (hp->empty);
05641                 for (i = 0; i < 4; i++) {
05642                         cob_free_list (hp->queue[i].first);
05643                         if (hp->file[i].fp != NULL) {
05644                                 fclose (hp->file[i].fp);
05645                         }
05646                 }
05647                 free (hp);
05648         }
05649         f->file = NULL;
05650         RETURN_STATUS (COB_STATUS_00_SUCCESS);
05651 }
05652 
05653 void
05654 cob_file_release (cob_file *f)
05655 {
05656         struct cobsort  *hp;
05657         cob_field       *fnstatus = NULL;
05658         int             ret;
05659 
05660         hp = f->file;
05661         if (likely(hp)) {
05662                 fnstatus = hp->fnstatus;
05663         }
05664         ret = cob_file_sort_submit (f, f->record->data);
05665         switch (ret) {
05666         case 0:
05667                 RETURN_STATUS (COB_STATUS_00_SUCCESS);
05668                 break;
05669         default:
05670                 if (likely(hp)) {
05671                         *(int *)(hp->sort_return) = 16;
05672                 }
05673                 RETURN_STATUS (COB_STATUS_30_PERMANENT_ERROR);
05674                 break;
05675         }
05676 }
05677 
05678 void
05679 cob_file_return (cob_file *f)
05680 {
05681         struct cobsort  *hp;
05682         cob_field       *fnstatus = NULL;
05683         int             ret;
05684 
05685         hp = f->file;
05686         if (likely(hp)) {
05687                 fnstatus = hp->fnstatus;
05688         }
05689         ret = cob_file_sort_retrieve (f, f->record->data);
05690         switch (ret) {
05691         case 0:
05692                 RETURN_STATUS (COB_STATUS_00_SUCCESS);
05693                 break;
05694         case COBSORTEND:
05695                 RETURN_STATUS (COB_STATUS_10_END_OF_FILE);
05696                 break;
05697         default:
05698                 if (likely(hp)) {
05699                         *(int *)(hp->sort_return) = 16;
05700                 }
05701                 RETURN_STATUS (COB_STATUS_30_PERMANENT_ERROR);
05702                 break;
05703         }
05704 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines