~ubuntu-branches/ubuntu/maverick/evolution-data-server/maverick-proposed

« back to all changes in this revision

Viewing changes to libdb/tcl/tcl_dbcursor.c

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2010-05-17 17:02:06 UTC
  • mfrom: (1.1.79 upstream) (1.6.12 experimental)
  • Revision ID: james.westby@ubuntu.com-20100517170206-4ufr52vwrhh26yh0
Tags: 2.30.1-1ubuntu1
* Merge from debian experimental. Remaining change:
  (LP: #42199, #229669, #173703, #360344, #508494)
  + debian/control:
    - add Vcs-Bzr tag
    - don't use libgnome
    - Use Breaks instead of Conflicts against evolution 2.25 and earlier.
  + debian/evolution-data-server.install,
    debian/patches/45_libcamel_providers_version.patch:
    - use the upstream versioning, not a Debian-specific one 
  + debian/libedata-book1.2-dev.install, debian/libebackend-1.2-dev.install,
    debian/libcamel1.2-dev.install, debian/libedataserverui1.2-dev.install:
    - install html documentation
  + debian/rules:
    - don't build documentation it's shipped with the tarball

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*-
2
 
 * See the file LICENSE for redistribution information.
3
 
 *
4
 
 * Copyright (c) 1999-2001
5
 
 *      Sleepycat Software.  All rights reserved.
6
 
 */
7
 
 
8
 
#include "db_config.h"
9
 
 
10
 
#ifndef lint
11
 
static const char revid[] = "$Id$";
12
 
#endif /* not lint */
13
 
 
14
 
#ifndef NO_SYSTEM_INCLUDES
15
 
#include <sys/types.h>
16
 
 
17
 
#include <stdlib.h>
18
 
#include <string.h>
19
 
#include <tcl.h>
20
 
#endif
21
 
 
22
 
#include "db_int.h"
23
 
#include "dbinc/tcl_db.h"
24
 
 
25
 
/*
26
 
 * Prototypes for procedures defined later in this file:
27
 
 */
28
 
static int tcl_DbcDup __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DBC *));
29
 
static int tcl_DbcGet __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DBC *, int));
30
 
static int tcl_DbcPut __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DBC *));
31
 
 
32
 
/*
33
 
 * PUBLIC: int dbc_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
34
 
 *
35
 
 * dbc_cmd --
36
 
 *      Implements the cursor command.
37
 
 */
38
 
int
39
 
dbc_Cmd(clientData, interp, objc, objv)
40
 
        ClientData clientData;          /* Cursor handle */
41
 
        Tcl_Interp *interp;             /* Interpreter */
42
 
        int objc;                       /* How many arguments? */
43
 
        Tcl_Obj *CONST objv[];          /* The argument objects */
44
 
{
45
 
        static char *dbccmds[] = {
46
 
#if CONFIG_TEST
47
 
                "pget",
48
 
#endif
49
 
                "close",
50
 
                "del",
51
 
                "dup",
52
 
                "get",
53
 
                "put",
54
 
                NULL
55
 
        };
56
 
        enum dbccmds {
57
 
#if CONFIG_TEST
58
 
                DBCPGET,
59
 
#endif
60
 
                DBCCLOSE,
61
 
                DBCDELETE,
62
 
                DBCDUP,
63
 
                DBCGET,
64
 
                DBCPUT
65
 
        };
66
 
        DBC *dbc;
67
 
        DBTCL_INFO *dbip;
68
 
        int cmdindex, result, ret;
69
 
 
70
 
        Tcl_ResetResult(interp);
71
 
        dbc = (DBC *)clientData;
72
 
        dbip = _PtrToInfo((void *)dbc);
73
 
        result = TCL_OK;
74
 
 
75
 
        if (objc <= 1) {
76
 
                Tcl_WrongNumArgs(interp, 1, objv, "command cmdargs");
77
 
                return (TCL_ERROR);
78
 
        }
79
 
        if (dbc == NULL) {
80
 
                Tcl_SetResult(interp, "NULL dbc pointer", TCL_STATIC);
81
 
                return (TCL_ERROR);
82
 
        }
83
 
        if (dbip == NULL) {
84
 
                Tcl_SetResult(interp, "NULL dbc info pointer", TCL_STATIC);
85
 
                return (TCL_ERROR);
86
 
        }
87
 
 
88
 
        /*
89
 
         * Get the command name index from the object based on the berkdbcmds
90
 
         * defined above.
91
 
         */
92
 
        if (Tcl_GetIndexFromObj(interp, objv[1], dbccmds, "command",
93
 
            TCL_EXACT, &cmdindex) != TCL_OK)
94
 
                return (IS_HELP(objv[1]));
95
 
        switch ((enum dbccmds)cmdindex) {
96
 
#if CONFIG_TEST
97
 
        case DBCPGET:
98
 
                result = tcl_DbcGet(interp, objc, objv, dbc, 1);
99
 
                break;
100
 
#endif
101
 
        case DBCCLOSE:
102
 
                /*
103
 
                 * No args for this.  Error if there are some.
104
 
                 */
105
 
                if (objc > 2) {
106
 
                        Tcl_WrongNumArgs(interp, 2, objv, NULL);
107
 
                        return (TCL_ERROR);
108
 
                }
109
 
                _debug_check();
110
 
                ret = dbc->c_close(dbc);
111
 
                result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
112
 
                    "dbc close");
113
 
                if (result == TCL_OK) {
114
 
                        (void)Tcl_DeleteCommand(interp, dbip->i_name);
115
 
                        _DeleteInfo(dbip);
116
 
                }
117
 
                break;
118
 
        case DBCDELETE:
119
 
                /*
120
 
                 * No args for this.  Error if there are some.
121
 
                 */
122
 
                if (objc > 2) {
123
 
                        Tcl_WrongNumArgs(interp, 2, objv, NULL);
124
 
                        return (TCL_ERROR);
125
 
                }
126
 
                _debug_check();
127
 
                ret = dbc->c_del(dbc, 0);
128
 
                result = _ReturnSetup(interp, ret, DB_RETOK_DBCDEL(ret),
129
 
                    "dbc delete");
130
 
                break;
131
 
        case DBCDUP:
132
 
                result = tcl_DbcDup(interp, objc, objv, dbc);
133
 
                break;
134
 
        case DBCGET:
135
 
                result = tcl_DbcGet(interp, objc, objv, dbc, 0);
136
 
                break;
137
 
        case DBCPUT:
138
 
                result = tcl_DbcPut(interp, objc, objv, dbc);
139
 
                break;
140
 
        }
