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 librararies 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"
46 static int _amstart();
49 * err = isstart(isfd, keydesc, length, record, mode)
51 * Isstart() selects index for subsequent read operations and set new
52 * current record position.
54 * isrecnum is set to indicate the start record.
57 * Returns 0 if successful, or -1 of any error.
60 * ENOTOPEN isfd does not correspond to an open ISAM file, or the
61 * ISAM file was opened with ISOUTPUT mode.
62 * EBADARG Bad mode parameter.
63 * EBADARG keylen is out of range.
64 * ENOREC Specified record cannot be found (random access read).
65 * EBADKEY Error in the key descriptor.
69 isstart(isfd, keydesc, length, record, mode)
71 struct keydesc *keydesc;
80 enum readmode readmode;
81 char dummy_record [1]; /* used for ISFIRST and ISLAST */
85 * Get File Access Block.
87 if ((fab = _isfd_find(isfd)) == NULL) {
88 _setiserrno2(ENOTOPEN, '9', '0');
93 * Check that the open mode was ISINPUT, or ISINOUT.
95 if (fab->openmode != OM_INPUT && fab->openmode != OM_INOUT) {
96 _setiserrno2(ENOTOPEN, '9', '0');
103 if ((readmode = _getreadmode(mode)) == RM_BADMODE) {
104 _setiserrno2(EBADARG, '9', '0');
109 * Some arguments are used only when a particular mode is specified.
111 if (readmode == RM_FIRST || readmode == RM_LAST || USE_PHYS_ORDER(keydesc)) {
112 precord = dummy_record;
117 reclen = fab->minreclen;
120 reclen = fab->minreclen;
124 if ((ret = _amstart(&fab->isfhandle, precord, reclen,
125 readmode, keydesc, length, &fab->curpos,
126 &recnum, &fab->errcode)) == ISOK) {
127 isrecnum = recnum; /* Set isrecnum */
130 _seterr_errcode(&fab->errcode);
132 return (ret); /* Successful start */
136 * _amstart(isfhandle, record, reclen, readmode,
137 * keydesc, keylen, curpos, recnum, errcode)
139 * _amstart() reads a record from ISAM file
142 * isfhandle Handle of ISAM file
143 * readmode Specifies access mode (random or sequential)
144 * curpos old record position
145 * recnum copy of isrecnum
146 * keydesc key descriptor
147 * keylen # of bytes of key to match
148 * record extract key from this record buffer
151 * curpos new current position
152 * recnum record number
153 * errcode error status of the operation
154 * reclen actual length of the record
157 * Successfull isstart() returns the new curpos and frees the old curpos.
162 _amstart(isfhandle, record, reclen, readmode,
163 keydesc, keylen, curpos, recnum, errcode)
164 Bytearray *isfhandle;
165 enum readmode readmode;
170 struct errcode *errcode;
171 struct keydesc *keydesc;
178 char recbuf [ISMAXRECLEN];
182 char keybuf1 [MAXKEYSIZE], keybuf2 [MAXKEYSIZE];
193 * Get FCB corresponding to the isfhandle handle.
195 if ((fcb = _openfcb(isfhandle, errcode)) == NULL) {
200 rec_read = (fcb->varflag?_vlrec_read:_flrec_read);
203 * Update information in FCB from CNTL page on the disk
205 (void)_isfcb_cntlpg_r2(fcb);
207 if (USE_PHYS_ORDER(keydesc)) {
209 * Physical order in use.
213 * Allocate new current position structure.
215 newcrpsize = sizeof(*newcrp);
216 newcrp = (Crp *) _ismalloc(sizeof(*newcrp));
217 memset ((char *)newcrp, 0, sizeof(*newcrp));
218 newcrp->keyid = PHYS_ORDER;
222 recnum2 = *recnum; /* passed from isrecnum */
223 if ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK) {
224 _amseterrcode(errcode, ENOREC);
227 newcrp->flag = CRP_BEFORE;
228 newcrp->recno = recnum2;
232 recnum2 = *recnum + 1;
233 if (recnum2 < 1) recnum2 = 1;
235 * Skip deleted records.
237 while ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK &&
242 _amseterrcode(errcode, ENOREC);
245 newcrp->flag = CRP_BEFORE;
246 newcrp->recno = recnum2;
251 if (recnum2 < 1) recnum2 = 1;
253 * Skip deleted records.
255 while ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK &&
260 _amseterrcode(errcode, ENOREC);
263 newcrp->flag = CRP_BEFORE;
264 newcrp->recno = recnum2;
268 recnum2 = *recnum - 1;
269 if (recnum2 > fcb->lastrecno) recnum2 = fcb->lastrecno;
271 * Skip deleted records.
273 while ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK &&
278 _amseterrcode(errcode, ENOREC);
281 newcrp->flag = CRP_AFTER;
282 newcrp->recno = recnum2;
287 if (recnum2 > fcb->lastrecno) recnum2 = fcb->lastrecno;
289 * Skip deleted records.
291 while ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK &&
296 _amseterrcode(errcode, ENOREC);
299 newcrp->flag = CRP_AFTER;
300 newcrp->recno = recnum2;
306 * Skip deleted records.
308 while ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK &&
313 newcrp->flag = CRP_BEFORE;
314 newcrp->recno = recnum2;
317 newcrp->flag = CRP_AFTERANY;
321 recnum2 = fcb->lastrecno;
323 * Skip deleted records.
325 while ((err = rec_read(fcb, recbuf, recnum2, &reclen2)) != ISOK &&
330 newcrp->flag = CRP_AFTER;
331 newcrp->recno = recnum2;
334 newcrp->flag = CRP_BEFOREANY;
338 _isfatal_error("Invalid readmode");
344 * Build new curpos, deallocate old curpos.
346 _bytearr_free(curpos);
347 *curpos = _bytearr_new(sizeof(*newcrp), (char *)newcrp);
349 } /* physical order */
353 * Use order defined by some key.
357 * Check key descriptor for validity.
359 if (_validate_keydesc(keydesc, fcb->minreclen) != ISOK) {
360 _amseterrcode(errcode, EBADKEY);
365 * Convert key descriptor to internal form.
367 _iskey_xtoi (&keydesc2, keydesc);
369 /* Find key decriptor in the FCB. */
370 if ((pkeydesc2 = _isfcb_findkey(fcb ,&keydesc2)) == NULL) {
371 _amseterrcode(errcode, EBADKEY);
376 * skipkeybytes is set to the number of bytes in the beginning
378 * RECNOSIZE for ISNODUPS keys to skip recno part
379 * RECNOSIZE + DUPIDSIZE to skip recno and duplicate serial number
381 skipbytes = RECNOSIZE;
382 if (ALLOWS_DUPS2(pkeydesc2))
383 skipbytes += DUPIDSIZE;
388 if (keylen < 0 || keylen > pkeydesc2->k2_len - skipbytes) {
389 _amseterrcode(errcode, EBADARG);
394 * Special case if keylen == 0: use the entire key.
397 matchkeylen = pkeydesc2->k2_len - skipbytes;
399 matchkeylen = keylen;
402 * Allocate new current record position.
404 newcrpsize = sizeof(Crp) + pkeydesc2->k2_len;
405 newcrp = (Crp *) _ismalloc((unsigned)newcrpsize);
406 memset((char *)newcrp, 0, newcrpsize);
408 newcrp->keyid = pkeydesc2->k2_keyid; /* Key identifier in FCB */
409 newcrp->matchkeylen = matchkeylen; /* number of bytes to match */
412 * Create B tree object.
414 btree = _isbtree_create(fcb, pkeydesc2);
420 * Make sure that you will read the first duplicate.
422 _iskey_fillmin(pkeydesc2, keybuf1);
425 * Extract key fields from record.
427 _iskey_extract(pkeydesc2, record, keybuf2);
428 memcpy( keybuf1 + skipbytes,keybuf2 + skipbytes, matchkeylen);
431 * Position pointer in the B-tree in before the searched value.
433 _isbtree_search(btree, keybuf1);
435 if ((pkey = _isbtree_next(btree)) == NULL) {
436 _amseterrcode(errcode, ENOREC);
440 if (readmode == RM_EQUAL &&
441 memcmp(keybuf1 + skipbytes, pkey + skipbytes,
443 _amseterrcode(errcode, ENOREC);
447 newcrp->flag = CRP_BEFORE;
448 newcrp->recno = ldrecno(pkey + KEY_RECNO_OFF);
449 memcpy( newcrp->key,pkey, pkeydesc2->k2_len);
454 * Make sure that you will read past all matching records.
456 _iskey_fillmax(pkeydesc2, keybuf1);
459 * Extract key fields from record.
461 _iskey_extract(pkeydesc2, record, keybuf2);
462 memcpy( keybuf1 + skipbytes,keybuf2 + skipbytes, matchkeylen);
465 * Position pointer in the B-tree after the searched value.
467 _isbtree_search(btree, keybuf1);
469 if ((pkey = _isbtree_next(btree)) == NULL) {
470 _amseterrcode(errcode, ENOREC);
474 newcrp->flag = CRP_BEFORE;
475 newcrp->recno = ldrecno(pkey + KEY_RECNO_OFF);
476 memcpy( newcrp->key,pkey, pkeydesc2->k2_len);
481 * Make sure that you will read before all matching records.
483 _iskey_fillmin(pkeydesc2, keybuf1);
486 * Extract key fields from record.
488 _iskey_extract(pkeydesc2, record, keybuf2);
489 memcpy( keybuf1 + skipbytes,keybuf2 + skipbytes, matchkeylen);
492 * Position pointer in the B-tree after the searched value.
494 _isbtree_search(btree, keybuf1);
496 if ((pkey = _isbtree_current(btree)) == NULL) {
497 _amseterrcode(errcode, ENOREC);
501 newcrp->flag = CRP_AFTER;
502 newcrp->recno = ldrecno(pkey + KEY_RECNO_OFF);
503 memcpy( newcrp->key,pkey, pkeydesc2->k2_len);
508 * Make sure that you will the last duplicate.
510 _iskey_fillmax(pkeydesc2, keybuf1);
513 * Extract key fields from record.
515 _iskey_extract(pkeydesc2, record, keybuf2);
516 memcpy( keybuf1 + skipbytes,keybuf2 + skipbytes, matchkeylen);
519 * Position pointer in the B-tree in before the searched value.
521 _isbtree_search(btree, keybuf1);
523 if ((pkey = _isbtree_current(btree)) == NULL) {
524 _amseterrcode(errcode, ENOREC);
528 newcrp->flag = CRP_AFTER;
529 newcrp->recno = ldrecno(pkey + KEY_RECNO_OFF);
530 memcpy( newcrp->key,pkey, pkeydesc2->k2_len);
535 * Fill key buffer with -infinity.
537 _iskey_fillmin(pkeydesc2, keybuf1);
540 * Position pointer in the B-tree before any key entry.
542 _isbtree_search(btree, keybuf1);
544 if ((pkey = _isbtree_next(btree)) == NULL) {
545 newcrp->flag = CRP_AFTERANY;
548 newcrp->flag = CRP_BEFORE;
549 newcrp->recno = ldrecno(pkey + KEY_RECNO_OFF);
550 memcpy( newcrp->key,pkey, pkeydesc2->k2_len);
556 * Fill key buffer with +infinity.
558 _iskey_fillmax(pkeydesc2, keybuf1);
561 * Position pointer in the B-tree after all entries.
563 _isbtree_search(btree, keybuf1);
565 if ((pkey = _isbtree_current(btree)) == NULL) {
566 newcrp->flag = CRP_BEFOREANY;
569 newcrp->flag = CRP_AFTER;
570 newcrp->recno = ldrecno(pkey + KEY_RECNO_OFF);
571 memcpy( newcrp->key,pkey, pkeydesc2->k2_len);
576 _isfatal_error("Invalid readmode");
579 *recnum = newcrp->recno;
582 * Build new curpos, deallocate old curpos data.
584 _bytearr_free(curpos);
585 *curpos = _bytearr_new((u_short)newcrpsize, (char *)newcrp);
587 _isbtree_destroy(btree);
590 _amseterrcode(errcode, ISOK);
594 free((char *)newcrp);
596 _isdisk_commit(); /* This will only check
597 * that we unfixed all fixed
607 _isbtree_destroy(btree);
610 * If error is EBADKEY, make the current position undefined.
612 if (errcode->iserrno == EBADKEY) {
613 ((Crp *)curpos->data)->flag = CRP_UNDEF;
617 * If error is ENOREC, switch to the new key, but set the current
618 * record position undefined.
620 if (errcode->iserrno == ENOREC && newcrp != NULL) {
621 _bytearr_free(curpos);
622 *curpos = _bytearr_new((u_short)newcrpsize, (char *)newcrp);
623 ((Crp *)curpos->data)->flag = CRP_UNDEF;
627 free((char *)newcrp);