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