source: trunk/base/src/registry2.0/itemobj.c @ 27518

Last change on this file since 27518 was 27518, checked in by sfiera@…, 10 years ago

Committing registry2.0 to local branch

File size: 6.6 KB
Line 
1/*
2 * item.c
3 * $Id: $
4 *
5 * Copyright (c) 2007 Chris Pickel <sfiera@macports.org>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#if HAVE_CONFIG_H
30#include <config.h>
31#endif
32
33#include <string.h>
34#include <stdlib.h>
35#include <tcl.h>
36#include <sqlite3.h>
37
38#include "itemobj.h"
39#include "registry.h"
40#include "util.h"
41
42/* ${item} retain */
43/* Increments the refcount of the item. Calls to retain should be balanced by
44 * calls to release. The refcount starts at 1 and needn't be retained by the
45 * creator.
46 */
47static int item_obj_retain(Tcl_Interp* interp, item_t* item, int objc,
48        Tcl_Obj* CONST objv[]) {
49    sqlite3_stmt* stmt;
50    if (objc != 2) {
51        Tcl_WrongNumArgs(interp, 2, objv, "");
52        return TCL_ERROR;
53    }
54    sqlite3_prepare(item->db, "UPDATE items SET refcount = refcount+1 WHERE "
55            "rowid=?", -1, &stmt, NULL);
56    sqlite3_bind_int64(stmt, 1, item->rowid);
57    sqlite3_step(stmt);
58    sqlite3_finalize(stmt);
59    Tcl_SetObjResult(interp, objv[0]);
60    return TCL_OK;
61}
62
63/* ${item} release */
64/* Decrements the refcount of the item. If this is called after all retains have
65 * been balanced with releases, the object will be freed.
66 */
67static int item_obj_release(Tcl_Interp* interp, item_t* item, int objc,
68        Tcl_Obj* CONST objv[]) {
69    sqlite3_stmt* stmt;
70    int refcount;
71    if (objc != 2) {
72        Tcl_WrongNumArgs(interp, 2, objv, "");
73        return TCL_ERROR;
74    }
75    sqlite3_prepare(item->db, "UPDATE items SET refcount = refcount-1 "
76            "WHERE rowid=?", -1, &stmt, NULL);
77    sqlite3_bind_int64(stmt, 1, item->rowid);
78    sqlite3_step(stmt);
79    sqlite3_finalize(stmt);
80    sqlite3_prepare(item->db, "SELECT refcount FROM items WHERE rowid=?", -1,
81            &stmt, NULL);
82    sqlite3_bind_int64(stmt, 1, item->rowid);
83    sqlite3_step(stmt);
84    refcount = sqlite3_column_int(stmt, 0);
85    sqlite3_finalize(stmt);
86    if (refcount <= 0) {
87        Tcl_DeleteCommand(interp, Tcl_GetString(objv[0]));
88    }
89    return TCL_OK;
90}
91
92/* ${item} key name ?value? */
93static int item_obj_key(Tcl_Interp* interp, item_t* item, int objc,
94        Tcl_Obj* CONST objv[]) {
95    static const char* keys[] = {
96        "name", "url", "path", "worker", "options", "variants",
97        NULL
98    };
99    if (objc == 3) {
100        /* ${item} key name; return the current value */
101        int index;
102        if (Tcl_GetIndexFromObj(interp, objv[2], keys, "key", 0, &index)
103                != TCL_OK) {
104            /* objv[2] is not a valid key */
105            return TCL_ERROR;
106        } else {
107            sqlite3_stmt* stmt;
108            char query[64];
109            char* key = Tcl_GetString(objv[2]);
110            int len;
111            const char* result;
112            Tcl_Obj* resultObj;
113            sprintf(query, "SELECT %s FROM items WHERE rowid=?", key);
114            sqlite3_prepare(item->db, query, -1, &stmt, NULL);
115            sqlite3_bind_int64(stmt, 1, item->rowid);
116            sqlite3_step(stmt);
117            /* eliminate compiler warning about signedness */
118            result = sqlite3_column_text(stmt, 0);
119            len = sqlite3_column_bytes(stmt, 0);
120            resultObj = Tcl_NewStringObj(result, len);
121            Tcl_SetObjResult(interp, resultObj);
122            sqlite3_finalize(stmt);
123        }
124    } else if (objc == 4) {
125        /* ${item} key name value; set a new value */
126        int index;
127        if (Tcl_GetIndexFromObj(interp, objv[2], keys, "key", 0, &index)
128                != TCL_OK) {
129            /* objv[2] is not a valid key */
130            return TCL_ERROR;
131        } else {
132            sqlite3_stmt* stmt;
133            char query[64];
134            char* key = Tcl_GetString(objv[2]);
135            char* value = Tcl_GetString(objv[3]);
136            sprintf(query, "UPDATE items SET %s=? WHERE rowid=?", key);
137            sqlite3_prepare(item->db, query, -1, &stmt, NULL);
138            sqlite3_bind_text(stmt, 1, value, -1, SQLITE_STATIC);
139            sqlite3_bind_int64(stmt, 2, item->rowid);
140            sqlite3_step(stmt);
141            sqlite3_finalize(stmt);
142        }
143    } else {
144        Tcl_WrongNumArgs(interp, 1, objv, "key name ?value?");
145        return TCL_ERROR;
146    }
147    return TCL_OK;
148}
149
150typedef struct {
151    char* name;
152    int (*function)(Tcl_Interp* interp, item_t* item, int objc,
153            Tcl_Obj* CONST objv[]);
154} item_obj_cmd_type;
155
156static item_obj_cmd_type item_cmds[] = {
157    { "retain", item_obj_retain },
158    { "release", item_obj_release },
159    { "key", item_obj_key },
160    { NULL, NULL }
161};
162
163/* ${item} cmd ?arg ...? */
164/* This function implements the command that will be called when an item created
165 * by `registry::item` is used as a procedure. Since all data is kept in a
166 * temporary sqlite3 database that is created for the current interpreter, none
167 * of the sqlite3 functions used have any error checking. That should be a safe
168 * assumption, since nothing outside of registry:: should ever have the chance
169 * to touch it.
170 */
171int item_obj_cmd(ClientData clientData, Tcl_Interp* interp, int objc,
172        Tcl_Obj* CONST objv[]) {
173    int cmd_index;
174    if (objc < 2) {
175        Tcl_WrongNumArgs(interp, 1, objv, "cmd ?arg ...?");
176        return TCL_ERROR;
177    }
178    if (Tcl_GetIndexFromObjStruct(interp, objv[1], item_cmds,
179                sizeof(item_obj_cmd_type), "cmd", 0, &cmd_index) == TCL_OK) {
180        item_obj_cmd_type* cmd = &item_cmds[cmd_index];
181        return cmd->function(interp, (item_t*)clientData, objc, objv);
182    }
183    return TCL_ERROR;
184}
Note: See TracBrowser for help on using the repository browser.