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