2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
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 $ */
29 static char sccsid[] = "@(#)isstart.c 1.9 89/07/17 Copyr 1988 Sun Micro";
32 * Copyright (c) 1988 by Sun Microsystems, Inc.
39 * Select index and set record position.
43 #include "isam_impl.h"
47 static int _amstart();
50 * err = isstart(isfd, keydesc, length, record, mode)
52 * Isstart() selects index for subsequent read operations and set new
53 * current record position.
55 * isrecnum is set to indicate the start record.
58 * Returns 0 if successful, or -1 of any error.
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.
70 isstart(int isfd, struct keydesc *keydesc, int length, char *record,
77 enum readmode readmode;
78 char dummy_record [1]; /* used for ISFIRST and ISLAST */
82 * Get File Access Block.
84 if ((fab = _isfd_find(isfd)) == NULL) {
85 _setiserrno2(ENOTOPEN, '9', '0');
90 * Check that the open mode was ISINPUT, or ISINOUT.
92 if (fab->openmode != OM_INPUT && fab->openmode != OM_INOUT) {
93 _setiserrno2(ENOTOPEN, '9', '0');
100 if ((readmode = _getreadmode(mode)) == RM_BADMODE) {
101 _setiserrno2(EBADARG, '9', '0');
106 * Some arguments are used only when a particular mode is specified.
108 if (readmode == RM_FIRST || readmode == RM_LAST || USE_PHYS_ORDER(keydesc)) {
109 precord = dummy_record;
114 reclen = fab->minreclen;
117 reclen = fab->minreclen;
121 if ((ret = _amstart(&fab->isfhandle, precord, reclen,
122 readmode, keydesc, length, &fab->curpos,
123 &recnum, &fab->errcode)) == ISOK) {
124 isrecnum = recnum; /* Set isrecnum */
127 _seterr_errcode(&fab->errcode);
129 return (ret); /* Successful start */
133 * _amstart(isfhandle, record, reclen, readmode,
134 * keydesc, keylen, curpos, recnum, errcode)
136 * _amstart() reads a record from ISAM file
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
148 * curpos new current position
149 * recnum record number
150 * errcode error status of the operation
151 * reclen actual length of the record
154 * Successfull isstart() returns the new curpos and frees the old curpos.
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)
167 char recbuf [ISMAXRECLEN];
171 char keybuf1 [MAXKEYSIZE], keybuf2 [MAXKEYSIZE];
182 * Get FCB corresponding to the isfhandle handle.
184 if ((fcb = _openfcb(isfhandle, errcode)) == NULL) {
189 rec_read = (fcb->varflag?_vlrec_read:_flrec_read);
192 * Update information in FCB from CNTL page on the disk
194 (void)_isfcb_cntlpg_r2(fcb);
196 if (USE_PHYS_ORDER(keydesc)) {
198 * Physical order in use.
202 * Allocate new current position structure.
204 newcrpsize = sizeof(*newcrp);
205 newcrp = (Crp *) _ismalloc(sizeof(*newcrp));
206 memset ((char *)newcrp, 0, sizeof(*newcrp));
207 newcrp->keyid = PHYS_ORDER;
211 recnum2 = *recnum; /* passed from isrecnum */
212 if ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK) {
213 _amseterrcode(errcode, ENOREC);
216 newcrp->flag = CRP_BEFORE;
217 newcrp->recno = recnum2;
221 recnum2 = *recnum + 1;
222 if (recnum2 < 1) recnum2 = 1;
224 * Skip deleted records.
226 while ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK &&
231 _amseterrcode(errcode, ENOREC);
234 newcrp->flag = CRP_BEFORE;
235 newcrp->recno = recnum2;
240 if (recnum2 < 1) recnum2 = 1;
242 * Skip deleted records.
244 while ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK &&
249 _amseterrcode(errcode, ENOREC);
252 newcrp->flag = CRP_BEFORE;
253 newcrp->recno = recnum2;
257 recnum2 = *recnum - 1;
258 if (recnum2 > fcb->lastrecno) recnum2 = fcb->lastrecno;
260 * Skip deleted records.
262 while ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK &&
267 _amseterrcode(errcode, ENOREC);
270 newcrp->flag = CRP_AFTER;
271 newcrp->recno = recnum2;
276 if (recnum2 > fcb->lastrecno) recnum2 = fcb->lastrecno;
278 * Skip deleted records.
280 while ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK &&
285 _amseterrcode(errcode, ENOREC);
288 newcrp->flag = CRP_AFTER;
289 newcrp->recno = recnum2;
295 * Skip deleted records.
297 while ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK &&
302 newcrp->flag = CRP_BEFORE;
303 newcrp->recno = recnum2;
306 newcrp->flag = CRP_AFTERANY;
310 recnum2 = fcb->lastrecno;
312 * Skip deleted records.
314 while ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK &&
319 newcrp->flag = CRP_AFTER;
320 newcrp->recno = recnum2;
323 newcrp->flag = CRP_BEFOREANY;
327 _isfatal_error("Invalid readmode");
333 * Build new curpos, deallocate old curpos.
335 _bytearr_free(curpos);
336 *curpos = _bytearr_new(sizeof(*newcrp), (char *)newcrp);
338 } /* physical order */
342 * Use order defined by some key.
346 * Check key descriptor for validity.
348 if (_validate_keydesc(keydesc, fcb->minreclen) != ISOK) {
349 _amseterrcode(errcode, EBADKEY);
354 * Convert key descriptor to internal form.
356 _iskey_xtoi (&keydesc2, keydesc);
358 /* Find key decriptor in the FCB. */
359 if ((pkeydesc2 = _isfcb_findkey(fcb ,&keydesc2)) == NULL) {
360 _amseterrcode(errcode, EBADKEY);
365 * skipkeybytes is set to the number of bytes in the beginning
367 * RECNOSIZE for ISNODUPS keys to skip recno part
368 * RECNOSIZE + DUPIDSIZE to skip recno and duplicate serial number
370 skipbytes = RECNOSIZE;
371 if (ALLOWS_DUPS2(pkeydesc2))
372 skipbytes += DUPIDSIZE;
377 if (keylen < 0 || keylen > pkeydesc2->k2_len - skipbytes) {
378 _amseterrcode(errcode, EBADARG);
383 * Special case if keylen == 0: use the entire key.
386 matchkeylen = pkeydesc2->k2_len - skipbytes;
388 matchkeylen = keylen;
391 * Allocate new current record position.
393 newcrpsize = sizeof(Crp) + pkeydesc2->k2_len;
394 newcrp = (Crp *) _ismalloc((unsigned)newcrpsize);
395 memset((char *)newcrp, 0, newcrpsize);
397 newcrp->keyid = pkeydesc2->k2_keyid; /* Key identifier in FCB */
398 newcrp->matchkeylen = matchkeylen; /* number of bytes to match */
401 * Create B tree object.
403 btree = _isbtree_create(fcb, pkeydesc2);
409 * Make sure that you will read the first duplicate.
411 _iskey_fillmin(pkeydesc2, keybuf1);
414 * Extract key fields from record.
416 _iskey_extract(pkeydesc2, record, keybuf2);
417 memcpy( keybuf1 + skipbytes,keybuf2 + skipbytes, matchkeylen);
420 * Position pointer in the B-tree in before the searched value.
422 _isbtree_search(btree, keybuf1);
424 if ((pkey = _isbtree_next(btree)) == NULL) {
425 _amseterrcode(errcode, ENOREC);
429 if (readmode == RM_EQUAL &&
430 memcmp(keybuf1 + skipbytes, pkey + skipbytes,
432 _amseterrcode(errcode, ENOREC);
436 newcrp->flag = CRP_BEFORE;
437 newcrp->recno = ldrecno(pkey + KEY_RECNO_OFF);
438 memcpy( newcrp->key,pkey, pkeydesc2->k2_len);
443 * Make sure that you will read past all matching records.
445 _iskey_fillmax(pkeydesc2, keybuf1);
448 * Extract key fields from record.
450 _iskey_extract(pkeydesc2, record, keybuf2);
451 memcpy( keybuf1 + skipbytes,keybuf2 + skipbytes, matchkeylen);
454 * Position pointer in the B-tree after the searched value.
456 _isbtree_search(btree, keybuf1);
458 if ((pkey = _isbtree_next(btree)) == NULL) {
459 _amseterrcode(errcode, ENOREC);
463 newcrp->flag = CRP_BEFORE;
464 newcrp->recno = ldrecno(pkey + KEY_RECNO_OFF);
465 memcpy( newcrp->key,pkey, pkeydesc2->k2_len);
470 * Make sure that you will read before all matching records.
472 _iskey_fillmin(pkeydesc2, keybuf1);
475 * Extract key fields from record.
477 _iskey_extract(pkeydesc2, record, keybuf2);
478 memcpy( keybuf1 + skipbytes,keybuf2 + skipbytes, matchkeylen);
481 * Position pointer in the B-tree after the searched value.
483 _isbtree_search(btree, keybuf1);
485 if ((pkey = _isbtree_current(btree)) == NULL) {
486 _amseterrcode(errcode, ENOREC);
490 newcrp->flag = CRP_AFTER;
491 newcrp->recno = ldrecno(pkey + KEY_RECNO_OFF);
492 memcpy( newcrp->key,pkey, pkeydesc2->k2_len);
497 * Make sure that you will the last duplicate.
499 _iskey_fillmax(pkeydesc2, keybuf1);
502 * Extract key fields from record.
504 _iskey_extract(pkeydesc2, record, keybuf2);
505 memcpy( keybuf1 + skipbytes,keybuf2 + skipbytes, matchkeylen);
508 * Position pointer in the B-tree in before the searched value.
510 _isbtree_search(btree, keybuf1);
512 if ((pkey = _isbtree_current(btree)) == NULL) {
513 _amseterrcode(errcode, ENOREC);
517 newcrp->flag = CRP_AFTER;
518 newcrp->recno = ldrecno(pkey + KEY_RECNO_OFF);
519 memcpy( newcrp->key,pkey, pkeydesc2->k2_len);
524 * Fill key buffer with -infinity.
526 _iskey_fillmin(pkeydesc2, keybuf1);
529 * Position pointer in the B-tree before any key entry.
531 _isbtree_search(btree, keybuf1);
533 if ((pkey = _isbtree_next(btree)) == NULL) {
534 newcrp->flag = CRP_AFTERANY;
537 newcrp->flag = CRP_BEFORE;
538 newcrp->recno = ldrecno(pkey + KEY_RECNO_OFF);
539 memcpy( newcrp->key,pkey, pkeydesc2->k2_len);
545 * Fill key buffer with +infinity.
547 _iskey_fillmax(pkeydesc2, keybuf1);
550 * Position pointer in the B-tree after all entries.
552 _isbtree_search(btree, keybuf1);
554 if ((pkey = _isbtree_current(btree)) == NULL) {
555 newcrp->flag = CRP_BEFOREANY;
558 newcrp->flag = CRP_AFTER;
559 newcrp->recno = ldrecno(pkey + KEY_RECNO_OFF);
560 memcpy( newcrp->key,pkey, pkeydesc2->k2_len);
565 _isfatal_error("Invalid readmode");
568 *recnum = newcrp->recno;
571 * Build new curpos, deallocate old curpos data.
573 _bytearr_free(curpos);
574 *curpos = _bytearr_new((u_short)newcrpsize, (char *)newcrp);
576 _isbtree_destroy(btree);
579 _amseterrcode(errcode, ISOK);
584 _isdisk_commit(); /* This will only check
585 * that we unfixed all fixed
595 _isbtree_destroy(btree);
598 * If error is EBADKEY, make the current position undefined.
600 if (errcode->iserrno == EBADKEY) {
601 ((Crp *)curpos->data)->flag = CRP_UNDEF;
605 * If error is ENOREC, switch to the new key, but set the current
606 * record position undefined.
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;
615 free((char *)newcrp);