lib/tt/mini_isam: remove register keyword
[oweals/cde.git] / cde / lib / tt / mini_isam / isvarrec.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 /*%%  (c) Copyright 1993, 1994 Hewlett-Packard Company                   */
24 /*%%  (c) Copyright 1993, 1994 International Business Machines Corp.     */
25 /*%%  (c) Copyright 1993, 1994 Sun Microsystems, Inc.                    */
26 /*%%  (c) Copyright 1993, 1994 Novell, Inc.                              */
27 /*%%  $XConsortium: isvarrec.c /main/3 1995/10/23 11:45:36 rswiston $                                                    */
28 #ifndef lint
29 static char sccsid[] = "@(#)isvarrec.c 1.8 89/07/17 Copyr 1988 Sun Micro";
30 #endif
31 /*
32  * Copyright (c) 1988 by Sun Microsystems, Inc.
33  */
34
35 /*
36  * isvarrec.c
37  *
38  * Description:
39  *      Fixed length record access (VLRA) module.
40  */
41
42 #include "isam_impl.h"
43
44 /* Local functions */
45 long _vl_getpos();                           /* Get offset in .rec file */
46 int  _vl_deleted();                          /* 0/1 returns 1 if record is deleted */
47 static void remove_from_chain2();            /* used by _vlrec_wrrec() */
48 long _istail_insert();
49 static void _istail_delete();
50 static _istail_read();
51
52 /*
53  * _vlrec_write(fcb, record, recnum, reclen)
54  *
55  * Write a record.
56  *
57  * Input params:
58  *      FCB     File Control Block
59  *      record  record buffer
60  *      reclen  record length (NOT USED)
61  *
62  * Output params:
63  *      recnum  record number of the new record
64  *
65  * Returns 0 if record was written successfully, or -1 if any error.
66  */
67
68 /*ARGSUSED*/
69 int
70 _vlrec_write(Fcb *fcb, char *record, Recno *recnum, int reclen)
71 {
72     Recno               recnum2;
73     long                rec_position;
74     long                tailoff = VL_RECNOTAIL;
75     char                recnobuf [RECNOSIZE];
76     char                tailoffbuf[LONGSIZE];
77
78     /*
79      * Reuse a deleted record if one exits.
80      * Otherwise, extend .rec file by a record.
81      */
82     if (fcb->freerecno != NULL_RECNO) {
83         recnum2 = fcb->freerecno;
84
85         /*
86          * Remove record from the chain of deleted records.
87          */
88         rec_position = _vl_getpos(fcb, recnum2); /* Offset in .rec file */
89         _cp_fromfile(fcb, fcb->datfd, recnobuf, rec_position + LONGSIZE, RECNOSIZE);
90         fcb->freerecno = ldrecno(recnobuf);
91     }
92     else {
93         recnum2 = ++(fcb->lastrecno);
94
95         /* 
96          * Extend .rec file size if necessary.
97          */
98         while (_vl_getpos(fcb, recnum2 + 1) > fcb->datsize * ISPAGESIZE) {
99             fcb->datsize = _extend_file(fcb, fcb->datfd, fcb->datsize);
100         }
101         rec_position = _vl_getpos(fcb, recnum2); /* Offset in .rec file */
102     }
103
104     /* 
105      * Store variable part of record (the 'tail') in .var file.
106      */
107     tailoff = _istail_insert(fcb, record + fcb->minreclen, 
108                              reclen - fcb->minreclen);
109
110     /*
111      * Copy record to the .rec file. Mark record as undeleted.
112      */
113     stlong(tailoff, tailoffbuf);
114     _cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE); 
115     _cp_tofile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen); 
116
117     *recnum = recnum2;
118
119     return (ISOK);
120 }
121
122 /*
123  * _vlrec_read(fcb, record, recnum, reclen)
124  *
125  * Read a record.
126  *
127  * Input params:
128  *      FCB     File Control Block
129  *      recnum  record number of the record
130  *      reclen  filled with the record size for compatibilty with
131  *              variable length records
132  *
133  * Output params:
134  *      record  record buffer is filled with data
135  *
136  * Returns 0 if record was read successfully, or error code if any error.
137  */
138
139 int
140 _vlrec_read(Fcb *fcb, char *record, Recno recnum, int *reclen)
141 {
142     long                rec_position;
143     long                tailoff;
144     char                tailoffbuf[LONGSIZE];
145
146     /*
147      * Check that recnum is within the range of existing record numbers.
148      */
149     if (recnum < 1 || recnum > fcb->lastrecno)
150         return (EENDFILE);
151
152     rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
153
154     /*
155      * Check that the record is not marked as deleted.
156      */
157     _cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
158     tailoff = ldlong(tailoffbuf);
159     if (tailoff == VL_RECDELETED) {
160         return (ENOREC);
161     }
162
163     /*
164      * Copy record from the .at file. 
165      */
166     _cp_fromfile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen); 
167
168     *reclen = fcb->minreclen;
169
170     /*
171      * Get the 'tail' of the record if any.
172      */
173     *reclen += _istail_read(fcb, tailoff, record + fcb->minreclen);
174
175     if (*reclen > fcb->maxreclen)
176         _isfatal_error("Corrupted file: too long variable length record");
177
178     return (ISOK);
179 }
180
181 /*
182  * pos = _vl_getpos(fcb, recnum)
183  *
184  * Calculate the position of record in .rec file.
185  */
186
187 long
188 _vl_getpos(Fcb *fcb, Recno recnum)
189 {
190     return ((long)(ISCNTLSIZE + (fcb->minreclen + LONGSIZE) * (recnum -1)));
191 }
192
193 /*
194  * _vlrec_rewrite(fcb, record, recnum, reclen)
195  *
196  * Rewrite a record.
197  *
198  * Input params:
199  *      FCB     File Control Block
200  *      recnum  record number of the record
201  *      record  new record
202  *      int     reclen (NOT USED)
203  *
204  * Returns 0 if record was rewritten successfully, or error code if any error.
205  */
206
207 /*ARGSUSED*/
208 int
209 _vlrec_rewrite(Fcb *fcb, char *record, Recno recnum, int reclen)
210 {
211     long                rec_position;
212     long                tailoff;
213     char                tailoffbuf[LONGSIZE];
214
215     /*
216      * Check that recnum is within the range of existing record numbers.
217      */
218     if (recnum < 1 || recnum > fcb->lastrecno)
219         return (EENDFILE);
220
221     rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
222
223     /*
224      * Check that the record is not marked as deleted.
225      */
226     _cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE); 
227     tailoff = ldlong(tailoffbuf);
228     if (tailoff == VL_RECDELETED) {
229         return (ENOREC);
230     }
231
232     /* 
233      * Store variable part of record (the 'tail') in .var file.
234      */
235     tailoff = _istail_modify(fcb, tailoff, record + fcb->minreclen, 
236                              reclen - fcb->minreclen);
237
238     /*
239      * Copy new record to the .rec file. 
240      */
241     stlong(tailoff, tailoffbuf);
242     _cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
243     _cp_tofile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen); 
244
245     return (ISOK);
246 }
247
248 /*
249  * _vlrec_delete;(fcb, recnum)
250  *
251  * Rewrite a record.
252  *
253  * Input params:
254  *      FCB     File Control Block
255  *      recnum  record number of the record
256  *
257  * Returns 0 if record was rewritten successfully, or error code if any error.
258  */
259
260 int
261 _vlrec_delete(Fcb *fcb, Recno recnum)
262 {
263     long                rec_position;
264     long                tailoff;
265     char                tailoffbuf[LONGSIZE];
266     char                recnobuf [RECNOSIZE];
267
268     /*
269      * Check that recnum is within the range of existing record numbers.
270      */
271     if (recnum < 1 || recnum > fcb->lastrecno)
272         return (EENDFILE);
273
274     rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
275
276     /*
277      * Check that the record is not marked as deleted.
278      */
279     _cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE); 
280     tailoff = ldlong(tailoffbuf);
281     if (tailoff == VL_RECDELETED) {
282         return (ENOREC);
283     }
284
285     /*
286      * Set the delete flag to VL_RECDELETED.
287      */
288     tailoff = VL_RECDELETED;
289     stlong(tailoff, tailoffbuf);
290     _cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
291
292     /*
293      * Insert record into chain of deleted records.
294      */
295     strecno(fcb->freerecno, recnobuf);
296     _cp_tofile(fcb, fcb->datfd, recnobuf, rec_position + LONGSIZE, RECNOSIZE);
297     fcb->freerecno = recnum;
298
299     /*
300      * Delete tail from .var file.
301      */
302
303     return (ISOK);
304 }
305
306 /*
307  * _vlrec_wrrec(fcb, record, recnum, reclen)
308  *
309  * Write a record by record number.
310  *
311  * Input params:
312  *      FCB     File Control Block
313  *      recnum  record number of the record
314  *      record  record buffer
315  *      int     reclen (NOT USED)
316  *
317  * Returns 0 if record was written successfully, or error code if any error.
318  *
319  * Note that _vlrec_wrrec() commits updates and syncs the FCB to avoid
320  *      buffer pool overflow.
321  */
322
323 /*ARGSUSED*/
324 int
325 _vlrec_wrrec(Fcb *fcb, char *record, Recno recnum, int reclen)
326 {
327     long                rec_position;
328     long                tailoff;
329     char                tailoffbuf[LONGSIZE];
330     Recno               recnum2;
331     char                recnumbuf [RECNOSIZE];
332
333     /*
334      * Check that recnum is not negative.
335      */
336     if (recnum < 1)
337         return (EBADARG);
338
339     rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
340
341     if (recnum > fcb->lastrecno)  {
342
343         /*
344          * If the recnum is bigger than the highest record number in the .rec
345          * file, extend the .rec file.
346          */
347         while (_vl_getpos(fcb, recnum + 1) > fcb->datsize * ISPAGESIZE) {
348             fcb->datsize = _extend_file(fcb, fcb->datfd, fcb->datsize);
349             
350             /* Sync the updates to avoid buffer pool overflow. */
351             _isdisk_commit();
352             _isdisk_sync();
353             (void)_isfcb_cntlpg_w2(fcb);
354         }
355
356         /*
357          * Mark all records in the range <fcb->lastrecno+1, recnum>  as
358          * deleted.
359          */
360         tailoff = VL_RECDELETED;
361         stlong(tailoff, tailoffbuf);
362         for (recnum2 = fcb->lastrecno + 1; recnum2 <= recnum; recnum2++) {      
363             _cp_tofile(fcb, fcb->datfd, tailoffbuf, _vl_getpos(fcb, recnum2), LONGSIZE); 
364             strecno(fcb->freerecno, recnumbuf);
365             _cp_tofile(fcb, fcb->datfd, recnumbuf,
366                        _vl_getpos(fcb, recnum2) + LONGSIZE, RECNOSIZE); 
367             fcb->freerecno = recnum2;
368             
369             /* Sync the updates to avoid buffer pool overflow. */
370             _isdisk_commit();
371             _isdisk_sync();
372             fcb->lastrecno = recnum;
373             (void)_isfcb_cntlpg_w2(fcb);
374         }
375         
376         /*
377          * Note that the disk structures are in a consistent state now,
378          * the .rec was extended by a few records marked as 'deleted'.
379          * This is important for subsequent rollbacks.
380          */
381     } 
382
383     /*
384      * If recnum specifies a record that has existed, check whether it
385      * has been deleted. _vlrec_wrrec() does not override existing record.
386      */
387     _cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE); 
388     tailoff = ldlong(tailoffbuf);
389     if (tailoff != VL_RECDELETED) {
390         return (EDUPL);
391     }
392
393     /*
394      * Remove the record from the chain of deleted records.
395      */
396     remove_from_chain2(fcb, recnum);
397
398     /* 
399      * Store variable part of record (the 'tail') in .var file.
400      */
401     tailoff = _istail_insert(fcb, record + fcb->minreclen, reclen - fcb->minreclen);
402
403     /*
404      * Copy new record to the .rec file. 
405      */
406     stlong(tailoff, tailoffbuf);
407     _cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE); 
408     _cp_tofile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen); 
409
410     return (ISOK);
411 }
412
413 /*
414  * remove_from_chain(fcb, recnum)
415  *
416  * Remove record from the chain of deleted records.
417  */
418
419 static void
420 remove_from_chain2(Fcb *fcb, Recno recnum)
421 {
422     char                recnobuf1 [RECNOSIZE] , recnobuf2 [RECNOSIZE];
423     long                pos1, pos2;
424     Recno               recnum2;
425
426     pos1 = _vl_getpos(fcb, recnum);
427     _cp_fromfile(fcb, fcb->datfd, recnobuf1, pos1 + LONGSIZE, RECNOSIZE); 
428
429     if (fcb->freerecno == recnum) {
430         fcb->freerecno = ldrecno(recnobuf1);
431     }
432     else {
433         recnum2 = fcb->freerecno;
434         do {
435             pos2 = _vl_getpos(fcb, recnum2);
436             _cp_fromfile(fcb, fcb->datfd, recnobuf2, pos2 + LONGSIZE, RECNOSIZE); 
437             recnum2 = ldrecno(recnobuf2);
438         } while (recnum2 != recnum && recnum2 != NULL_RECNO);
439
440         _cp_tofile(fcb, fcb->datfd, recnobuf1, pos2 + LONGSIZE, RECNOSIZE); 
441     }
442 }
443
444
445 /*
446  * The following are functions that manipulate the 'tails' of variable
447  * records.  The tail is the actual record with the fixed part removed
448  * (fixed part starts at offset zero and its length is minimum record 
449  * length.  The tails are stored in the .var file.
450  */
451
452
453 /* Insert tail into .var file. Return offset in .var file */
454
455 long _istail_insert(Fcb *fcb, char *tailp, int taillen)
456 {
457     char                frameheadbuf [2 * SHORTSIZE];
458     int                 framelen;
459     long                offset;
460
461 /*    printf ("_insert called, taillen %d\n", taillen); */
462
463     if (taillen == 0)
464         return (VL_RECNOTAIL);
465
466     framelen = taillen + 2 * SHORTSIZE;
467
468     /*
469      * Set up frame header.
470      */
471     stshort((short)taillen, frameheadbuf + VR_FRAMELEN_OFF);
472     stshort((short)taillen, frameheadbuf + VR_TAILLEN_OFF);
473
474     offset = fcb->varend;
475
476     /*
477      * Extend .var file if that is necesary.    
478      */
479     while (offset + framelen > fcb->varsize * ISPAGESIZE)
480         fcb->varsize = _extend_file(fcb, fcb->varfd, fcb->varsize);
481
482     /*
483      * Copy frame head and tail to .var file.
484      */
485     _cp_tofile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
486     _cp_tofile(fcb, fcb->varfd, tailp, offset + 2 * SHORTSIZE, taillen);
487  
488     fcb->varend += taillen + 2 * SHORTSIZE;
489
490     return (offset);
491 }
492
493 /* Remove tail from .var file */
494
495 /* ARGSUSED */
496 Static void _istail_delete(Fcb *fcb, long offset)
497 {
498     /* 
499      * Don't do anything in NetISAM 1.0. The tails are lost, the space
500      * will be re-used after next restructuring: "copy -c file" command
501      */
502     return;
503 }
504
505 /* Read tail from .var file */
506
507 Static _istail_read(Fcb *fcb, long offset, char *buffer)
508 {
509     char                frameheadbuf [2 * SHORTSIZE];
510     int                 taillen;
511
512 /*    printf ("_read called, offset %d\n", offset); */
513
514     if (offset == VL_RECNOTAIL)
515         return (0);
516
517     /* 
518      * Read frame header.
519      */
520      _cp_fromfile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
521     taillen = ldshort(frameheadbuf + VR_TAILLEN_OFF);
522      _cp_fromfile(fcb, fcb->varfd, buffer, offset + 2 * SHORTSIZE, taillen);
523     
524     return (taillen);
525 }
526     
527 /* Rewrite tail. Returns -1 if the new tail is longer than the original frame */
528
529 int _istail_modify(Fcb *fcb, long offset, char *tailp, int taillen)
530 {
531     char                frameheadbuf [2 * SHORTSIZE];
532     int                 framelen;
533
534     /*
535      * Trivial case: no old frame, no new tail.
536      */
537     if (offset == VL_RECNOTAIL && taillen == 0)
538         return (offset);
539
540     if (offset != VL_RECNOTAIL) {
541         /* 
542          * Read frame header.
543          */
544         _cp_fromfile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
545         framelen = ldshort(frameheadbuf + VR_FRAMELEN_OFF);
546     }
547     else
548         framelen = 0;
549
550     if (taillen > framelen) {
551         /* 
552          * Delete the old frame if the new tail does not fit.
553          * Insert the new tail at the end of .var file.
554          */
555
556         _istail_delete(fcb, offset);
557         return (_istail_insert(fcb, tailp, taillen));
558     }
559     else {
560         /*
561          * The new tail fits in the existing frame.
562          */
563         stshort((short)taillen, frameheadbuf + VR_TAILLEN_OFF);
564         _cp_tofile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
565         _cp_tofile(fcb, fcb->varfd, tailp, offset + 2 * SHORTSIZE, taillen);
566
567         return (offset);
568     }
569 }