141
 
        return (result);
142
 
}
143
 
 
144
 
/*
145
 
 * tcl_DbcPut --
146
 
 */
147
 
static int
148
 
tcl_DbcPut(interp, objc, objv, dbc)
149
 
        Tcl_Interp *interp;             /* Interpreter */
150
 
        int objc;                       /* How many arguments? */
151
 
        Tcl_Obj *CONST objv[];          /* The argument objects */
152
 
        DBC *dbc;                       /* Cursor pointer */
153
 
{
154
 
        static char *dbcutopts[] = {
155
 
#if CONFIG_TEST
156
 
                "-nodupdata",
157
 
#endif
158
 
                "-after",
159
 
                "-before",
160
 
                "-current",
161
 
                "-keyfirst",
162
 
                "-keylast",
163
 
                "-partial",
164
 
                NULL
165
 
        };
166
 
        enum dbcutopts {
167
 
#if CONFIG_TEST
168
 
                DBCPUT_NODUPDATA,
169
 
#endif
170
 
                DBCPUT_AFTER,
171
 
                DBCPUT_BEFORE,
172
 
                DBCPUT_CURRENT,
173
 
                DBCPUT_KEYFIRST,
174
 
                DBCPUT_KEYLAST,
175
 
                DBCPUT_PART
176
 
        };
177
 
        DB *thisdbp;
178
 
        DBT key, data;
179
 
        DBTCL_INFO *dbcip, *dbip;
180
 
        DBTYPE type;
181
 
        Tcl_Obj **elemv, *res;
182
 
        void *dtmp, *ktmp;
183
 
        db_recno_t recno;
184
 
        u_int32_t flag;
185
 
        int elemc, freekey, freedata, i, optindex, result, ret;
186
 
 
187
 
        result = TCL_OK;
188
 
        flag = 0;
189
 
        freekey = freedata = 0;
190
 
 
191
 
        if (objc < 2) {
192
 
                Tcl_WrongNumArgs(interp, 2, objv, "?-args? ?key?");
193
 
                return (TCL_ERROR);
194
 
        }
195
 
 
196
 
        memset(&key, 0, sizeof(key));
197
 
        memset(&data, 0, sizeof(data));
198
 
 
199
 
        /*
200
 
         * Get the command name index from the object based on the options
201
 
         * defined above.
202
 
         */
203
 
        i = 2;
204
 
        while (i < (objc - 1)) {
205
 
                if (Tcl_GetIndexFromObj(interp, objv[i], dbcutopts, "option",
206
 
                    TCL_EXACT, &optindex) != TCL_OK) {
207
 
                        /*
208
 
                         * Reset the result so we don't get
209
 
                         * an errant error message if there is another error.
210
 
                         */
211
 
                        if (IS_HELP(objv[i]) == TCL_OK) {
212
 
                                result = TCL_OK;
213
 
                                goto out;
214
 
                        }
215
 
                        Tcl_ResetResult(interp);
216
 
                        break;
217
 
                }
218
 
                i++;
219
 
                switch ((enum dbcutopts)optindex) {
220
 
#if CONFIG_TEST
221
 
                case DBCPUT_NODUPDATA:
222
 
                        FLAG_CHECK(flag);
223
 
                        flag = DB_NODUPDATA;
224
 
                        break;
225
 
#endif
226
 
                case DBCPUT_AFTER:
227
 
                        FLAG_CHECK(flag);
228
 
                        flag = DB_AFTER;
229
 
                        break;
230
 
                case DBCPUT_BEFORE:
231
 
                        FLAG_CHECK(flag);
232
 
                        flag = DB_BEFORE;
233
 
                        break;
234
 
                case DBCPUT_CURRENT:
235
 
                        FLAG_CHECK(flag);
236
 
                        flag = DB_CURRENT;
237
 
                        break;
238
 
                case DBCPUT_KEYFIRST:
239
 
                        FLAG_CHECK(flag);
240
 
                        flag = DB_KEYFIRST;
241
 
                        break;
242
 
                case DBCPUT_KEYLAST:
243
 
                        FLAG_CHECK(flag);
244
 
                        flag = DB_KEYLAST;
245
 
                        break;
246
 
                case DBCPUT_PART:
247
 
                        if (i > (objc - 2)) {
248
 
                                Tcl_WrongNumArgs(interp, 2, objv,
249
 
                                    "?-partial {offset length}?");
250
 
                                result = TCL_ERROR;
251
 
                                break;
252
 
                        }
253
 
                        /*
254
 
                         * Get sublist as {offset length}
255
 
                         */
256
 
                        result = Tcl_ListObjGetElements(interp, objv[i++],
257
 
                            &elemc, &elemv);
258
 
                        if (elemc != 2) {
259
 
                                Tcl_SetResult(interp,
260
 
                                    "List must be {offset length}", TCL_STATIC);
261
 
                                result = TCL_ERROR;
262
 
                                break;
263
 
                        }
264
 
                        data.flags |= DB_DBT_PARTIAL;
265
 
                        result = _GetUInt32(interp, elemv[0], &data.doff);
266
 
                        if (result != TCL_OK)
267
 
                                break;
268
 
                        result = _GetUInt32(interp, elemv[1], &data.dlen);
269
 
                        /*
270
 
                         * NOTE: We don't check result here because all we'd
271
 
                         * do is break anyway, and we are doing that.  If you
272
 
                         * add code here, you WILL need to add the check
273
 
                         * for result.  (See the check for save.doff, a few
274
 
                         * lines above and copy that.)
275
 
                         */
276
 
                }
277
 
                if (result != TCL_OK)
278
 
                        break;
279
 
        }
280
 
        if (result != TCL_OK)
281
 
                goto out;
282
 
 
283
 
        /*
284
 
         * We need to determine if we are a recno database or not.  If we are,
285
 
         * then key.data is a recno, not a string.
286
 
         */
287
 
        dbcip = _PtrToInfo(dbc);
288
 
        if (dbcip == NULL)
289
 
                type = DB_UNKNOWN;
290
 
        else {
291
 
                dbip = dbcip->i_parent;
292
 
                if (dbip == NULL) {
293
 
                        Tcl_SetResult(interp, "Cursor without parent database",
294
 
                            TCL_STATIC);
295
 
                        result = TCL_ERROR;
296
 
                        return (result);
297
 
                }
298
 
                thisdbp = dbip->i_dbp;
299
 
                (void)thisdbp->get_type(thisdbp, &type);
300
 
        }
301
 
        /*
302
 
         * When we get here, we better have:
303
 
         * 1 arg if -after, -before or -current
304
 
         * 2 args in all other cases
305
 
         */
306
 
        if (flag == DB_AFTER || flag == DB_BEFORE || flag == DB_CURRENT) {
307
 
                if (i != (objc - 1)) {
308
 
                        Tcl_WrongNumArgs(interp, 2, objv,
309
 
                            "?-args? data");
310
 
                        result = TCL_ERROR;
311
 
                        goto out;
312
 
                }
313
 
                /*
314
 
                 * We want to get the key back, so we need to set
315
 
                 * up the location to get it back in.
316
 
                 */
317
 
                if (type == DB_RECNO || type == DB_QUEUE) {
318
 
                        recno = 0;
319
 
                        key.data = &recno;
320
 
                        key.size = sizeof(db_recno_t);
321
 
                }
322
 
        } else {
323
 
                if (i != (objc - 2)) {
324
 
                        Tcl_WrongNumArgs(interp, 2, objv,
325
 
                            "?-args? key data");
326
 
                        result = TCL_ERROR;
327
 
                        goto out;
328
 
                }
329
 
                if (type == DB_RECNO || type == DB_QUEUE) {
330
 
                        result = _GetUInt32(interp, objv[objc-2], &recno);
331
 
                        if (result == TCL_OK) {
332
 
                                key.data = &recno;
333
 
                                key.size = sizeof(db_recno_t);
334
 
                        } else
335
 
                                return (result);
336
 
                } else {
337
 
                        ret = _CopyObjBytes(interp, objv[objc-2], &ktmp,
338
 
                            &key.size, &freekey);
339
 
                        if (ret != 0) {
340
 
                                result = _ReturnSetup(interp, ret,
341
 
                                    DB_RETOK_DBCPUT(ret), "dbc put");
342
 
                                return (result);
343
 
                        }
344
 
                        key.data = ktmp;
345
 
                }
346
 
        }
347
 
        ret = _CopyObjBytes(interp, objv[objc-1], &dtmp,
348
 
            &data.size, &freedata);
349
 
        data.data = dtmp;
350
 
        if (ret != 0) {
351
 
                result = _ReturnSetup(interp, ret,
352
 
                    DB_RETOK_DBCPUT(ret), "dbc put");
353
 
                goto out;
354
 
        }
355
 
        _debug_check();
356
 
        ret = dbc->c_put(dbc, &key, &data, flag);
357
 
        result = _ReturnSetup(interp, ret, DB_RETOK_DBCPUT(ret),
358
 
            "dbc put");
359
 
        if (ret == 0 &&
360
 
            (flag == DB_AFTER || flag == DB_BEFORE) && type == DB_RECNO) {
361
 
                res = Tcl_NewLongObj((long)*(db_recno_t *)key.data);
362
 
                Tcl_SetObjResult(interp, res);
363
 
        }
364
 
out:
365
 
        if (freedata)
366
 
                (void)__os_free(NULL, dtmp);
367
 
        if (freekey)
368
 
                (void)__os_free(NULL, ktmp);
369
 
        return (result);
370
 
}
371
 
 
372
 
