OpenCOBOL 1.1pre-rel
|
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 }