Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / DtSearch / raima / dio.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*
24  *   COMPONENT_NAME: austext
25  *
26  *   FUNCTIONS: EXCL_OPEN
27  *              Pi
28  *              cache_init
29  *              clear_cache
30  *              d_setfiles
31  *              d_setpages
32  *              dio_clear
33  *              dio_close
34  *              dio_clrfile
35  *              dio_findpg
36  *              dio_flush
37  *              dio_free
38  *              dio_get
39  *              dio_in
40  *              dio_init
41  *              dio_open
42  *              dio_out
43  *              dio_pzalloc
44  *              dio_pzclr
45  *              dio_pzdel
46  *              dio_pzflush
47  *              dio_pzgetts
48  *              dio_pzinit
49  *              dio_pznext
50  *              dio_pzread
51  *              dio_pzsetts
52  *              dio_read
53  *              dio_release
54  *              dio_rrlb
55  *              dio_setdef
56  *              dio_touch
57  *              dio_write
58  *              dio_wrlb
59  *
60  *   ORIGINS: 27, 157
61  *
62  *   This module contains IBM CONFIDENTIAL code. -- (IBM
63  *   Confidential Restricted when combined with the aggregated
64  *   modules for this product)
65  *
66  *   OBJECT CODE ONLY SOURCE MATERIALS
67  *   (C) COPYRIGHT International Business Machines Corp. 1995, 1996
68  *   All Rights Reserved
69  *   US Government Users Restricted Rights - Use, duplication or
70  *   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
71  */
72 /*------------------------------------------------------------------------
73  $XConsortium: dio.c /main/7 1996/11/25 18:48:24 drk $
74    dio - Database Input/Output Control Functions
75
76    Copyright (C) 1984, 1985, 1986, 1987 by Raima Corporation
77 ------------------------------------------------------------------------*/
78
79 /* ********************** EDIT HISTORY *******************************
80
81  SCR    DATE    INI                   DESCRIPTION
82 ----- --------- --- -----------------------------------------------------
83    76 16-JUN-88 RSC Clean up so SINGLE_USER produces good code
84   240 20-Jun-88 RSC Clean up so NO_TRANS produces good code
85   103 24-Jun-88 RSC Improve generation of single user version
86   295 01-Jul-88 RSC make cnt_open_files global, to support initial.c mods
87   333 05-Jul-88 RSC make wrlb only fiddle with rlb, not entire rid
88   115 18-Jul-88 RSC Integrate VAX VMS changes into master code
89   366 25-Jul-88 RSC dio_pzread should use dio_open, not DB_OPEN
90       04-Aug-88 RTK MULTI_TASK changes
91       11-Aug-88 RTK d_setpages and d_setfiles must return immediately if
92                     another task already has opened a database.
93   115 16-Aug-88 RSC Fixup of VMS integration
94   423 10-Sep-88 RSC Fixup of multi-task compile problems
95   420 15-Sep-88 RTK Encompassed calls to dio_unlock within an ifdef MEMLOCK
96   423 15-Sep-88 RSC Also cleared last_dblu in clear_cache
97   423 15-Sep-88 RSC Removed '#' from ifdef two lines up - vpp no like!!!!!
98   420 16-Sep-88 RTK A couple missing FAR's
99   425 05-Oct-88 RSC d_trabort wasn't completely clearing page zero, added
100                     dio_pzclr to support d_trabort
101   433 31-Oct-88 RSC Fix for SCR #423 wasn't quite right - query wouldn't run
102   532 06-Jan-89 RSC Fix code so NO_TRANS compiles correctly
103       08-Feb-89 RSC Fix from AMCY - clear cache wasn't completely swapping.
104   420 13-Feb-89 WLW Cleared last_dblu in clear_cache (only safe thing to do)
105       14-Feb-89 RSC Misc fixes
106   588 16-Feb-89 RSC remove ifndef SINGLE_USER around CLOSE_FILES
107   612 21-Feb-89 RSC always clear ovfl_addr in dbpg_table
108   619 09-Mar-89 WLW call o_fileinit from dio_pzgetts, don't call dio_pzsetts
109                     from dio_pzread.
110       05-May-89 WLW Added ".v" tag to Currtask for MULTI_TASKing
111
112  $Log$
113  * Revision 1.2  1995/10/17  19:15:37  miker
114  * Changed open mode from hardcoded O_RDWR to global var db_oflag.
115  *
116 */
117
118 #include <stdio.h>
119 #include <fcntl.h>
120 #include "vista.h"
121 #include "dbtype.h"
122 #include "dbswab.h"
123
124 #define DEBUG_DIO
125 #ifdef DEBUG_DIO
126 int     debugging_dio_init = FALSE;
127 int     debugging_dio_close = FALSE;
128 #endif
129
130 #ifndef NO_TRANS
131
132 /* On MS-DOS networks, files must be closed whenever a lock is freed.
133    Function dio_clrfile is called whenever a lock is freed to clear
134    from the cache the pages of the file whose lock is being freed.
135    CLosing and opening files on Unix, VMS and other host computers, 
136    however, is very slow and is not necessary for database integrity.
137    The following constant definition specifies whether or not the files
138    need to be closed.   A definition per supported MS-DOS compiler is 
139    required.
140 */
141 #ifdef MSC
142 #define CLOSE_FILES
143 #endif
144 #ifdef LAT
145 #define CLOSE_FILES
146 #endif
147 #ifdef WIZ
148 #define CLOSE_FILES
149 #endif
150 #ifdef TURBO
151 #define CLOSE_FILES
152 #endif
153 /*------------ transaction logging data ------------*/
154 #define DEFIXPAGES 4          /* default number of index cache pages */
155 #define MINIXPAGES 2          /* minimum number of index cache pages */
156 int ix_pgtab_sz = DEFIXPAGES;
157 LOOKUP_ENTRY_P Ix_lookup = POINTER_INIT(); /* index page lookup table */
158 PAGE_ENTRY_P Ixpg_table = POINTER_INIT(); /* index page table */
159 static int ixpg_lru_slot;     /* least recently accessed ix page */
160
161 /* transaction logging enabled flag */
162 int trlog_flag = 0;  /* set only by user implemented functions */
163
164 BOOLEAN use_ovfl = YES;        /* Default to using overflow */
165 CHAR_P Dbpgbuff = POINTER_INIT();  /* allocated by dio_init used by o_update */
166 /*------------ end of transaction logging data ------------*/
167 #endif          /* NO_TRANS */
168
169 #ifndef SINGLE_USER
170 #define EXCL_OPEN()     (dbopen >= 2)
171 #else
172 #define EXCL_OPEN()     (TRUE)
173 #endif
174
175 #define DEFDBPAGES 16         /* default number of database cache pages */
176 #define MINDBPAGES 8          /* minimum number of database cache pages */
177
178 extern BOOLEAN trcommit;
179
180 int db_pgtab_sz = DEFDBPAGES;
181
182 LOOKUP_ENTRY_P Db_lookup = POINTER_INIT(); /* database page lookup table */
183 PAGE_ENTRY_P Dbpg_table = POINTER_INIT(); /* database page table */
184 static struct
185 {
186 #ifdef MULTI_TASK
187    TASK FAR *task;
188 #endif
189    FILE_NO file;
190    F_ADDR pageno;
191    int slot;
192 } last_dblu;                  /* last found lookup entry in cache */
193
194 /* maximum number of open files allowed by
195    operating system (user settable) */
196 /* On VMS systems, max_open_files need to be defined with a globaldef
197    instead of just a normal external.  This will force this module to be
198    included, thus giving a default value to max_open_files.  If it were
199    just a normal external the VMS linker would not load this module unless
200    a reference to a function in it is made and it would leave max_open_files
201    with a value of 0. */
202 int max_open_files = 8; 
203 INT_P Used_files = POINTER_INIT(); /* LRU file table */
204 int cnt_open_files = 0;    /* count of currently open files */
205 static int last_file = 0;     /* least recently used file */
206
207 static int dbpg_lru_slot;      /* least recently accessed db page */
208 static int no_modheld;         /* number of modified or held db pages */
209 static FILE_NO working_file;   /* current key file being processed */
210
211 static void cache_init(P1(int) Pi(LOOKUP_ENTRY FAR *)
212                                       Pi(PAGE_ENTRY FAR *) Pi(int));
213 static int dio_pzinit(P0);
214 static int clear_cache(P1(FILE_NO) Pi(FILE_NO));
215 static int dio_pzflush(P0);
216 #ifdef NO_TRANS
217 static int dio_in(P1(PAGE_ENTRY FAR *) Pi(LOOKUP_ENTRY FAR *));
218 #else
219 static int dio_in(P1(PAGE_ENTRY FAR *) Pi(LOOKUP_ENTRY FAR *)
220                                  Pi(BOOLEAN));
221 #endif
222
223 #define used_files Used_files.ptr
224 #define db_lookup Db_lookup.ptr
225 #define dbpg_table Dbpg_table.ptr
226
227
228
229 /* Set the maximum number of open db_VISTA files
230 */
231 d_setfiles(num)
232 int num;
233 {
234    if ( dbpg_table ) return( dberr(S_DBCLOSE) );
235
236    if ( num > 0 && num < 256 )
237       max_open_files = num;
238
239    return( db_status = S_OKAY );
240 }
241
242
243 /* Set number of virtual memory pages
244 */
245 d_setpages(dbpgs, ixpgs)
246 int dbpgs; /* # of db cache pages */
247 int ixpgs; /* # of index cache pages - ignored in single-user version */
248 {
249    if ( dbpg_table ) return( dberr(S_SETPAGES) );
250
251    db_pgtab_sz = (dbpgs <= MINDBPAGES) ? MINDBPAGES : dbpgs;
252
253 #ifndef NO_TRANS
254    if ( use_ovfl ) {
255       ix_pgtab_sz = (ixpgs <= MINIXPAGES) ? MINIXPAGES : ixpgs;
256    }
257 #endif
258    return( db_status = S_OKAY );
259 }
260
261
262 /****************************************/
263 /*                                      */
264 /*              dio_open                */
265 /*                                      */
266 /****************************************/
267 /* Open a database file
268 */
269 dio_open( fno )
270 FILE_NO fno;
271 {
272    FILE_ENTRY FAR *file_ptr, FAR *lru_file_ptr;
273    register int FAR *uf_ptr;
274
275    file_ptr = &file_table[fno];
276    if ( file_ptr->ft_status == CLOSED ) {
277       if ( cnt_open_files == max_open_files ) {
278          /* find least recently used file */
279          uf_ptr = &used_files[last_file];
280          lru_file_ptr = &file_table[last_file];
281          while (*uf_ptr || (lru_file_ptr->ft_status == CLOSED)) {
282             *uf_ptr = FALSE;
283             if (++last_file >= size_ft) {
284                last_file = 0;
285                lru_file_ptr = file_table;
286                uf_ptr = used_files;
287             }
288             else {
289               ++lru_file_ptr;
290               ++uf_ptr;
291            }
292          }
293          dio_close(last_file);
294          if (++last_file >= size_ft)
295             last_file = 0;
296       }
297       used_files[fno] = TRUE;
298
299          file_ptr->ft_desc = open_b(file_ptr->ft_name, db_oflag);
300       if (file_ptr->ft_desc < 0)
301          return( dberr( S_NOFILE ) );
302       file_ptr->ft_status = OPEN;
303       ++cnt_open_files;
304    }
305    return( db_status = S_OKAY );
306 } /* dio_open() */
307
308
309 /****************************************/
310 /*                                      */
311 /*              dio_close               */
312 /*                                      */
313 /****************************************/
314 /* Close a database file
315 */
316 dio_close( fno )
317 FILE_NO fno;
318 {
319    FILE_ENTRY FAR *file_ptr;
320
321    file_ptr = &file_table[fno];
322    if ( file_ptr->ft_status == OPEN ) {
323       DB_CLOSE( file_ptr->ft_desc );
324       file_ptr->ft_status = CLOSED;
325       --cnt_open_files;
326    }
327    return( db_status = S_OKAY );
328 }
329
330
331 /****************************************/
332 /*                                      */
333 /*              dio_init                */
334 /*                                      */
335 /****************************************/
336 /* Initialize database I/O
337 */
338 dio_init()
339 {
340    CHAR_P Tempbuff;
341 #define tempbuff Tempbuff.ptr
342
343 #ifdef DEBUG_DIO
344     if (debugging_dio_init) {
345         printf (__FILE__"300 dio_init: dbpgtab=%p pgsz=%d largest=%d\n",
346             dbpg_table, (int)page_size, (int)largest_page);
347         fflush(stdout);
348     }
349 #endif
350
351    if ( dbpg_table ) {
352       if ( dio_pzinit() != S_OKAY ) {
353          return( db_status );
354       }
355       if ( page_size > largest_page ) {
356          if ( (tempbuff = ALLOC(&Tempbuff, page_size, "tempbuff")) == NULL )
357             return( dberr(S_NOMEMORY) );
358 #ifndef NO_TRANS
359          MEM_UNLOCK(&Dbpgbuff);
360          FREE(&Dbpgbuff);
361          Dbpgbuff = Tempbuff;
362 #endif
363          largest_page = page_size;
364       }
365 #ifdef DEBUG_DIO
366       if (debugging_dio_init) {
367         printf (__FILE__"323 dio_init: pzinited ok. pgsz=%d largest=%d\n",
368             (int)page_size, (int)largest_page);
369         fflush(stdout);
370       }
371 #endif
372
373       return( S_OKAY );
374    } /* end if ( dbpg_table ) */
375
376    used_files =
377         /* Macro references must be on one line for some compilers */ 
378         (int FAR *)ALLOC(&Used_files, (size_ft+1)*sizeof(int), "used_files");
379    db_lookup =
380         /* Macro references must be on one line for some compilers */ 
381         (LOOKUP_ENTRY FAR *)
382         ALLOC(&Db_lookup, db_pgtab_sz*sizeof(LOOKUP_ENTRY), "db_lookup");
383    dbpg_table =
384         /* Macro references must be on one line for some compilers */ 
385         (PAGE_ENTRY FAR *)
386         ALLOC(&Dbpg_table, db_pgtab_sz*sizeof(PAGE_ENTRY), "dbpg_table");
387 #ifdef DEBUG_DIO
388    if (debugging_dio_init) {
389         printf (__FILE__"345 dio_init: usedfls=%p lookup=%p pgtab=%p\n",
390             used_files, db_lookup, dbpg_table);
391         fflush(stdout);
392    }
393 #endif
394    if ( !used_files || !dbpg_table || !db_lookup )
395       return( dberr(S_NOMEMORY) );
396    byteset(used_files, 0, (size_ft + 1)*sizeof(*used_files));
397
398 #ifdef MULTI_TASK
399    last_dblu.task = NULL;
400 #endif
401    last_dblu.file = -1;
402    last_dblu.pageno = -1L;
403    last_dblu.slot = -1;
404
405    /* initialize database cache */
406    cache_init((int)db_pgtab_sz, db_lookup, dbpg_table, (int)page_size);
407    /***cache_init(db_pgtab_sz, db_lookup, dbpg_table, page_size);****/
408    if (db_status != S_OKAY) return(db_status);
409 #ifndef NO_TRANS
410    if ( use_ovfl ) {
411       ix_lookup =
412         /* Macro references must be on one line for some compilers */ 
413         (LOOKUP_ENTRY FAR *)
414         ALLOC(&Ix_lookup, ix_pgtab_sz*sizeof(LOOKUP_ENTRY),"ix_lookup");
415       ixpg_table = 
416         /* Macro references must be on one line for some compilers */ 
417         (PAGE_ENTRY FAR *)
418         ALLOC(&Ixpg_table, ix_pgtab_sz*sizeof(PAGE_ENTRY), "ixpg_table");
419       if ( !ix_lookup || !ixpg_table )
420          return( dberr(S_NOMEMORY) );
421
422       cache_init(ix_pgtab_sz, ix_lookup, ixpg_table, IX_PAGESIZE);
423       if (db_status != S_OKAY)
424          return (db_status);
425
426       if ( (dbpgbuff = ALLOC(&Dbpgbuff, page_size, "dbpgbuff")) == NULL )
427          return( dberr(S_NOMEMORY) );
428
429       ixpg_lru_slot = 0;
430    }
431 #endif                  /* NO_TRANS */
432    last_file = 0;
433    dbpg_lru_slot = 0;
434    no_modheld  = 0;
435    working_file = NONE;
436
437    /* initialize the page zero table and return */
438 #ifdef DEBUG_DIO
439    if (debugging_dio_init) {
440         puts (__FILE__"390 dio_init: last act is call to dio_pzinit.");
441         fflush(stdout);
442    }
443 #endif
444    return( dio_pzinit() );
445 #undef tempbuff
446 } /* dio_init() */
447
448
449 static void     cache_init (pg_cnt, lu_ptr, pg_ptr, pgsize)
450 int                 pg_cnt;
451 LOOKUP_ENTRY FAR *  lu_ptr;
452 PAGE_ENTRY FAR *    pg_ptr;
453 int                 pgsize;
454 {
455    register int pg_no;
456
457 #ifdef DEBUG_DIO
458    if (debugging_dio_init) {
459         printf (__FILE__"400 cache_init: pgcnt=%d lu=%p pgp=%p pgsz=%d\n",
460             pg_cnt, lu_ptr, pg_ptr, pgsize);
461         fflush(stdout);
462    }
463 #endif
464
465    for (pg_no = 0; pg_no < pg_cnt; ++pg_no, ++lu_ptr, ++pg_ptr)
466    {
467 #ifdef MULTI_TASK
468       lu_ptr->task = NULL;
469 #endif
470       lu_ptr->file = -1;
471       lu_ptr->pageno = -1L;
472       lu_ptr->pg_slot = pg_no;
473
474       pg_ptr->lu_slot = pg_no;
475       pg_ptr->recently_used = FALSE;
476       pg_ptr->modified = FALSE;
477       pg_ptr->holdcnt = 0;
478 #ifndef NO_TRANS
479       pg_ptr->ovfl_addr = 0L;
480 #endif
481       pg_ptr->buff = ALLOC(&pg_ptr->Buff, pgsize, db_avname);
482       if (pg_ptr->buff == NULL) {
483 #ifdef DEBUG_DIO
484          if (debugging_dio_init) {
485                 printf (__FILE__"428 cache_init: alloc failed pgsz=%d\n",
486                     pgsize);
487                 fflush(stdout);
488          }
489 #endif
490          dberr(S_NOMEMORY);
491          return;
492       }
493       MEM_UNLOCK(&pg_ptr->Buff);
494    } /* end loop on pg_cnt */
495    return;
496 } /* cache_init() */
497
498
499 /****************************************/
500 /*                                      */
501 /*              dio_free                */
502 /*                                      */
503 /****************************************/
504 /* Free the memory allocated for pages
505 */
506 void dio_free()
507 {
508    register int pgt_lc;                 /* loop control */
509    register PAGE_ENTRY FAR *pg_ptr;
510
511 #ifdef MULTI_TASK
512    if ( task_count > 1 ) {
513       return;
514    }
515 #endif
516    MEM_UNLOCK(&db_global.Pgzero);
517    FREE(&db_global.Pgzero);
518    MEM_UNLOCK(&Used_files);
519    FREE(&Used_files);
520    MEM_UNLOCK(&Db_lookup);
521    FREE(&Db_lookup);
522    for (pgt_lc = db_pgtab_sz, pg_ptr = dbpg_table; --pgt_lc >= 0; ++pg_ptr) {
523       MEM_UNLOCK(&pg_ptr->Buff);
524       FREE(&pg_ptr->Buff);
525    }
526    MEM_UNLOCK(&Dbpg_table);
527    FREE(&Dbpg_table);
528 #ifndef NO_TRANS
529    if ( use_ovfl ) {
530       MEM_UNLOCK(&Ix_lookup);
531       FREE(&Ix_lookup);
532       for (pgt_lc = ix_pgtab_sz, pg_ptr = ixpg_table; --pgt_lc >= 0; ++pg_ptr) {
533          MEM_UNLOCK(&pg_ptr->Buff);
534          FREE(&pg_ptr->Buff);
535       }
536       MEM_UNLOCK(&Ixpg_table);
537       FREE(&Ixpg_table);
538       MEM_UNLOCK(&Dbpgbuff);
539       FREE(&Dbpgbuff);
540    }
541 #endif
542 } /* dio_free() */
543
544
545 /****************************************/
546 /*                                      */
547 /*              dio_clrfile             */
548 /*                                      */
549 /****************************************/
550 /* Clear pages for a single file.
551 */
552 dio_clrfile(fno )
553 register FILE_NO fno;
554 {
555    return( clear_cache(fno, fno+1) );
556 }
557
558
559
560 /****************************************/
561 /*                                      */
562 /*              dio_clear               */
563 /*                                      */
564 /****************************************/
565 /* Clear all pages for *all* files from I/O buffer
566 */
567 dio_clear()
568 {
569    return( clear_cache(0, size_ft) );
570 }
571
572
573 /****************************************/
574 /*                                      */
575 /*              clear_cache             */
576 /*                                      */
577 /****************************************/
578 /* Clear database page cache.
579  * Clears all pages for a range of specified files.
580  * Subroutine of dio_clrfile and dio_clear.
581  */
582 static int clear_cache(fr_file, to_file )
583 FILE_NO fr_file;   /* clear from file "fr_file" */
584 FILE_NO to_file;   /* ..to (not thru) file "to_file" */
585 {
586    FILE_NO s_file;   /* start file to be cleared */
587    FILE_NO e_file;   /* end file (+1) to be cleared */
588    register int i;
589    LOOKUP_ENTRY FAR *lu_ptr, FAR *lu2_ptr;
590    int pg_slot;
591    PAGE_ENTRY FAR *pg_ptr;
592    PGZERO FAR *pgzero_ptr;
593    FILE_ENTRY FAR *file_ptr;
594    int FAR *appl_ptr, FAR *excl_ptr;
595
596 #ifndef SINGLE_USER
597    /* 
598       We only clear pages which are not from static files and are
599       not still locked.  The check on app_locks is made to implement 
600       the ability to hold locks after the end of a transaction 
601    */
602    for (s_file = e_file = fr_file, file_ptr = &file_table[e_file],
603                 appl_ptr = &app_locks[e_file], excl_ptr = &excl_locks[e_file];
604         s_file < to_file;
605         ++file_ptr, ++appl_ptr, ++excl_ptr) {
606 #else
607    for (s_file = e_file = fr_file, file_ptr = &file_table[e_file];
608         s_file < to_file;
609         ++file_ptr) {
610 #endif
611       if ((e_file < to_file) &&
612 #ifndef SINGLE_USER
613           ((dbopen >= 2) || (!*appl_ptr && !*excl_ptr)) && 
614 #endif
615           !(file_ptr->ft_flags & STATIC)) 
616          ++e_file;
617       else {
618          if (s_file < e_file) {
619             /* find range of pages to be cleared */
620             dio_findpg(s_file, 0L, NULL, NULL, &lu_ptr);
621             dio_findpg(e_file, 0L, NULL, NULL, &lu2_ptr);
622
623 #ifdef MULTI_TASK
624             last_dblu.task = NULL;
625 #endif
626             last_dblu.file = -1;
627             last_dblu.pageno = -1L;
628             last_dblu.slot = -1;
629
630             if (lu_ptr < lu2_ptr) { /* otherwise file has no pages in cache */
631                /* adjust lookup table entries */
632                while ((lu_ptr > db_lookup) && ((--lu_ptr)->file >= 0)) {
633                   --lu2_ptr;
634
635 #ifdef MULTI_TASK
636                   lu2_ptr->task = lu_ptr->task;
637 #endif
638                   lu2_ptr->file = lu_ptr->file;
639                   lu2_ptr->pageno = lu_ptr->pageno;
640                   /* exchange page slot numbers */
641                   pg_slot = lu_ptr->pg_slot;
642                   lu_ptr->pg_slot = lu2_ptr->pg_slot;
643                   lu2_ptr->pg_slot = pg_slot;
644                   dbpg_table[pg_slot].lu_slot = lu2_ptr - db_lookup;
645                   dbpg_table[lu_ptr->pg_slot].lu_slot = lu_ptr - db_lookup;
646                }
647
648                if ( lu_ptr->file < 0 )
649                   ++lu_ptr;
650
651                while (lu_ptr < lu2_ptr) {
652
653 #ifdef MULTI_TASK
654                   lu_ptr->task = NULL;
655 #endif
656                   lu_ptr->file = -1;
657                   lu_ptr->pageno = -1L;
658                   pg_ptr = &dbpg_table[lu_ptr->pg_slot];
659                   if ( pg_ptr->modified || pg_ptr->holdcnt ) {
660                      --no_modheld;
661                      pg_ptr->modified = FALSE;
662                   }
663                   pg_ptr->recently_used = FALSE;
664                   pg_ptr->holdcnt = 0;
665 #ifndef NO_TRANS
666                   pg_ptr->ovfl_addr = 0L;
667 #endif
668                   ++lu_ptr;
669                }
670             }
671             /* clear page zeroes and close files */
672             for (i = s_file, pgzero_ptr = &pgzero[i];
673                  i < e_file;
674                  ++i, ++pgzero_ptr) {
675                pgzero_ptr->pz_modified = FALSE;
676                pgzero_ptr->pz_next = 0L;
677 #ifdef   CLOSE_FILES
678                dio_close(i);
679 #endif
680             }
681          }
682          s_file = ++e_file;
683       }
684    }     
685    return( db_status = S_OKAY );
686 } /* clear_cache() */
687
688
689 /****************************************/
690 /*                                      */
691 /*               dio_flush              */
692 /*                                      */
693 /****************************************/
694 /* Flushes entire database I/O cache.
695  * Writes out all modified cache pages to respective files (dio_out),
696  * then writes out page zero (dio_pzflush).
697  */
698 int dio_flush()
699 {
700    register int pgt_lc;                 /* loop control */
701    int fno;
702    PAGE_ENTRY FAR *pg_ptr;
703    LOOKUP_ENTRY FAR *lu_ptr;
704
705 #ifdef DEBUG_DIO
706     if (debugging_dio_close) {
707         printf (__FILE__"685 dio_flush: check cache dbpgtab=%p count=%d\n",
708             dbpg_table, (int)db_pgtab_sz);
709         fflush(stdout);
710     }
711 #endif
712    if ( dbpg_table == NULL ) return( db_status = S_OKAY );
713
714    for (pgt_lc = db_pgtab_sz, pg_ptr = dbpg_table; --pgt_lc >= 0; ++pg_ptr) {
715       if (!pg_ptr->modified) {
716 #ifndef NO_TRANS
717          pg_ptr->ovfl_addr = 0L;                /*[612]*/
718 #endif
719          continue;
720       }
721       lu_ptr = &db_lookup[pg_ptr->lu_slot];
722 #ifdef MULTI_TASK
723       if ( lu_ptr->task != Currtask.v.ptr ) {
724          continue;
725       }
726 #endif
727 #ifndef NO_TRANS
728       if ((dboptions & TRLOGGING) && trans_id && !trcommit && use_ovfl) {
729          /* flush to overflow/log file -- before tr commit */
730          if (o_write(pg_ptr, lu_ptr) != S_OKAY) return( db_status );
731          if ( lu_ptr->pageno > o_pages(lu_ptr->file) ) {
732             /* no need to rewrite this page at trcommit time */
733             pg_ptr->holdcnt = 0;
734             pg_ptr->modified = FALSE;
735             --no_modheld;
736          }
737          continue;
738       }
739       pg_ptr->ovfl_addr = 0L;
740 #endif
741       /* write directly to database */
742 #ifdef NO_TRANS
743 #ifdef DEBUG_DIO
744         if (debugging_dio_close) {
745             printf (__FILE__"723 dio_flush: write modified pg#%d @ %p\n",
746                 db_pgtab_sz - pgt_lc,  pg_ptr);
747             fflush(stdout);
748         }
749 #endif
750       if (dio_out(pg_ptr, lu_ptr) != S_OKAY) return( db_status );
751 #else
752       if (dio_out(pg_ptr, lu_ptr, 1) != S_OKAY) return( db_status );
753 #endif
754       pg_ptr->holdcnt = 0;
755       pg_ptr->modified = FALSE;
756       --no_modheld;
757 #ifndef NO_TRANS
758       if ( trlog_flag ) {
759          fno = lu_ptr->file;
760          MEM_LOCK(&pg_ptr->Buff);
761          d_trlog(fno, (int)lu_ptr->pageno, pg_ptr->buff,
762                  file_table[fno].ft_pgsize);
763          MEM_UNLOCK(&pg_ptr->Buff);
764       }
765 #endif
766    }
767    /* store the page zero values in the data file and return */
768    return( dio_pzflush() );
769 } /* dio_flush() */
770
771
772
773 /* Set the default file number
774 */
775 void dio_setdef( file_no )
776 FILE_NO file_no;
777 {
778    working_file = file_no;
779 }
780
781
782
783 /****************************************/
784 /*                                      */
785 /*               dio_get                */
786 /*                                      */
787 /****************************************/
788 /* Database I/O page get
789 */
790 dio_get( page_no, page_ptr, hold )
791 F_ADDR page_no;
792 char FAR * FAR *page_ptr;
793 int hold;
794 {
795    PAGE_ENTRY FAR *pg_ptr;
796
797 #ifndef SINGLE_USER
798    if ( dbopen == 1 ) {
799       if ( !app_locks[working_file] && !excl_locks[working_file] &&
800            !(file_table[working_file].ft_flags & STATIC) )
801          return( dberr(S_NOTLOCKED) );
802    }
803 #endif
804    if ( pgzero[working_file].pz_next == 0L )
805       if ( dio_pzread(working_file) != S_OKAY )
806          RETURN( db_status );
807
808    if (dio_findpg(working_file, page_no, dbpg_table, &pg_ptr, NULL) == S_OKAY) {
809       MEM_LOCK(&pg_ptr->Buff);
810       *page_ptr = pg_ptr->buff;
811       pg_ptr->recently_used = TRUE;
812       used_files[working_file] = TRUE;
813       if ( hold ) {
814          if ( ++pg_ptr->holdcnt > 1 )
815             dberr(S_SYSERR);
816          else if ( ! pg_ptr->modified )
817             ++no_modheld;
818       }
819    }
820    return( db_status );
821 } /* dio_get() */
822
823
824
825 /****************************************/
826 /*                                      */
827 /*              dio_touch               */
828 /*                                      */
829 /****************************************/
830 /* Set modified flag for a page
831 */
832 dio_touch( page_no )
833 F_ADDR page_no;
834 {
835    PAGE_ENTRY FAR *pg_ptr;
836
837 #ifndef NO_TRANS
838    /* ensure overflow data is initialized when exclusive db access */
839    if ((trans_id && (dboptions & TRLOGGING) && use_ovfl) &&
840        (o_fileinit(working_file) != S_OKAY))
841       return( db_status );
842 #endif
843 #ifndef SINGLE_USER
844    if ( dbopen == 1 ) { 
845       /* check shared access priviledges */
846       if ( !trans_id && !excl_locks[working_file] )  
847          return( dberr(S_NOTRANS) );
848       if ( app_locks[working_file] >= 0 && !excl_locks[working_file] )
849          return( dberr( S_NOTLOCKED ) );
850    }
851 #endif
852    if (dio_findpg(working_file, page_no, dbpg_table, &pg_ptr, NULL) == S_OKAY ) {
853       pg_ptr->recently_used = TRUE;
854       used_files[working_file] = TRUE;
855       if ( ! pg_ptr->modified ) {
856          pg_ptr->modified = TRUE;
857          if ( ! pg_ptr->holdcnt )
858             ++no_modheld;
859       }
860       if ( pg_ptr->holdcnt > 0 ) {
861          --pg_ptr->holdcnt;
862          if ( pg_ptr->holdcnt ) {
863             db_status = S_OKAY;
864          }
865          MEM_UNLOCK(&pg_ptr->Buff);
866       }
867    }
868    return( db_status );
869 } /* dio_touch() */
870
871
872
873 /****************************************/
874 /*                                      */
875 /*              dio_read                */
876 /*                                      */
877 /****************************************/
878 /* Database I/O read
879  * Merely returns ptr into rec in a page
880  * unless a page swap is necessary.
881  */
882 dio_read( dba, recptr, hold )
883 DB_ADDR dba;
884 char FAR * FAR *recptr;
885 int hold;
886 {
887    FILE_NO file;
888    int offset;
889    F_ADDR us1, us2;
890    FILE_ENTRY FAR *file_ptr;
891    PAGE_ENTRY FAR *pg_ptr;
892
893    file = NUM2INT((FILE_NO)((dba >> FILESHIFT) & FILEMASK), ft_offset);
894    file_ptr = &file_table[file];
895
896    if ( pgzero[file].pz_next == 0L )
897       if ( dio_pzread(file) != S_OKAY )
898          RETURN( db_status );
899
900 #ifndef SINGLE_USER
901    if ( dbopen == 1 ) {
902       /* check shared access priviledges */
903       if (!app_locks[file] &&
904           !excl_locks[file] &&
905           !(file_ptr->ft_flags & STATIC))
906          return( dberr(S_NOTLOCKED) );
907    }
908 #endif
909    us1 = ADDRMASK & dba;
910    us2 = (us1 - 1)/file_ptr->ft_slots;
911    if (dio_findpg(file, us2 + 1, dbpg_table, &pg_ptr, NULL) == S_OKAY ) {
912       pg_ptr->recently_used = TRUE;
913       used_files[file] = TRUE;
914       offset = file_ptr->ft_slsize*(int)(us1 - 1 - us2*file_ptr->ft_slots) +
915                                                                      PGHDRSIZE;
916       MEM_LOCK(&pg_ptr->Buff);
917       *recptr = &pg_ptr->buff[offset];
918       if ( hold ) {
919          if ( (++pg_ptr->holdcnt == 1) && !pg_ptr->modified) {
920             ++no_modheld;
921          }
922       }
923    }
924    return( db_status );
925 } /* dio_read() */
926
927
928 /****************************************/
929 /*                                      */
930 /*              dio_write               */
931 /*                                      */
932 /****************************************/
933 /* Database I/O write: copies data record into a page slot.
934  * Finds record's page, swapping it into cache if necessary.
935  * Sets page's 'touched' flags, timestamps, etc.
936  * If recptr not NULL, copies rec to page cache.
937  */
938 dio_write( dba, recptr, release )
939 DB_ADDR dba;
940 CONST char FAR *recptr;
941 int release;
942 {
943    FILE_NO file;
944    F_ADDR us1, us2;
945    int offset;
946    FILE_ENTRY FAR *file_ptr;
947    PAGE_ENTRY FAR *pg_ptr;
948
949    file = NUM2INT((FILE_NO)((dba >> FILESHIFT) & FILEMASK), ft_offset);
950
951 #ifndef NO_TRANS
952    /* ensure overflow data is initialized when exclusive db access */
953    if ((trans_id && (dboptions & TRLOGGING) && use_ovfl) &&
954        (o_fileinit(file) != S_OKAY))
955       return( db_status );
956 #endif
957 #ifndef SINGLE_USER
958    if (dbopen == 1) {
959       if (!trans_id && !excl_locks[file])  
960          return( dberr(S_NOTRANS) );
961
962       /* check shared access priviledges */
963       if ( app_locks[file] >= 0 && !excl_locks[file] )
964          return( dberr(S_NOTLOCKED) );
965    }
966 #endif
967    file_ptr = &file_table[file];
968    us1 = ADDRMASK & dba;
969    us2 = (us1 - 1)/file_ptr->ft_slots;
970    if (dio_findpg(file, us2 + 1, dbpg_table, &pg_ptr, NULL) == S_OKAY ) {
971       pg_ptr->recently_used = TRUE;
972       used_files[file] = TRUE;
973       if ( recptr != NULL ) {
974          offset = file_ptr->ft_slsize*(int)(us1 - 1 - us2*file_ptr->ft_slots) +
975                                                                      PGHDRSIZE;
976          MEM_LOCK(&pg_ptr->Buff);
977          bytecpy(&pg_ptr->buff[offset], recptr, file_ptr->ft_slsize);
978          MEM_UNLOCK(&pg_ptr->Buff);
979       }
980       if ( ! pg_ptr->modified ) {
981          pg_ptr->modified = TRUE;
982          if ( ! pg_ptr->holdcnt )
983             ++no_modheld;
984       }
985       if ( release ) {
986          if ( --pg_ptr->holdcnt < 0 )
987             dberr(S_SYSERR);
988          MEM_UNLOCK(&pg_ptr->Buff);
989       }
990    }
991    return( db_status );
992 } /* dio_write() */
993
994
995 /* Release database page hold
996 */
997 dio_release( dba )
998 DB_ADDR dba;
999 {
1000    FILE_NO file;
1001    F_ADDR us1, us2;
1002    PAGE_ENTRY FAR *pg_ptr;
1003
1004    file = NUM2INT((FILE_NO)((dba >> FILESHIFT) & FILEMASK), ft_offset);
1005    us1 = ADDRMASK & dba;
1006    us2 = file_table[file].ft_slots;
1007    if (dio_findpg(file, ((us1 - 1)/us2) + 1, dbpg_table, &pg_ptr,
1008                   NULL) == S_OKAY) {
1009       if (pg_ptr->holdcnt) {
1010          --pg_ptr->holdcnt;
1011          if ( !pg_ptr->holdcnt && !pg_ptr->modified )
1012             --no_modheld;
1013          MEM_UNLOCK(&pg_ptr->Buff);
1014       }
1015    }
1016    return( db_status );
1017 }
1018
1019
1020
1021 #ifndef SINGLE_USER
1022 /* Read record lock bit
1023 */
1024 dio_rrlb(dba, rid )
1025 DB_ADDR dba;
1026 INT *rid;
1027 {
1028    FILE_NO file;   /* file number */
1029    F_ADDR page;    /* page number */
1030    F_ADDR sno;     /* slot number */
1031    F_ADDR spp;     /* slots per page */
1032    F_ADDR offset;  /* lseek address - offset from start of file */
1033    FILE_ENTRY FAR *file_ptr;
1034
1035    file = NUM2INT((FILE_NO)((dba >> FILESHIFT) & FILEMASK), ft_offset);
1036    if ( dio_open(file) == S_OKAY ) {
1037       file_ptr = &file_table[file];
1038       sno = ADDRMASK & dba;
1039       spp = file_ptr->ft_slots;
1040       page = (sno - 1)/spp + 1;
1041       offset = PGHDRSIZE + page*file_ptr->ft_pgsize +
1042                                  (sno - 1 - (page - 1)*spp)*file_ptr->ft_slsize;
1043       DB_LSEEK(file_ptr->ft_desc, offset, 0);
1044       if ( DB_READ(file_ptr->ft_desc, (char FAR *)rid, sizeof(INT))
1045                 != sizeof(INT) ) {
1046          dberr(S_BADREAD);
1047       }
1048       NTOHS (*rid);
1049    }
1050    return( db_status );
1051 } /* dio_rrlb() */
1052
1053
1054 /* Write record lock bit
1055 */
1056 dio_wrlb(dba, rid )
1057 DB_ADDR dba;
1058 INT rid;
1059 {
1060    FILE_NO file;   /* file number */
1061    F_ADDR page;    /* page number */
1062    F_ADDR sno;     /* slot number */
1063    F_ADDR spp;     /* slots per page */
1064    F_ADDR offset;  /* offset from start of page or file */
1065    int clr_in_tx;  /* true if called from d_rlbclr in trx */
1066    INT trid;            /* [333] working rid */
1067    FILE_ENTRY FAR *file_ptr;
1068    PAGE_ENTRY FAR *pg_ptr;
1069
1070    file = NUM2INT((FILE_NO)((dba >> FILESHIFT) & FILEMASK), ft_offset);
1071    file_ptr = &file_table[file];
1072    sno = ADDRMASK & dba;
1073    spp = file_ptr->ft_slots;
1074    page = ((sno - 1)/spp) + 1;
1075    offset = PGHDRSIZE + (sno - 1 - (page - 1)*spp)*file_ptr->ft_slsize;
1076    clr_in_tx = !(rid & RLBMASK) && trans_id;
1077
1078    if ( dbopen > 1 || (app_locks[file] || excl_locks[file]) ) {
1079       /* file is locked - check if record in cache */
1080       if (dio_findpg(file, page, dbpg_table, &pg_ptr, NULL) == S_OKAY) {
1081          MEM_LOCK(&pg_ptr->Buff);
1082          /* record in cache - update only rlb in rid */
1083          bytecpy(&trid, &pg_ptr->buff[offset], sizeof(INT));
1084          MEM_UNLOCK(&pg_ptr->Buff);
1085          rid = (trid & ~((INT)RLBMASK)) | (rid & RLBMASK);
1086          bytecpy(&pg_ptr->buff[offset], &rid, sizeof(INT));
1087          if ( clr_in_tx ) {
1088             /* clearing within a transaction requires touching page */
1089             if ( ! pg_ptr->modified ) {
1090                pg_ptr->modified = TRUE;
1091                if ( ! pg_ptr->holdcnt )
1092                   ++no_modheld;
1093             }
1094          }
1095       }
1096       else
1097          clr_in_tx = FALSE;
1098    }
1099    if ( ! clr_in_tx ) {
1100       /* update only rlb directly to disk */
1101       if ( dio_open(file) == S_OKAY ) {
1102          offset += page*file_ptr->ft_pgsize;
1103
1104          /* read rid from disk, and set/clear rlb accordingly */
1105          DB_LSEEK(file_ptr->ft_desc, offset, 0);
1106          if ( DB_READ(file_ptr->ft_desc, (char FAR *)&trid, sizeof(INT))
1107                 != sizeof(INT) ) {
1108             dberr(S_BADREAD);
1109          }
1110          NTOHS (trid);
1111          rid = (trid & ~((INT)RLBMASK)) | (rid & RLBMASK);
1112
1113          /* write original rid out with modified rlb */
1114          trid = htons (rid); /* make a copy in trid for byte swap */
1115          DB_LSEEK(file_ptr->ft_desc, offset, 0);        /* reseek */
1116          if ( DB_WRITE(file_ptr->ft_desc, (char FAR *)&trid, sizeof(INT)) !=
1117               sizeof(INT) )
1118             dberr(S_BADWRITE);
1119       }
1120    }
1121    return( db_status );
1122 } /* dio_wrlb() */
1123 #endif                  /* SINGLE_USER */
1124
1125
1126 /****************************************/
1127 /*                                      */
1128 /*              dio_findpg              */
1129 /*                                      */
1130 /****************************************/
1131 /* Search a cache for page
1132 */
1133 dio_findpg(file, page, pg_table, xpg_ptr, xlu_ptr )
1134 FILE_NO      file;       /* file number = 0..size_ft-1 */
1135 F_ADDR       page;       /* database page number */
1136 PAGE_ENTRY FAR *pg_table;   /* = dbpg_table, ixpg_table, or NULL */
1137 PAGE_ENTRY FAR * FAR *xpg_ptr;  /* pointer to page table entry for found page */
1138 LOOKUP_ENTRY FAR * FAR *xlu_ptr;/* pointer to lookup table slot for found page*/
1139 {
1140 #ifdef MULTI_TASK
1141    CHAR_P Tempbuff;
1142 #define tempbuff Tempbuff.ptr
1143 #endif
1144    LOOKUP_ENTRY FAR *lookup;  /* = db_lookup or ix_lookup */
1145    int pgtab_sz;          /* = db_pgtab_sz or ix_pgtab_sz */
1146    long cmp;
1147    int cnt;
1148    register int lu_slot, l, u;
1149    LOOKUP_ENTRY FAR *lu_ptr, FAR *replu_ptr;
1150    PAGE_ENTRY FAR *pg_ptr;
1151    int *lru_ptr;
1152    int pg_slot;
1153 #ifndef NO_TRANS
1154    BOOLEAN db_cache;      /* TRUE if currently using dbpg_table */
1155    F_ADDR ovfl_addr;
1156 #endif
1157 #ifdef MULTI_TASK
1158    INT pgsize;
1159 #endif
1160
1161 #ifdef NO_TRANS
1162
1163    /* check if desired page was last one */
1164 #ifdef MULTI_TASK
1165    if ((Currtask.v.ptr == last_dblu.task) && (file == last_dblu.file) && (page == last_dblu.pageno)) {
1166 #else
1167    if ((file == last_dblu.file) && (page == last_dblu.pageno)) {
1168 #endif
1169       if (xlu_ptr != NULL)
1170          *xlu_ptr = &db_lookup[last_dblu.slot];
1171       if (xpg_ptr != NULL)
1172          *xpg_ptr = &dbpg_table[db_lookup[last_dblu.slot].pg_slot];
1173       return( db_status = S_OKAY );
1174    }
1175    lookup = db_lookup;
1176    pgtab_sz = db_pgtab_sz;
1177 #else                   /* NO_TRANS */
1178    if (db_cache = (!pg_table || (pg_table == dbpg_table))) {
1179       /* check if desired page was last one */
1180 #ifdef MULTI_TASK
1181       if ((Currtask.v.ptr == last_dblu.task) && (file == last_dblu.file) &&
1182              (page == last_dblu.pageno)) {
1183 #else
1184       if ((file == last_dblu.file) && (page == last_dblu.pageno)) {
1185 #endif
1186          if (xlu_ptr != NULL)
1187             *xlu_ptr = &db_lookup[last_dblu.slot];
1188          if (xpg_ptr != NULL)
1189             *xpg_ptr = &dbpg_table[db_lookup[last_dblu.slot].pg_slot];
1190          return( db_status = S_OKAY );
1191       }
1192       lookup = db_lookup;
1193       pgtab_sz = db_pgtab_sz;
1194    }
1195    else {
1196       lookup = ix_lookup;
1197       pgtab_sz = ix_pgtab_sz;
1198    }
1199 #endif                  /* NO_TRANS */
1200    /* perform binary search of sorted lookup table */
1201    l = 0;
1202    u = pgtab_sz - 1;
1203    while (u >= l) {
1204       lu_ptr = &lookup[lu_slot = (l + u)/2];
1205 #ifdef MULTI_TASK
1206       if ((cmp = Currtask.v.ptr - lu_ptr->task) == 0)
1207 #endif
1208          if ((cmp = file - lu_ptr->file) == 0)
1209             cmp = page - lu_ptr->pageno;
1210       if (cmp < 0)
1211          u = lu_slot - 1;
1212       else if (cmp > 0)
1213          l = lu_slot + 1;
1214       else {
1215 #ifndef NO_TRANS
1216          if (db_cache)
1217          {
1218 #endif
1219 #ifdef MULTI_TASK
1220             last_dblu.task = lu_ptr->task;
1221 #endif
1222             last_dblu.file = lu_ptr->file;
1223             last_dblu.pageno = lu_ptr->pageno;
1224             last_dblu.slot = lu_slot;
1225 #ifndef NO_TRANS
1226          }
1227 #endif
1228          if (xlu_ptr != NULL)
1229             *xlu_ptr = lu_ptr;
1230          if (xpg_ptr != NULL)
1231             *xpg_ptr = &pg_table[lu_ptr->pg_slot];
1232          return( db_status = S_OKAY );
1233       }
1234    }
1235    if ( ! pg_table ) {
1236       /* null page table indicates that only a lookup was desired */
1237       if (cmp > 0)
1238          ++lu_ptr;
1239       if (xlu_ptr != NULL)
1240          *xlu_ptr = lu_ptr;
1241       return( db_status = S_NOTFOUND );
1242    }
1243    /* page not found - read into cache */
1244 #ifndef NO_TRANS
1245    if( !use_ovfl && trans_id && (no_modheld == pgtab_sz) )
1246       return( db_status =  S_TRCHANGES );
1247
1248    /* check to see if page is in overflow file */
1249    ovfl_addr = 0L;
1250    if ( cache_ovfl && file != ov_file ) {
1251       if ( o_search( file, page, &ovfl_addr ) != S_OKAY )
1252          return( db_status );
1253    }
1254    /* check for overflow */
1255    if ( db_cache && trans_id && (no_modheld == pgtab_sz) && !cache_ovfl ) {
1256       cache_ovfl = TRUE;
1257    }
1258    /* select a page to replace */
1259    if (db_cache) {
1260       lru_ptr = &dbpg_lru_slot;
1261    } else {
1262       lru_ptr = &ixpg_lru_slot;
1263    }
1264 #else
1265    /* select a page to replace */
1266    lru_ptr = &dbpg_lru_slot;
1267 #endif                  /* NO_TRANS */
1268    for (cnt = 2*pgtab_sz, pg_slot = *lru_ptr, pg_ptr = &pg_table[pg_slot];
1269         --cnt >= 0;
1270         ++pg_slot, ++pg_ptr) {
1271       if (pg_slot >= pgtab_sz)
1272       {
1273          pg_slot = 0;
1274          pg_ptr = pg_table;
1275       }
1276       replu_ptr = &lookup[pg_ptr->lu_slot];
1277       if (!pg_ptr->recently_used && (pg_ptr->holdcnt == 0)) {
1278 #ifdef NO_TRANS
1279          if (pg_ptr->modified) {
1280             dio_out(pg_ptr, replu_ptr);
1281             pg_ptr->modified = FALSE;
1282             --no_modheld;
1283          }
1284 #else
1285          if (pg_ptr->modified) {
1286             /* allow updates outside transactions for single-user mode */
1287 #ifdef SINGLE_USER
1288             if (!db_cache || (EXCL_OPEN() && !trans_id)) {
1289 #else
1290 #ifdef MULTI_TASK
1291             MEM_LOCK(&replu_ptr->task->Excl_locks);
1292 #endif
1293             if (!db_cache || ((EXCL_OPEN() ||
1294 #ifdef MULTI_TASK
1295                 ( replu_ptr->task == Currtask.v.ptr ) ?
1296                    excl_locks[lookup[pg_ptr->lu_slot].file] :
1297                    replu_ptr->task->Excl_locks.ptr[replu_ptr->file]) && 
1298                 !trans_id)) {
1299 #else
1300                 excl_locks[lookup[pg_ptr->lu_slot].file]) && !trans_id)) {
1301 #endif          /* MULTI_TASK */
1302 #endif          /* SINGLE_USER */
1303                /* ix page swapping occurs here */
1304                dio_out(pg_ptr, replu_ptr, db_cache);
1305                pg_ptr->modified = FALSE;
1306                if ( db_cache ) --no_modheld;
1307             }
1308             else { 
1309                if (!use_ovfl || !cache_ovfl) continue; /* skip modified pages */
1310                /* Write out modified page */
1311                pg_ptr->modified = FALSE;
1312                --no_modheld;  /* must be in db cache */
1313                if (o_write(pg_ptr, replu_ptr) != S_OKAY) return( db_status );
1314             }
1315 #ifdef MULTI_TASK
1316             MEM_UNLOCK(&replu_ptr->task->Excl_locks);
1317 #endif
1318          }
1319          pg_ptr->ovfl_addr = ovfl_addr;
1320 #endif                  /* NO_TRANS */
1321          pg_ptr->recently_used = TRUE;
1322          if ((*lru_ptr = (pg_slot + 1)) >= pgtab_sz)
1323             *lru_ptr = 0;
1324          break;
1325       }
1326       else if ( pg_ptr->holdcnt == 0 )
1327          pg_ptr->recently_used = FALSE;
1328    }
1329    if (cnt < 0)
1330       return( dberr(S_FAULT) );
1331
1332    /* adjust lookup table */
1333    if (replu_ptr < lu_ptr) {
1334       if (cmp < 0)
1335       {
1336          --lu_ptr;
1337          --lu_slot;
1338       }
1339       while (replu_ptr < lu_ptr) {
1340          bytecpy(replu_ptr, replu_ptr + 1, sizeof(*replu_ptr));
1341          pg_table[replu_ptr->pg_slot].lu_slot = replu_ptr - lookup;
1342          ++replu_ptr;
1343       }
1344    }
1345    else if (replu_ptr > lu_ptr) {
1346       if (cmp > 0)
1347       {
1348          ++lu_ptr;
1349          ++lu_slot;
1350       }
1351       while (replu_ptr > lu_ptr) {
1352          bytecpy(replu_ptr, replu_ptr - 1, sizeof(*replu_ptr));
1353          pg_table[replu_ptr->pg_slot].lu_slot = replu_ptr - lookup;
1354          --replu_ptr;
1355       }
1356    }
1357 #ifdef MULTI_TASK
1358
1359 #ifdef NO_TRANS
1360    pgsize = file_table[( lu_ptr->file > -1 ) ? lu_ptr->file : file].ft_pgsize;
1361 #else
1362    pgsize = ( db_cache )
1363             ? file_table[( lu_ptr->file > -1 ) ? lu_ptr->file : file].ft_pgsize
1364             : file_table[ov_file].ft_pgsize;
1365 #endif
1366
1367    if ( ! pgsize ) {
1368       pgsize = page_size;
1369    }
1370    if ( pgsize != file_table[file].ft_pgsize ) {
1371       Tempbuff.ptr = NULL;
1372       tempbuff = ALLOC(&Tempbuff, file_table[file].ft_pgsize, "dbpgbuff");
1373       if ( ! tempbuff ) {
1374          return( dberr(S_NOMEMORY) );
1375       }
1376       if ( pg_ptr->buff ) {
1377          MEM_UNLOCK(&pg_ptr->Buff);
1378          FREE(&pg_ptr->Buff);
1379       }
1380       MEM_UNLOCK(&Tempbuff);
1381       pg_ptr->Buff = Tempbuff;
1382    }
1383 #endif /* MULTI_TASK */
1384
1385 #ifdef MULTI_TASK
1386    lu_ptr->task = Currtask.v.ptr;
1387 #endif
1388    lu_ptr->file = file;
1389    lu_ptr->pageno = page;
1390    lu_ptr->pg_slot = pg_slot;
1391    pg_ptr->lu_slot = lu_slot;
1392    if (xlu_ptr != NULL)
1393       *xlu_ptr = lu_ptr;
1394    if (xpg_ptr != NULL)
1395       *xpg_ptr = pg_ptr;
1396 #ifdef NO_TRANS
1397 #ifdef MULTI_TASK
1398    last_dblu.task = lu_ptr->task;
1399 #endif
1400    last_dblu.file = lu_ptr->file;
1401    last_dblu.pageno = lu_ptr->pageno;
1402    last_dblu.slot = lu_slot;
1403    dio_in(pg_ptr, lu_ptr);
1404 #else
1405    if (db_cache) {
1406 #ifdef MULTI_TASK
1407       last_dblu.task = lu_ptr->task;
1408 #endif
1409       last_dblu.file = lu_ptr->file;
1410       last_dblu.pageno = lu_ptr->pageno;
1411       last_dblu.slot = lu_slot;
1412    }
1413    dio_in(pg_ptr, lu_ptr, db_cache);
1414 #endif
1415
1416    return( db_status );
1417 #undef tempbuff
1418 } /* dio_findpg() */
1419
1420
1421 /****************************************/
1422 /*                                      */
1423 /*               dio_out                */
1424 /*                                      */
1425 /****************************************/
1426 /* Writes a page in the cache to file.
1427  * For byte order neutrality:
1428  * Each page is raima header data, then a bunch of slots.
1429  * The first 4 bytes of the page header is the timestamp
1430  * when the page was written, and it's swapped here.
1431  * Each slot is raima record header and user record data.
1432  * The user record data must already have been byte
1433  * swapped if necessary--to vista its just a large char buf.
1434  * The rest of the page header and the record header for each
1435  * slot is byte swapped before the io by calling the
1436  * page swap function.
1437  */
1438 #ifndef NO_TRANS
1439 dio_out(pg_ptr, lu_ptr, db_cache)
1440 #else
1441 dio_out(pg_ptr, lu_ptr)
1442 #endif
1443 PAGE_ENTRY FAR *pg_ptr;    /* page table entry to be output */
1444 LOOKUP_ENTRY FAR *lu_ptr;  /* corresponding lookup table entry */
1445 #ifndef NO_TRANS
1446    BOOLEAN db_cache;      /* TRUE if pg_ptr is in db page cache */
1447 #endif
1448 {
1449    int          desc;   /* file descriptor */
1450    int          fno;    /* file number */
1451    int          pgsize; /* size of page */
1452    long         addr;   /* file address */
1453    time_t       host_timestamp;
1454    ULONG        netorder_timestamp;
1455
1456    MEM_LOCK(&pg_ptr->Buff);
1457
1458    /* Get the current time in "network" format.
1459     * (Original vista code had it typed as a long.)
1460     */
1461    time (&host_timestamp);
1462    netorder_timestamp = (ULONG) host_timestamp;
1463    HTONL (netorder_timestamp);
1464
1465 #ifdef NO_TRANS
1466    fno = lu_ptr->file;
1467    pgsize = file_table[fno].ft_pgsize;
1468    addr = lu_ptr->pageno * (long)pgsize;
1469    memcpy (pg_ptr->buff, &netorder_timestamp, sizeof(ULONG));
1470 #else
1471    if ( db_cache ) {
1472       fno = lu_ptr->file;
1473       pgsize = file_table[fno].ft_pgsize;
1474    }
1475    else
1476       pgsize = file_table[ov_file].ft_pgsize;
1477
1478    if ( pg_ptr->ovfl_addr == 0L ) {
1479       /* write to database */
1480       addr = lu_ptr->pageno * (long)pgsize;
1481       memcpy (pg_ptr->buff, &netorder_timestamp, sizeof(ULONG));
1482    }
1483    else {
1484       /* write to overflow file */
1485       fno = ov_file;
1486       addr = pg_ptr->ovfl_addr;
1487    }
1488 #endif
1489    if ( dio_open(fno) == S_OKAY ) {
1490       swab_page (pg_ptr->buff, &file_table[fno], HTON);
1491       desc = file_table[fno].ft_desc;
1492       DB_LSEEK( desc, addr, 0 );
1493       if (DB_WRITE( desc, pg_ptr->buff, pgsize ) != pgsize) dberr(S_BADWRITE);
1494    }
1495    MEM_UNLOCK(&pg_ptr->Buff);
1496    return( db_status );
1497 } /* dio_out() */
1498
1499
1500
1501 /****************************************/
1502 /*                                      */
1503 /*               dio_in                 */
1504 /*                                      */
1505 /****************************************/
1506 #ifdef NO_TRANS
1507 /* Read in a page to the buffer
1508 */
1509 static int dio_in(pg_ptr, lu_ptr)
1510 PAGE_ENTRY FAR *pg_ptr; /* page table entry to be input */
1511 LOOKUP_ENTRY FAR *lu_ptr; /* corresponding to pg_ptr */
1512 #else
1513 /* Read in a page to the buffer
1514 */
1515 static int dio_in(pg_ptr, lu_ptr, db_cache )
1516 PAGE_ENTRY FAR *pg_ptr; /* page table entry to be input */
1517 LOOKUP_ENTRY FAR *lu_ptr; /* corresponding to pg_ptr */
1518 BOOLEAN db_cache;  /* TRUE if pg_ptr in db cache */
1519 #endif
1520 {
1521    int desc;   /* file descriptor */
1522    int fno;    /* file number */
1523    int pgsize; /* page size */
1524    long addr;  /* file address */
1525    PGZERO FAR *pgzero_ptr;
1526    FILE_ENTRY FAR *file_ptr;
1527    int r;
1528
1529    file_ptr = &file_table[fno = lu_ptr->file];
1530 #ifdef NO_TRANS
1531    pgsize = file_ptr->ft_pgsize;
1532    addr = lu_ptr->pageno*pgsize;
1533 #else
1534    pgsize = db_cache ? file_ptr->ft_pgsize : file_table[ov_file].ft_pgsize;
1535
1536    if (pg_ptr->ovfl_addr == 0L) {
1537       /* read from database file */
1538       /* if !db_cache, overflow address not set on initial read */
1539       addr = db_cache ? lu_ptr->pageno*pgsize :
1540                         (pg_ptr->ovfl_addr = lu_ptr->pageno);
1541    }
1542    else {
1543       /* read from overflow file */
1544       file_ptr = &file_table[fno = ov_file];
1545       addr = pg_ptr->ovfl_addr;
1546    }
1547 #endif
1548    if ( dio_open(fno) == S_OKAY ) {
1549       desc = file_ptr->ft_desc;
1550       DB_LSEEK(desc, addr, 0);
1551       MEM_LOCK(&pg_ptr->Buff);
1552       if ((r = DB_READ( desc, pg_ptr->buff, pgsize )) < pgsize) {
1553          byteset(&pg_ptr->buff[r], '\0', pgsize - r);
1554          DB_LSEEK(desc, addr, 0);
1555          if (DB_WRITE( desc, pg_ptr->buff, pgsize ) != pgsize) {
1556             /* clean up and return out of space */
1557             DB_LSEEK(desc, addr, 0);
1558             DB_WRITE(desc, "", 0);
1559             pgzero_ptr = &pgzero[fno];
1560             pgzero_ptr->pz_next--;
1561             pgzero_ptr->pz_modified = TRUE;
1562             dio_pzflush();
1563             dberr( S_NOSPACE );
1564          }
1565       }
1566       swab_page (pg_ptr->buff, file_ptr, NTOH);
1567       MEM_UNLOCK(&pg_ptr->Buff);
1568    }
1569    return( db_status );
1570 } /* dio_in() */
1571
1572
1573 /***********************************************************************
1574    Page zero handling functions for data and key files
1575 ***********************************************************************/
1576
1577 #ifndef  NO_TIMESTAMP
1578 /* Increment and return file timestamp
1579 */
1580 ULONG dio_pzsetts(fno )
1581 FILE_NO fno;
1582 {
1583    ULONG ts;
1584    PGZERO FAR *pgzero_ptr;
1585
1586    if ( db_tsrecs || db_tssets ) {
1587       pgzero_ptr = &pgzero[fno];
1588       pgzero_ptr->pz_modified = TRUE;
1589       ts = ++pgzero_ptr->pz_timestamp;
1590    }
1591    else
1592       ts = 0;
1593
1594    return( ts );
1595 }
1596
1597
1598 /* Return file timestamp
1599 */
1600 ULONG dio_pzgetts(fno)
1601 FILE_NO fno;
1602 {
1603    if ( pgzero[fno].pz_next == 0L )
1604       dio_pzread(fno);
1605    o_fileinit(fno);
1606    return ( pgzero[fno].pz_timestamp );
1607 }
1608
1609 #endif
1610
1611 /* Initialize page zero table
1612 */
1613 static int dio_pzinit()
1614 {
1615    register FILE_NO i;
1616    PGZERO FAR *pgzero_ptr;
1617
1618 #ifdef DEBUG_DIO
1619    if (debugging_dio_init) {
1620         printf (__FILE__"1430 dio_pzinit: szft=%d oldsz=%d\n",
1621             (int)size_ft, (int)old_size_ft);
1622         fflush (stdout);
1623    }
1624 #endif
1625
1626    /* Macro references must be on one line for some compilers */ 
1627    if (ALLOC_TABLE(&db_global.Pgzero, size_ft*sizeof(PGZERO), 
1628                       old_size_ft*sizeof(PGZERO), "pgzero") != S_OKAY ) {
1629 #ifdef DEBUG_DIO
1630         if (debugging_dio_init) {
1631             printf (__FILE__"1444 pzinit: alloc_table failed, db_status=%d\n",
1632                     db_status);
1633             fflush (stdout);
1634         }
1635 #endif
1636         return( db_status );
1637    }
1638
1639    /* read in page zeros */
1640    for (i = old_size_ft, pgzero_ptr = pgzero; 
1641         i < size_ft;
1642         ++i, ++pgzero_ptr) {        
1643       pgzero_ptr->pz_dchain = 0L;
1644       pgzero_ptr->pz_next = 0L;
1645       pgzero_ptr->pz_timestamp = 0;
1646       pgzero_ptr->pz_modified = FALSE;
1647    }
1648    return( db_status = S_OKAY );
1649 } /* dio_pzinit() */
1650
1651
1652 /****************************************/
1653 /*                                      */
1654 /*             dio_pzflush              */
1655 /*                                      */
1656 /****************************************/
1657 /* Flush page zero table
1658  * Complement to dio_out which writes all pages except page zero.
1659  */
1660 static int dio_pzflush()
1661 {
1662    register FILE_NO i;
1663    int desc;
1664    register PGZERO FAR *pgzero_ptr;
1665    register FILE_ENTRY FAR *file_ptr;
1666    LONG         align_LONG;
1667    char         *cptr;
1668    int          j;
1669
1670 #ifndef NO_TRANS
1671    if ( (dboptions & TRLOGGING) && trans_id && !trcommit && use_ovfl ) {
1672       /* flush to overflow/log file -- before tx commit */
1673       for (i = 0, pgzero_ptr = pgzero; i < size_ft; ++i, ++pgzero_ptr) {
1674          if (pgzero_ptr->pz_modified ) 
1675             if ( o_pzwrite( i ) != S_OKAY ) return( db_status );
1676       }
1677    }
1678    else {
1679 #endif
1680       /* flush modified page zeroes to database files */
1681       for (i = 0, pgzero_ptr = pgzero, file_ptr = file_table; i < size_ft; 
1682            ++i, ++pgzero_ptr, ++file_ptr) {
1683          if ( pgzero_ptr->pz_modified ) {
1684             if ( dio_open(i) != S_OKAY )
1685                return( db_status );
1686
1687             /* The only byte swap operations necessary
1688              * on a page zero are the first 5 LONG integers.
1689              */
1690             for (j = 0, cptr = (char *) pgzero_ptr;
1691                  j < PGZEROSZ/sizeof(LONG);
1692                  ++j, cptr += sizeof(LONG)) {
1693                 memcpy (&align_LONG, cptr, sizeof(LONG));
1694                 HTONL (align_LONG);
1695                 memcpy (cptr, &align_LONG, sizeof(LONG));
1696             }
1697             desc = file_ptr->ft_desc;
1698             DB_LSEEK(desc, 0L, 0);
1699             if (DB_WRITE(desc, (char FAR *)pgzero_ptr, PGZEROSZ) != PGZEROSZ) 
1700                return( dberr(S_BADWRITE) );
1701             pgzero_ptr->pz_modified = FALSE;
1702 #ifndef NO_TRANS
1703             if ( trlog_flag )
1704                d_trlog(i, 0, (char FAR *)pgzero_ptr,  PGZEROSZ);
1705 #endif
1706          }
1707 #ifdef   CLOSE_FILES
1708          dio_close(i);
1709 #endif
1710       }
1711 #ifndef NO_TRANS
1712    }
1713 #endif
1714    return( db_status = S_OKAY );
1715 } /* dio_pzflush() */
1716
1717
1718 /****************************************/
1719 /*                                      */
1720 /*              dio_pzread              */
1721 /*                                      */
1722 /****************************************/
1723 /* Read a file's page zero
1724 */
1725 dio_pzread(fno)
1726 FILE_NO fno;  /* file number */
1727 {
1728    FILE_ENTRY FAR *file_ptr;
1729    PGZERO FAR *pgzero_ptr;
1730
1731    pgzero_ptr = &pgzero[fno];
1732    file_ptr = &file_table[fno];
1733
1734    /* open this file, if not already open */
1735    dio_open(fno);
1736    if (file_ptr->ft_desc < 0) {
1737       pgzero_ptr->pz_dchain =           0;
1738       pgzero_ptr->pz_next =             0;
1739       pgzero_ptr->pz_timestamp =        0;
1740       pgzero_ptr->pz_modified =         FALSE;
1741       return( db_status );      /* db_status set by dio_open */
1742    }
1743
1744    /* seek to and read page zero */
1745    DB_LSEEK(file_ptr->ft_desc, 0L, 0);
1746    if ( DB_READ(file_ptr->ft_desc, (char FAR *)pgzero_ptr, PGZEROSZ) 
1747                                                         != PGZEROSZ ) {
1748       return( dberr(S_BADREAD) );
1749    }
1750    NTOHL (pgzero_ptr->pz_dchain);
1751    NTOHL (pgzero_ptr->pz_next);
1752    NTOHL (pgzero_ptr->pz_timestamp);
1753    return( db_status = S_OKAY );
1754 } /* dio_pzread() */
1755
1756
1757
1758 /****************************************/
1759 /*                                      */
1760 /*              dio_pzalloc             */
1761 /*                                      */
1762 /****************************************/
1763 /* Allocate new record slot or key node from page zero,
1764  * ie from delete chain if possible.
1765  * Returns memory address of the free slot into 'loc'.
1766  */
1767 dio_pzalloc(fno, loc )
1768 FILE_NO fno;    /* file number */
1769 F_ADDR *loc;    /* pointer to allocated location */
1770 {
1771    DB_ADDR dba;
1772    F_ADDR pg;
1773    char FAR *ptr;
1774    PGZERO FAR *pgzero_ptr;
1775
1776 #ifndef SINGLE_USER
1777    /* check shared access priviledges */
1778    if ( dbopen == 1 && !trans_id && !excl_locks[fno] )
1779       return( dberr(S_NOTRANS) );
1780 #endif
1781
1782    pgzero_ptr = &pgzero[fno];
1783    if ( pgzero_ptr->pz_next == 0L )
1784       if ( dio_pzread(fno) != S_OKAY )
1785          RETURN( db_status );
1786    if ( file_table[fno].ft_type == KEY ) {
1787       if ( working_file != fno )
1788          return( dberr(S_NOWORK) );
1789       if ( pgzero_ptr->pz_dchain == NONE || ! (dboptions & DCHAINUSE) ) {
1790          if ( pgzero_ptr->pz_next == MAXRECORDS-1 )
1791             return( dberr(S_RECLIMIT) );
1792          pg = pgzero_ptr->pz_next++;
1793       }
1794       else {
1795          pg = pgzero_ptr->pz_dchain;
1796          if ( dio_get( pg, (char FAR * FAR *)&ptr, NOPGHOLD ) != S_OKAY )
1797             return( db_status );
1798         /* Get the first key node on the delete chain.
1799          * (sizeof external timestamp set to 4 bytes)
1800          ****** bytecpy(&pgzero_ptr->pz_dchain,
1801          ****** ptr+sizeof(long)+sizeof(INT), sizeof(F_ADDR)); *********
1802          */
1803          bytecpy (&pgzero_ptr->pz_dchain,
1804             ptr + sizeof(LONG) + sizeof(INT), sizeof(F_ADDR));
1805       }
1806    }
1807    else {
1808       if ( ! pgzero_ptr->pz_dchain || ! (dboptions & DCHAINUSE) ) {
1809          if ( pgzero_ptr->pz_next == MAXRECORDS )
1810             return( dberr(S_RECLIMIT) );
1811          pg = pgzero_ptr->pz_next++;
1812       }
1813       else {
1814          pg = pgzero_ptr->pz_dchain;
1815          dba = ((NUM2EXT(fno, ft_offset) & FILEMASK) << FILESHIFT) | pg;
1816          if ( dio_read(dba, (char FAR * FAR *)&ptr, NOPGHOLD) != S_OKAY )
1817             return( db_status );
1818          bytecpy(&pgzero_ptr->pz_dchain, ptr+sizeof(INT), sizeof(F_ADDR));
1819       }
1820    }
1821    *loc = pg;
1822    pgzero_ptr->pz_modified = TRUE;
1823    return( db_status = S_OKAY );
1824 } /* dio_pzalloc() */
1825
1826
1827 /****************************************/
1828 /*                                      */
1829 /*              dio_pzdel               */
1830 /*                                      */
1831 /****************************************/
1832 /* Delete record slot or key node from page zero
1833 */
1834 dio_pzdel(fno, loc )
1835 FILE_NO fno;  /* file number */
1836 F_ADDR  loc;  /* location to be freed */
1837 {
1838    DB_ADDR dba;
1839    INT recnum;
1840    char FAR *ptr;
1841    PGZERO FAR *pgzero_ptr;
1842
1843 #ifndef SINGLE_USER
1844    /* check shared access priviledges */
1845    if ( dbopen == 1 && !trans_id && !excl_locks[fno] )
1846       return( dberr(S_NOTRANS) );
1847 #endif
1848
1849    pgzero_ptr = &pgzero[fno];
1850    if ( pgzero_ptr->pz_next == 0L )
1851       if ( dio_pzread(fno) != S_OKAY )
1852          RETURN( db_status );
1853    if ( file_table[fno].ft_type == KEY ) {
1854       if ( working_file != fno )
1855          return( dberr(S_NOWORK) );
1856       if ( dio_get( loc, (char FAR * FAR *)&ptr, PGHOLD ) != S_OKAY )
1857          return( db_status );
1858       /*********************************************
1859        * Delete chain ptr in key node page is in location
1860        * of orphan ptr, bytes 6 - 9, not bytes 4 - 7
1861        * as printed in raima User Guide.
1862        * (sizeof external timestamp set to 4 bytes).
1863        ****** bytecpy(ptr+sizeof(long)+sizeof(INT),
1864        ****** &pgzero_ptr->pz_dchain, sizeof(F_ADDR)); *********
1865        *****************************************/
1866       bytecpy (ptr + sizeof(LONG) + sizeof(INT),
1867             &pgzero_ptr->pz_dchain, sizeof(F_ADDR));
1868       pgzero_ptr->pz_dchain = loc;
1869       dio_touch( loc );
1870    }
1871    else {
1872       dba = ((NUM2EXT(fno, ft_offset) & FILEMASK) << FILESHIFT) | loc;
1873       if ( dio_read( dba, (char FAR * FAR *)&ptr , NOPGHOLD) != S_OKAY )
1874          return( db_status );
1875       bytecpy(&recnum, ptr, sizeof(INT));
1876       recnum = ~recnum;  /* indicates deleted record */
1877       bytecpy(ptr, &recnum, sizeof(INT));
1878       bytecpy(ptr+sizeof(INT), &pgzero_ptr->pz_dchain, sizeof(F_ADDR));
1879       pgzero_ptr->pz_dchain = loc;
1880       if ( dio_write(dba, NULL, NOPGFREE) != S_OKAY )
1881          return( db_status );
1882    }
1883    pgzero_ptr->pz_modified = TRUE;
1884    return( db_status = S_OKAY );
1885 } /* dio_pzdel() */
1886
1887
1888 /****************************************/
1889 /*                                      */
1890 /*              dio_pznext              */
1891 /*                                      */
1892 /****************************************/
1893 /* Return pz_next for file fno
1894 */
1895 F_ADDR dio_pznext(fno)
1896 FILE_NO fno;
1897 {
1898    if ( pgzero[fno].pz_next == 0L )
1899       dio_pzread(fno);
1900    return ( pgzero[fno].pz_next );
1901 }
1902
1903 /****************************************/
1904 /*                                      */
1905 /*              dio_pzclr               */
1906 /*                                      */
1907 /****************************************/
1908 /* Clear page zero cache
1909 */
1910 void dio_pzclr()
1911 {
1912    register FILE_NO i;
1913    register PGZERO FAR *pgzero_ptr;
1914
1915    for (i = 0, pgzero_ptr = pgzero; i < size_ft; i++, pgzero_ptr++) {
1916       if (pgzero_ptr->pz_modified) {
1917          pgzero_ptr->pz_next = 0L;
1918          pgzero_ptr->pz_modified = FALSE;
1919       }
1920    }
1921    return;
1922 }
1923 /* vpp -nOS2 -dUNIX -nBSD -nVANILLA_BSD -nVMS -nMEMLOCK -nWINDOWS -nFAR_ALLOC -f/usr/users/master/config/nonwin dio.c */