/*
373
 
 * tcl_dbc_get --
374
 
 */
375
 
static int
376
 
tcl_DbcGet(interp, objc, objv, dbc, ispget)
377
 
        Tcl_Interp *interp;             /* Interpreter */
378
 
        int objc;                       /* How many arguments? */
379
 
        Tcl_Obj *CONST objv[];          /* The argument objects */
380
 
        DBC *dbc;                       /* Cursor pointer */
381
 
        int ispget;                     /* 1 for pget, 0 for get */
382
 
{
383
 
        static char *dbcgetopts[] = {
384
 
#if CONFIG_TEST
385
 
                "-dirty",
386
 
                "-get_both_range",
387
 
                "-multi",
388
 
                "-multi_key",
389
 
#endif
390
 
                "-current",
391
 
                "-first",
392
 
                "-get_both",
393
 
                "-get_recno",
394
 
                "-join_item",
395
 
                "-last",
396
 
                "-next",
397
 
                "-nextdup",
398
 
                "-nextnodup",
399
 
                "-partial",
400
 
                "-prev",
401
 
                "-prevnodup",
402
 
                "-rmw",
403
 
                "-set",
404
 
                "-set_range",
405
 
                "-set_recno",
406
 
                NULL
407
 
        };
408
 
        enum dbcgetopts {
409
 
#if CONFIG_TEST
410
 
                DBCGET_DIRTY,
411
 
                DBCGET_BOTH_RANGE,
412
 
                DBCGET_MULTI,
413
 
                DBCGET_MULTI_KEY,
414
 
#endif
415
 
                DBCGET_CURRENT,
416
 
                DBCGET_FIRST,
417
 
                DBCGET_BOTH,
418
 
                DBCGET_RECNO,
419
 
                DBCGET_JOIN,
420
 
                DBCGET_LAST,
421
 
                DBCGET_NEXT,
422
 
                DBCGET_NEXTDUP,
423
 
                DBCGET_NEXTNODUP,
424
 
                DBCGET_PART,
425
 
                DBCGET_PREV,
426
 
                DBCGET_PREVNODUP,
427
 
                DBCGET_RMW,
428
 
                DBCGET_SET,
429
 
                DBCGET_SETRANGE,
430
 
                DBCGET_SETRECNO
431
 
        };
432
 
        DB *thisdbp;
433
 
        DBT key, data, pdata;
434
 
        DBTCL_INFO *dbcip, *dbip;
435
 
        DBTYPE ptype, type;
436
 
        Tcl_Obj **elemv, *myobj, *retlist;
437
 
        void *dtmp, *ktmp;
438
 
        db_recno_t precno, recno;
439
 
        u_int32_t flag, op;
440
 
        int bufsize, elemc, freekey, freedata, i, optindex, result, ret;
441
 
 
442
 
        result = TCL_OK;
443
 
        flag = 0;
444
 
        freekey = freedata = 0;
445
 
 
446
 
        if (objc < 2) {
447
 
                Tcl_WrongNumArgs(interp, 2, objv, "?-args? ?key?");
448
 
                return (TCL_ERROR);
449
 
        }
450
 
 
451
 
        memset(&key, 0, sizeof(key));
452
 
        memset(&data, 0, sizeof(data));
453
 
        /*
454
 
         * Get the command name index from the object based on the options
455
 
         * defined above.
456
 
         */
457
 
        i = 2;
458
 
        while (i < objc) {
459
 
                if (Tcl_GetIndexFromObj(interp, objv[i], dbcgetopts,
460
 
                    "option", TCL_EXACT, &optindex) != TCL_OK) {
461
 
                        /*
462
 
                         * Reset the result so we don't get
463
 
                         * an errant error message if there is another error.
464
 
                         */
465
 
                        if (IS_HELP(objv[i]) == TCL_OK) {
466
 
                                result = TCL_OK;
467
 
                                goto out;
468
 
                        }
469
 
                        Tcl_ResetResult(interp);
470
 
                        break;
471
 
                }
472
 
                i++;
473
 
                switch ((enum dbcgetopts)optindex) {
474
 
#if CONFIG_TEST
475
 
                case DBCGET_DIRTY:
476
 
                        flag |= DB_DIRTY_READ;
477
 
                        break;
478
 
                case DBCGET_BOTH_RANGE:
479
 
                        FLAG_CHECK2(flag,
480
 
                            DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
481
 
                        flag |= DB_GET_BOTH_RANGE;
482
 
                        break;
483
 
                case DBCGET_MULTI:
484
 
                        flag |= DB_MULTIPLE;
485
 
                        result = Tcl_GetIntFromObj(interp, objv[i], &bufsize);
486
 
                        if (result != TCL_OK)
487
 
                                goto out;
488
 
                        i++;
489
 
                        break;
490
 
                case DBCGET_MULTI_KEY:
491
 
                        flag |= DB_MULTIPLE_KEY;
492
 
                        result = Tcl_GetIntFromObj(interp, objv[i], &bufsize);
493
 
                        if (result != TCL_OK)
494
 
                                goto out;
495
 
                        i++;
496
 
                        break;
497
 
#endif
498
 
                case DBCGET_RMW:
499
 
                        flag |= DB_RMW;
500
 
                        break;
501
 
                case DBCGET_CURRENT:
502
 
                        FLAG_CHECK2(flag,
503
 
                            DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
504
 
                        flag |= DB_CURRENT;
505
 
                        break;
506
 
                case DBCGET_FIRST:
507
 
                        FLAG_CHECK2(flag,
508
 
                            DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
509
 
                        flag |= DB_FIRST;
510
 
                        break;
511
 
                case DBCGET_LAST:
512
 
                        FLAG_CHECK2(flag,
513
 
                            DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
514
 
                        flag |= DB_LAST;
515
 
                        break;
516
 
                case DBCGET_NEXT:
517
 
                        FLAG_CHECK2(flag,
518
 
                            DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
519
 
                        flag |= DB_NEXT;
520
 
                        break;
521
 
                case DBCGET_PREV:
522
 
                        FLAG_CHECK2(flag,
523
 
                            DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
524
 
                        flag |= DB_PREV;
525
 
                        break;
526
 
                case DBCGET_PREVNODUP:
527
 
                        FLAG_CHECK2(flag,
528
 
                            DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
529
 
                        flag |= DB_PREV_NODUP;
530
 
                        break;
531
 
                case DBCGET_NEXTNODUP:
532
 
                        FLAG_CHECK2(flag,
533
 
                            DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
534
 
                        flag |= DB_NEXT_NODUP;
535
 
                        break;
536
 
                case DBCGET_NEXTDUP:
537
 
                        FLAG_CHECK2(flag,
538
 
                            DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
539
 
                        flag |= DB_NEXT_DUP;
540
 
                        break;
541
 
                case DBCGET_BOTH:
542
 
                        FLAG_CHECK2(flag,
543
 
                            DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
544
 
                        flag |= DB_GET_BOTH;
545
 
                        break;
546
 
                case DBCGET_RECNO:
547
 
                        FLAG_CHECK2(flag,
548
 
                            DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
549
 
                        flag |= DB_GET_RECNO;
550
 
                        break;
551
 
                case DBCGET_JOIN:
552
 
                        FLAG_CHECK2(flag,
553
 
                            DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
554
 
                        flag |= DB_JOIN_ITEM;
555
 
                        break;
556
 
                case DBCGET_SET:
557
 
                        FLAG_CHECK2(flag,
558
 
                            DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
559
 
                        flag |= DB_SET;
560
 
                        break;
561
 
                case DBCGET_SETRANGE:
562
 
                        FLAG_CHECK2(flag,
563
 
                            DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
564
 
                        flag |= DB_SET_RANGE;
565
 
                        break;
566
 
                case DBCGET_SETRECNO:
567
 
                        FLAG_CHECK2(flag,
568
 
                            DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
569
 
                        flag |= DB_SET_RECNO;
570
 
                        break;
571
 
                case DBCGET_PART:
572
 
                        if (i == objc) {
573
 
                                Tcl_WrongNumArgs(interp, 2, objv,
574
 
                                    "?-partial {offset length}?");
575
 
                                result = TCL_ERROR;
576
 
                                break;
577
 
                        }
578
 
                        /*
579
 
                         * Get sublist as {offset length}
580
 
                         */
581
 
                        result = Tcl_ListObjGetElements(interp, objv[i++],
582
 
                            &elemc, &elemv);
583
 
                        if (elemc != 2) {
584
 
                                Tcl_SetResult(interp,
585
 
                                    "List must be {offset length}", TCL_STATIC);
586
 
                                result = TCL_ERROR;
587
 
                                break;
588
 
                        }
589
 
                        data.flags |= DB_DBT_PARTIAL;
590
 
                        result = _GetUInt32(interp, elemv[0], &data.doff);
591
 
                        if (result != TCL_OK)
592
 
                                break;
593
 
                        result = _GetUInt32(interp, elemv[1], &data.dlen);
594
 
                        /*
595
 
                         * NOTE: We don't check result here because all we'd
596
 
                         * do is break anyway, and we are doing that.  If you
597
 
                         * add code here, you WILL need to add the check
598
 
                         * for result.  (See the check for save.doff, a few
599
 
                         * lines above and copy that.)
600
 
                         */
601
 
                        break;
602
 
                }
603
 
                if (result != TCL_OK)
604
 
                        break;
605
 
        }
606
 
        if (result != TCL_OK)
607
 
                goto out;
608
 
 
609
 
        /*
610
 
         * We need to determine if we are a recno database
611
 
         * or not.  If we are, then key.data is a recno, not
612
 
         * a string.
613
 
         */
614
 
        dbcip = _PtrToInfo(dbc);
615
 
        if (dbcip == NULL) {
616
 
                type = DB_UNKNOWN;
617
 
                ptype = DB_UNKNOWN;
618
 
        } else {
619
 
                dbip = dbcip->i_parent;
620
 
                if (dbip == NULL) {
621
 
                        Tcl_SetResult(interp, "Cursor without parent database",
622
 
                            TCL_STATIC);
623
 
                        result = TCL_ERROR;
624
 
                        goto out;
625
 
                }
626
 
                thisdbp = dbip->i_dbp;
627
 
                (void)thisdbp->get_type(thisdbp, &type);
628
 
                if (ispget && thisdbp->s_primary != NULL)
629
 
                        (void)thisdbp->
630
 
                            s_primary->get_type(thisdbp->s_primary, &ptype);
631
 
                else
632
 
                        ptype = DB_UNKNOWN;
633
 
        }
634
 
        /*
635
 
         * When we get here, we better have:
636
 
         * 2 args, key and data if GET_BOTH/GET_BOTH_RANGE was specified.
637
 
         * 1 arg if -set, -set_range or -set_recno
638
 
         * 0 in all other cases.
639
 
         */
640
 
        op = flag & DB_OPFLAGS_MASK;
641
 
        switch (op) {
642
 
        case DB_GET_BOTH:
643
 
#if CONFIG_TEST
644
 
        case DB_GET_BOTH_RANGE:
645
 
#endif
646
 
                if (i != (objc - 2)) {
647
 
                        Tcl_WrongNumArgs(interp, 2, objv,
648
 
                            "?-args? -get_both key data");
649
 
                        result = TCL_ERROR;
650
 
                        goto out;
651
 
                } else {
652
 
                        if (type == DB_RECNO || type == DB_QUEUE) {
653
 
                                result = _GetUInt32(
654
 
                                    interp, objv[objc-2], &recno);
655
 
                                if (result == TCL_OK) {
656
 
                                        key.data = &recno;
657
 
                                        key.size = sizeof(db_recno_t);
658
 
                                } else
659
 
                                        goto out;
660
 
                        } else {
661
 
                                /*
662
 
                                 * Some get calls (SET_*) can change the
663
 
                                 * key pointers.  So, we need to store
664
 
                                 * the allocated key space in a tmp.
665
 
                                 */
666
 
                                ret = _CopyObjBytes(interp, objv[objc-2],
667
 
                                    &ktmp, &key.size, &freekey);
668
 
                                if (ret != 0) {
669
 
                                        result = _ReturnSetup(interp, ret,
670
 
                                            DB_RETOK_DBCGET(ret), "dbc get");
671
 
                                        return (result);
672
 
                                }
673
 
                                key.data = ktmp;
674
 
                        }
675
 
                        if (ptype == DB_RECNO || ptype == DB_QUEUE) {
676
 
                                result = _GetUInt32(
677
 
                                    interp, objv[objc-1], &precno);
678
 
                                if (result == TCL_OK) {
679
 
                                        data.data = &precno;
680
 
                                        data.size = sizeof(db_recno_t);
681
 
                                } else
682
 
                                        goto out;
683
 
                        } else {
684
 
                                ret = _CopyObjBytes(interp, objv[objc-1],
685
 
                                    &dtmp, &data.size, &freedata);
686
 
                                if (ret != 0) {
687
 
                                        result = _ReturnSetup(interp, ret,
688
 
                                            DB_RETOK_DBCGET(ret), "dbc get");
689
 
                                        goto out;
690
 
                                }
691
 
                                data.data = dtmp;
692
 
                        }
693
 
                }
694
 
                break;
695
 
        case DB_SET:
696
 
        case DB_SET_RANGE:
697
 
        case DB_SET_RECNO:
698
 
                if (i != (objc - 1)) {
699
 
                        Tcl_WrongNumArgs(interp, 2, objv, "?-args? key");
700
 
                        result = TCL_ERROR;
701
 
                        goto out;
702
 
                }
703
 
                if (flag & (DB_MULTIPLE|DB_MULTIPLE_KEY)) {
704
 
                        (void)__os_malloc(NULL, bufsize, &data.data);
705
 
                        data.ulen = bufsize;
706
 
                        data.flags |= DB_DBT_USERMEM;
707
 
                } else
708
 
                        data.flags |= DB_DBT_MALLOC;
709
 
                if (op == DB_SET_RECNO ||
710
 
                    type == DB_RECNO || type == DB_QUEUE) {
711
 
                        result = _GetUInt32(interp, objv[objc - 1], &recno);
712
 
                        key.data = &recno;
713
 
                        key.size = sizeof(db_recno_t);
714
 
                } else {
715
 
                        /*
716
 
                         * Some get calls (SET_*) can change the
717
 
                         * key pointers.  So, we need to store
718
 
                         * the allocated key space in a tmp.
719
 
                         */
720
 
                        ret = _CopyObjBytes(interp, objv[objc-1],
721
 
                            &ktmp, &key.size, &freekey);
722
 
                        if (ret != 0) {
723
 
                                result = _ReturnSetup(interp, ret,
724
 
                                    DB_RETOK_DBCGET(ret), "dbc get");
725
 
                                return (result);
726
 
                        }
727
 
                        key.data = ktmp;
728
 
                }
729
 
                break;
730
 
        default:
731
 
                if (i != objc) {
732
 
                        Tcl_WrongNumArgs(interp, 2, objv, "?-args?");
733
 
                        result = TCL_ERROR;
734
 
                        goto out;
735
 
                }
736
 
                key.flags |= DB_DBT_MALLOC;
737
 
                if (flag & (DB_MULTIPLE|DB_MULTIPLE_KEY)) {
738
 
                        (void)__os_malloc(NULL, bufsize, &data.data);
739
 
                        data.ulen = bufsize;
740
 
                        data.flags |= DB_DBT_USERMEM;
741
 
                } else
742
 
                        data.flags |= DB_DBT_MALLOC;
743
 
        }
744
 
 
745
 
        _debug_check();
746
 
        memset(&pdata, 0, sizeof(DBT));
747
 
        if (ispget) {
748
 
                F_SET(&pdata, DB_DBT_MALLOC);
749
 
                ret = dbc->c_pget(dbc, &key, &data, &pdata, flag);
750
 
        } else
751
 
                ret = dbc->c_get(dbc, &key, &data, flag);
752
 
        result = _ReturnSetup(interp, ret, DB_RETOK_DBCGET(ret), "dbc get");
753
 
        if (result == TCL_ERROR)
754
 
                goto out;
755
 
 
756
 
        retlist = Tcl_NewListObj(0, NULL);
757
 
        if (ret == DB_NOTFOUND)
758
 
                goto out1;
759
 
        if (op == DB_GET_RECNO) {
760
 
                recno = *((db_recno_t *)data.data);
761
 
                myobj = Tcl_NewLongObj((long)recno);
762
 
                result = Tcl_ListObjAppendElement(interp, retlist, myobj);
763
 
        } else {
764
 
                if (flag & (DB_MULTIPLE|DB_MULTIPLE_KEY))
765
 
                        result = _SetMultiList(interp,
766
 
                            retlist, &key, &data, type, flag);
767
 
                else if ((type == DB_RECNO || type == DB_QUEUE) &&
768
 
                    key.data != NULL) {
769
 
                        if (ispget)
770
 
                                result = _Set3DBTList(interp, retlist, &key, 1,
771
 
                                    &data,
772
 
                                    (ptype == DB_RECNO || ptype == DB_QUEUE),
773
 
                                    &pdata);
774
 
                        else
775
 
                                result = _SetListRecnoElem(interp, retlist,
776
 
                                    *(db_recno_t *)key.data,
777
 
                                    data.data, data.size);
778
 
                } else {
779
 
                        if (ispget)
780
 
                                result = _Set3DBTList(interp, retlist, &key, 0,
781
 
                                    &data,
782
 
                                    (ptype == DB_RECNO || ptype == DB_QUEUE),
783
 
                                    &pdata);
784
 
                        else
785
 
                                result = _SetListElem(interp, retlist,
786
 
                                    key.data, key.size, data.data, data.size);
787
 
                }
788
 
        }
789
 
        if (key.data != NULL && F_ISSET(&key, DB_DBT_MALLOC))
790
 
                __os_ufree(dbc->dbp->dbenv, key.data);
791
 
        if (data.data != NULL && F_ISSET(&data, DB_DBT_MALLOC))
792
 
                __os_ufree(dbc->dbp->dbenv, data.data);
793
 
        if (pdata.data != NULL && F_ISSET(&pdata, DB_DBT_MALLOC))
794
 
                __os_ufree(dbc->dbp->dbenv, pdata.data);
795
 
out1:
796
 
        if (result == TCL_OK)
797
 
                Tcl_SetObjResult(interp, retlist);
798
 
out:
799
 
        if (data.data != NULL && flag & (DB_MULTIPLE|DB_MULTIPLE_KEY))
800
 
                __os_free(dbc->dbp->dbenv, data.data);
801
 
        if (freedata)
802
 
                (void)__os_free(NULL, dtmp);
803
 
        if (freekey)
804
 
                (void)__os_free(NULL, ktmp);
805
 
        return (result);
806
 
 
807
 
}
808
 
 
809
 
/*
810
 
 * tcl_DbcDup --
811
 
 */
812
 
static int
813
 
tcl_DbcDup(interp, objc, objv, dbc)
814
 
        Tcl_Interp *interp;             /* Interpreter */
815
 
        int objc;                       /* How many arguments? */
816
 
        Tcl_Obj *CONST objv[];          /* The argument objects */
817
 
        DBC *dbc;                       /* Cursor pointer */
818
 
{
819
 
        static char *dbcdupopts[] = {
820
 
                "-position",
821
 
                NULL
822
 
        };
823
 
        enum dbcdupopts {
824
 
                DBCDUP_POS
825
 
        };
826
 
        DBC *newdbc;
827
 
        DBTCL_INFO *dbcip, *newdbcip, *dbip;
828
 
        Tcl_Obj *res;
829
 
        u_int32_t flag;
830
 
        int i, optindex, result, ret;
831
 
        char newname[MSG_SIZE];
832
 
 
833
 
        result = TCL_OK;
834
 
        flag = 0;
835
 
        res = NULL;
836
 
 
837
 
        if (objc < 2) {
838
 
                Tcl_WrongNumArgs(interp, 2, objv, "?-args?");
839
 
                return (TCL_ERROR);
840
 
        }
841
 
 
842
 
        /*
843
 
         * Get the command name index from the object based on the options
844
 
         * defined above.
845
 
         */
846
 
        i = 2;
847
 
        while (i < objc) {
848
 
                if (Tcl_GetIndexFromObj(interp, objv[i], dbcdupopts,
849
 
                    "option", TCL_EXACT, &optindex) != TCL_OK) {
850
 
                        /*
851
 
                         * Reset the result so we don't get
852
 
                         * an errant error message if there is another error.
853
 
                         */
854
 
                        if (IS_HELP(objv[i]) == TCL_OK) {
855
 
                                result = TCL_OK;
856
 
                                goto out;
857
 
                        }
858
 
                        Tcl_ResetResult(interp);
859
 
                        break;
860
 
                }
861
 
                i++;
862
 
                switch ((enum dbcdupopts)optindex) {
863
 
                case DBCDUP_POS:
864
 
                        flag = DB_POSITION;
865
 
                        break;
866
 
                }
867
 
                if (result != TCL_OK)
868
 
                        break;
869
 
        }
870
 
        if (result != TCL_OK)
871
 
                goto out;
872
 
 
873
 
        /*
874
 
         * We need to determine if we are a recno database
875
 
         * or not.  If we are, then key.data is a recno, not
876
 
         * a string.
877
 
         */
878
 
        dbcip = _PtrToInfo(dbc);
879
 
        if (dbcip == NULL) {
880
 
                Tcl_SetResult(interp, "Cursor without info structure",
881
 
                    TCL_STATIC);
882
 
                result = TCL_ERROR;
883
 
                goto out;
884
 
        } else {
885
 
                dbip = dbcip->i_parent;
886
 
                if (dbip == NULL) {
887
 
                        Tcl_SetResult(interp, "Cursor without parent database",
888
 
                            TCL_STATIC);
889
 
                        result = TCL_ERROR;
890
 
                        goto out;
891
 
                }
892
 
        }
893
 
        /*
894
 
         * Now duplicate the cursor.  If successful, we need to create
895
 
         * a new cursor command.
896
 
         */
897
 
 
898
 
        snprintf(newname, sizeof(newname),
899
 
            "%s.c%d", dbip->i_name, dbip->i_dbdbcid);
900
 
        newdbcip = _NewInfo(interp, NULL, newname, I_DBC);
901
 
        if (newdbcip != NULL) {
902
 
                ret = dbc->c_dup(dbc, &newdbc, flag);
903
 
                if (ret == 0) {
904
 
                        dbip->i_dbdbcid++;
905
 
                        newdbcip->i_parent = dbip;
906
 
                        Tcl_CreateObjCommand(interp, newname,
907
 
                            (Tcl_ObjCmdProc *)dbc_Cmd,
908
 
                            (ClientData)newdbc, NULL);
909
 
                        res = Tcl_NewStringObj(newname, strlen(newname));
910
 
                        _SetInfoData(newdbcip, newdbc);
911
 
                        Tcl_SetObjResult(interp, res);
912
 
                } else {
913
 
                        result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
914
 
                            "db dup");
915
 
                        _DeleteInfo(newdbcip);
916
 
                }
917
 
        } else {
918
 
                Tcl_SetResult(interp, "Could not set up info", TCL_STATIC);
919
 
                result = TCL_ERROR;
920
 
        }
921
 
out:
922
 
        return (result);
923
 
 
924
 
}