lib/tt/mini_isam: remove register keyword
[oweals/cde.git] / cde / lib / tt / mini_isam / isstart.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: isstart.c /main/3 1995/10/23 11:45:08 rswiston $                                                     */
28 #ifndef lint
29 static char sccsid[] = "@(#)isstart.c 1.9 89/07/17 Copyr 1988 Sun Micro";
30 #endif
31 /*
32  * Copyright (c) 1988 by Sun Microsystems, Inc.
33  */
34
35 /*
36  * isstart.c
37  *
38  * Description:
39  *      Select index and set record position.
40  */
41
42
43 #include "isam_impl.h"
44 #include <sys/time.h>
45 #include <stdlib.h>
46
47 static int _amstart();
48
49 /*
50  * err =  isstart(isfd, keydesc, length, record, mode)
51  *
52  * Isstart() selects index for subsequent read operations and set new
53  *      current record position.
54  *
55  * isrecnum is set to indicate the start record.
56  *
57  *
58  * Returns 0 if successful, or -1 of any error.
59  *
60  * Errors:
61  *      ENOTOPEN isfd does not correspond to an open ISAM file, or the
62  *              ISAM file was opened with ISOUTPUT mode.
63  *      EBADARG Bad mode parameter.
64  *      EBADARG keylen is out of range.
65  *      ENOREC  Specified record cannot be found (random access read).
66  *      EBADKEY Error in the key descriptor.
67  */
68
69 int 
70 isstart(int isfd, struct keydesc *keydesc, int length, char *record,
71         int mode)
72 {
73     Fab *fab;
74     int                 reclen;
75     Recno               recnum;
76     int                 ret;
77     enum readmode       readmode;
78     char                dummy_record [1];    /* used for ISFIRST and ISLAST */
79     char                *precord;
80
81     /*
82      * Get File Access Block.
83      */
84     if ((fab = _isfd_find(isfd)) == NULL) {
85         _setiserrno2(ENOTOPEN, '9', '0');
86         return (ISERROR);
87     }
88
89     /*
90      * Check that the open mode was ISINPUT, or ISINOUT.
91      */
92     if (fab->openmode != OM_INPUT && fab->openmode != OM_INOUT) {
93         _setiserrno2(ENOTOPEN, '9', '0');
94         return (ISERROR);
95     }
96
97     /*
98      * Extract read mode.
99      */
100     if ((readmode = _getreadmode(mode)) == RM_BADMODE) {
101         _setiserrno2(EBADARG, '9', '0');
102         return (ISERROR);
103     }
104
105     /*
106      * Some arguments are used only when a particular mode is specified.
107      */
108     if (readmode == RM_FIRST || readmode == RM_LAST || USE_PHYS_ORDER(keydesc)) {
109         precord = dummy_record;
110         reclen = 0;
111     }
112     else {
113         precord = record;
114         reclen = fab->minreclen;
115     }
116     
117     reclen = fab->minreclen;
118         
119     recnum = isrecnum;
120
121     if ((ret = _amstart(&fab->isfhandle, precord, reclen,
122                         readmode, keydesc, length, &fab->curpos,
123                         &recnum, &fab->errcode)) == ISOK) {
124         isrecnum = recnum;                   /* Set isrecnum */
125     }
126
127     _seterr_errcode(&fab->errcode);
128
129     return (ret);                            /* Successful start */
130 }
131
132 /*
133  * _amstart(isfhandle, record, reclen, readmode,
134  *          keydesc, keylen, curpos, recnum, errcode)
135  *
136  * _amstart() reads a record from ISAM file
137  *
138  * Input params:
139  *      isfhandle       Handle of ISAM file
140  *      readmode        Specifies access mode (random or sequential)
141  *      curpos          old record position
142  *      recnum          copy of isrecnum
143  *      keydesc         key descriptor
144  *      keylen          # of bytes of key to match
145  *      record          extract key from this record buffer
146  *
147  * Output params:
148  *      curpos          new current position
149  *      recnum          record number
150  *      errcode         error status of the operation
151  *      reclen          actual length of the record
152  *
153  * Note:
154  * Successfull isstart() returns the new curpos and frees the old curpos.
155  */
156
157 /* ARGSUSED */
158 static int
159 _amstart(Bytearray *isfhandle, char *record, int *reclen,
160          enum readmode readmode, struct keydesc *keydesc, int keylen,
161          Bytearray *curpos, Recno *recnum, struct errcode *errcode)
162 {
163     Fcb                 *fcb;
164     Recno               recnum2;
165     int                 err;
166     Crp                 *newcrp = NULL;
167     char                recbuf [ISMAXRECLEN];
168     Keydesc2            keydesc2;
169     Keydesc2            *pkeydesc2;
170     int                 newcrpsize = 0;
171     char                keybuf1 [MAXKEYSIZE], keybuf2 [MAXKEYSIZE];
172     int                 matchkeylen;
173     int                 skipbytes;
174     char                *pkey;
175     Btree               *btree = NULL;
176     int                 reclen2;
177     int                 (*rec_read)();
178
179     _isam_entryhook();
180
181     /*
182      * Get FCB corresponding to the isfhandle handle.
183      */
184     if ((fcb = _openfcb(isfhandle, errcode)) == NULL) {
185         _isam_exithook();
186         return (ISERROR);
187     }
188
189     rec_read = (fcb->varflag?_vlrec_read:_flrec_read);
190
191     /*
192      * Update information in FCB from CNTL page on the disk
193      */
194     (void)_isfcb_cntlpg_r2(fcb);
195
196     if (USE_PHYS_ORDER(keydesc)) {
197         /*
198          * Physical order in use.
199          */
200
201         /*
202          * Allocate new current position structure.
203          */
204         newcrpsize = sizeof(*newcrp);
205         newcrp = (Crp *) _ismalloc(sizeof(*newcrp));
206         memset ((char *)newcrp, 0, sizeof(*newcrp));
207         newcrp->keyid = PHYS_ORDER;
208         
209         switch (readmode) {
210         case RM_EQUAL:
211             recnum2 = *recnum;               /* passed from isrecnum */
212             if ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK) {
213                 _amseterrcode(errcode, ENOREC);
214                 goto ERROR;
215             }
216             newcrp->flag = CRP_BEFORE;
217             newcrp->recno = recnum2;
218             break;
219
220         case RM_GREAT:
221             recnum2 = *recnum + 1;
222             if (recnum2 < 1) recnum2 = 1;
223             /*
224              * Skip deleted records.
225              */
226             while ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK &&
227                    err == ENOREC) 
228                 recnum2++;
229  
230             if (err != ISOK) {
231                 _amseterrcode(errcode, ENOREC);
232                 goto ERROR;
233             }
234             newcrp->flag = CRP_BEFORE;
235             newcrp->recno = recnum2;
236             break;
237
238         case RM_GTEQ:
239             recnum2 = *recnum;
240             if (recnum2 < 1) recnum2 = 1;
241             /*
242              * Skip deleted records.
243              */
244             while ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK &&
245                    err == ENOREC) 
246                 recnum2++;
247  
248             if (err != ISOK) {
249                 _amseterrcode(errcode, ENOREC);
250                 goto ERROR;
251             }
252             newcrp->flag = CRP_BEFORE;
253             newcrp->recno = recnum2;
254             break;
255
256         case RM_LESS:
257             recnum2 = *recnum - 1;
258             if (recnum2 > fcb->lastrecno) recnum2 = fcb->lastrecno;
259             /*
260              * Skip deleted records.
261              */
262             while ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK &&
263                    err == ENOREC) 
264                 recnum2--;
265  
266             if (err != ISOK) {
267                 _amseterrcode(errcode, ENOREC);
268                 goto ERROR;
269             }
270             newcrp->flag = CRP_AFTER;
271             newcrp->recno = recnum2;
272             break;
273
274         case RM_LTEQ:
275             recnum2 = *recnum;
276             if (recnum2 > fcb->lastrecno) recnum2 = fcb->lastrecno;
277             /*
278              * Skip deleted records.
279              */
280             while ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK &&
281                    err == ENOREC) 
282                 recnum2--;
283  
284             if (err != ISOK) {
285                 _amseterrcode(errcode, ENOREC);
286                 goto ERROR;
287             }
288             newcrp->flag = CRP_AFTER;
289             newcrp->recno = recnum2;
290             break;
291
292         case RM_FIRST:
293             recnum2 = 1;
294             /*
295              * Skip deleted records.
296              */
297             while ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK &&
298                    err == ENOREC) 
299                 recnum2++;
300  
301             if (err == ISOK) {
302                 newcrp->flag = CRP_BEFORE;
303                 newcrp->recno = recnum2;
304             }
305             else {
306                 newcrp->flag = CRP_AFTERANY;
307             }
308             break;
309         case RM_LAST:
310             recnum2 = fcb->lastrecno;
311             /*
312              * Skip deleted records.
313              */
314             while ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK &&
315                    err == ENOREC) 
316                 recnum2--;
317
318             if (err == ISOK) {
319                 newcrp->flag = CRP_AFTER;
320                 newcrp->recno = recnum2;
321             }
322             else {
323                 newcrp->flag = CRP_BEFOREANY;
324             }
325             break;
326         default:
327             _isfatal_error("Invalid readmode");
328         }
329
330         *recnum = recnum2;
331
332         /*
333          * Build new curpos, deallocate old curpos.
334          */
335         _bytearr_free(curpos);
336         *curpos = _bytearr_new(sizeof(*newcrp), (char *)newcrp);
337
338     } /* physical order */
339     else {
340
341         /*
342          * Use order defined by some key.
343          */
344         
345         /*
346          * Check key descriptor for validity.
347          */
348         if (_validate_keydesc(keydesc, fcb->minreclen) != ISOK) {
349             _amseterrcode(errcode, EBADKEY);
350             goto ERROR;
351         }
352         
353         /*
354          * Convert key descriptor to internal form.
355          */
356         _iskey_xtoi (&keydesc2, keydesc);
357         
358         /* Find key decriptor in the FCB. */
359         if ((pkeydesc2 = _isfcb_findkey(fcb ,&keydesc2)) == NULL) {
360             _amseterrcode(errcode, EBADKEY);
361             goto ERROR;
362         }
363
364         /*
365          * skipkeybytes is set to the number of bytes in the beginning
366          * of the key:
367          *  RECNOSIZE for ISNODUPS keys to skip recno part
368          *  RECNOSIZE + DUPIDSIZE to skip recno and duplicate serial number
369          */
370         skipbytes = RECNOSIZE;
371         if (ALLOWS_DUPS2(pkeydesc2))
372             skipbytes += DUPIDSIZE;
373
374         /*
375          * Validate keylen.
376          */
377         if (keylen < 0 || keylen > pkeydesc2->k2_len - skipbytes) {
378             _amseterrcode(errcode, EBADARG);
379             goto ERROR;
380         }
381
382         /*
383          * Special case if keylen == 0: use the entire key.
384          */
385         if (keylen == 0)
386             matchkeylen = pkeydesc2->k2_len - skipbytes;
387         else
388             matchkeylen = keylen;
389
390         /*
391          * Allocate new current record position.
392          */
393         newcrpsize = sizeof(Crp) + pkeydesc2->k2_len;
394         newcrp = (Crp *) _ismalloc((unsigned)newcrpsize);
395         memset((char *)newcrp, 0, newcrpsize);
396
397         newcrp->keyid = pkeydesc2->k2_keyid; /* Key identifier in FCB */
398         newcrp->matchkeylen = matchkeylen;   /* number of bytes to match */
399
400         /*
401          * Create B tree object.
402          */
403         btree = _isbtree_create(fcb, pkeydesc2);
404
405         switch (readmode) {
406         case RM_EQUAL:
407         case RM_GTEQ:
408             /* 
409              * Make sure that you will read the first duplicate. 
410              */
411             _iskey_fillmin(pkeydesc2, keybuf1);
412  
413             /* 
414              * Extract key fields from record. 
415              */
416             _iskey_extract(pkeydesc2, record, keybuf2);
417             memcpy( keybuf1 + skipbytes,keybuf2 + skipbytes, matchkeylen);
418
419             /*
420              * Position pointer in the B-tree in before the searched value. 
421              */
422             _isbtree_search(btree, keybuf1);
423         
424             if ((pkey = _isbtree_next(btree)) == NULL) {
425                 _amseterrcode(errcode, ENOREC);
426                 goto ERROR;
427             }
428             
429             if (readmode == RM_EQUAL &&
430                 memcmp(keybuf1 + skipbytes, pkey + skipbytes, 
431                        matchkeylen) != 0) {
432                 _amseterrcode(errcode, ENOREC);
433                 goto ERROR;
434             }
435
436             newcrp->flag = CRP_BEFORE;
437             newcrp->recno = ldrecno(pkey + KEY_RECNO_OFF);
438             memcpy( newcrp->key,pkey, pkeydesc2->k2_len);
439             break;
440
441         case RM_GREAT:
442             /* 
443              * Make sure that you will read past all matching records.
444              */
445             _iskey_fillmax(pkeydesc2, keybuf1);
446  
447             /* 
448              * Extract key fields from record. 
449              */
450             _iskey_extract(pkeydesc2, record, keybuf2);
451             memcpy( keybuf1 + skipbytes,keybuf2 + skipbytes, matchkeylen);
452
453             /*
454              * Position pointer in the B-tree after the searched value. 
455              */
456             _isbtree_search(btree, keybuf1);
457         
458             if ((pkey = _isbtree_next(btree)) == NULL) {
459                 _amseterrcode(errcode, ENOREC);
460                 goto ERROR;
461             }
462             
463             newcrp->flag = CRP_BEFORE;
464             newcrp->recno = ldrecno(pkey + KEY_RECNO_OFF);
465             memcpy( newcrp->key,pkey, pkeydesc2->k2_len);
466             break;
467             
468         case RM_LESS:
469             /* 
470              * Make sure that you will read before all matching records.
471              */
472             _iskey_fillmin(pkeydesc2, keybuf1);
473  
474             /* 
475              * Extract key fields from record. 
476              */
477             _iskey_extract(pkeydesc2, record, keybuf2);
478             memcpy( keybuf1 + skipbytes,keybuf2 + skipbytes, matchkeylen);
479
480             /*
481              * Position pointer in the B-tree after the searched value. 
482              */
483             _isbtree_search(btree, keybuf1);
484         
485             if ((pkey = _isbtree_current(btree)) == NULL) {
486                 _amseterrcode(errcode, ENOREC);
487                 goto ERROR;
488             }
489             
490             newcrp->flag = CRP_AFTER;
491             newcrp->recno = ldrecno(pkey + KEY_RECNO_OFF);
492             memcpy( newcrp->key,pkey, pkeydesc2->k2_len);
493             break;
494
495         case RM_LTEQ:
496             /* 
497              * Make sure that you will the last duplicate.
498              */
499             _iskey_fillmax(pkeydesc2, keybuf1);
500  
501             /* 
502              * Extract key fields from record. 
503              */
504             _iskey_extract(pkeydesc2, record, keybuf2);
505             memcpy( keybuf1 + skipbytes,keybuf2 + skipbytes, matchkeylen);
506
507             /*
508              * Position pointer in the B-tree in before the searched value. 
509              */
510             _isbtree_search(btree, keybuf1);
511         
512             if ((pkey = _isbtree_current(btree)) == NULL) {
513                 _amseterrcode(errcode, ENOREC);
514                 goto ERROR;
515             }
516             
517             newcrp->flag = CRP_AFTER;
518             newcrp->recno = ldrecno(pkey + KEY_RECNO_OFF);
519             memcpy( newcrp->key,pkey, pkeydesc2->k2_len);
520             break;
521
522         case RM_FIRST:
523             /* 
524              * Fill key buffer with -infinity.
525              */
526             _iskey_fillmin(pkeydesc2, keybuf1);
527  
528             /*
529              * Position pointer in the B-tree before any key entry.
530              */
531             _isbtree_search(btree, keybuf1);
532         
533             if ((pkey = _isbtree_next(btree)) == NULL) {
534                 newcrp->flag = CRP_AFTERANY;
535             }
536             else {
537                 newcrp->flag = CRP_BEFORE;
538                 newcrp->recno = ldrecno(pkey + KEY_RECNO_OFF);
539                 memcpy( newcrp->key,pkey, pkeydesc2->k2_len);
540             }
541             break;
542
543         case RM_LAST:
544             /* 
545              * Fill key buffer with +infinity.
546              */
547             _iskey_fillmax(pkeydesc2, keybuf1);
548  
549             /*
550              * Position pointer in the B-tree after all entries.
551              */
552             _isbtree_search(btree, keybuf1);
553         
554             if ((pkey = _isbtree_current(btree)) == NULL) {
555                 newcrp->flag = CRP_BEFOREANY;
556             }
557             else {
558                 newcrp->flag = CRP_AFTER;
559                 newcrp->recno = ldrecno(pkey + KEY_RECNO_OFF);
560                 memcpy( newcrp->key,pkey, pkeydesc2->k2_len);
561             }
562             break;
563
564         default:
565             _isfatal_error("Invalid readmode");
566         }
567
568         *recnum = newcrp->recno;
569
570         /*
571          * Build new curpos, deallocate old curpos data.
572          */
573         _bytearr_free(curpos);
574         *curpos = _bytearr_new((u_short)newcrpsize, (char *)newcrp);
575
576         _isbtree_destroy(btree);
577     }
578
579     _amseterrcode(errcode, ISOK);
580
581     /* Clean-up work. */
582     free(newcrp);
583
584     _isdisk_commit();                        /* This will only check
585                                               * that we unfixed all fixed
586                                               * buffers */
587     _isdisk_inval();
588
589     _isam_exithook();
590     return (ISOK);
591
592  ERROR:
593
594     if (btree != NULL)
595         _isbtree_destroy(btree);
596
597     /*
598      * If error is EBADKEY, make the current position undefined.
599      */
600     if (errcode->iserrno == EBADKEY) {
601         ((Crp *)curpos->data)->flag = CRP_UNDEF;
602     }
603
604     /*
605      * If error is ENOREC, switch to the new key, but set the current
606      * record position undefined.
607      */
608     if (errcode->iserrno == ENOREC && newcrp != NULL) {
609         _bytearr_free(curpos);
610         *curpos = _bytearr_new((u_short)newcrpsize, (char *)newcrp);
611         ((Crp *)curpos->data)->flag = CRP_UNDEF;
612     }
613
614     if (newcrp != NULL)
615         free((char *)newcrp);
616     _isdisk_inval();
617
618     _isam_exithook();
619     return (ISERROR);
620 }
621
622