source: trunk/base/src/registry2.0/item.c @ 27967

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

Setting properties on registry2.0/cregistry

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 8.3 KB
Line 
1/*
2 * item.c
3 * $Id: item.c 27967 2007-08-16 20:14:31Z sfiera@macports.org $
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 "item.h"
39#include "itemobj.h"
40#include "util.h"
41#include "registry.h"
42
43static void delete_item(ClientData clientData) {
44    sqlite_int64 rowid = ((item_t*)clientData)->rowid;
45    sqlite3* db = ((item_t*)clientData)->db;
46    sqlite3_stmt* stmt;
47    sqlite3_prepare(db, "DELETE FROM items WHERE rowid=?", -1, &stmt, NULL);
48    sqlite3_bind_int(stmt, rowid, 1);
49    sqlite3_step(stmt);
50    sqlite3_finalize(stmt);
51    free(clientData);
52}
53
54static item_t* get_item(Tcl_Interp* interp, char* name) {
55    return (item_t*)get_object(interp, name, "item", item_obj_cmd);
56}
57
58static int set_item(Tcl_Interp* interp, char* name, sqlite_int64 rowid) {
59    sqlite3* db = registry_db(interp, 0);
60    item_t* new_item = malloc(sizeof(item_t));
61    new_item->rowid = rowid;
62    new_item->db = db;
63    if (set_object(interp, name, new_item, "item", item_obj_cmd, delete_item)
64                == TCL_OK) {
65        sqlite3_stmt* stmt;
66        /* record the proc name in case we need to return it in a search */
67        if ((sqlite3_prepare(db, "UPDATE items SET proc=? WHERE rowid=?", -1,
68                    &stmt, NULL) == SQLITE_OK)
69                && (sqlite3_bind_text(stmt, 1, name, -1, SQLITE_STATIC)
70                    == SQLITE_OK)
71                && (sqlite3_bind_int64(stmt, 2, rowid) == SQLITE_OK)
72                && (sqlite3_step(stmt) == SQLITE_DONE)) {
73            sqlite3_finalize(stmt);
74            return TCL_OK;
75        }
76        Tcl_DeleteCommand(interp, name);
77        sqlite3_finalize(stmt);
78    }
79    free(new_item);
80    return TCL_ERROR;
81}
82
83/* item create ?name? */
84static int item_create(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) {
85    sqlite_int64 item;
86    sqlite3* db = registry_db(interp, 0);
87    if (objc > 3) {
88        Tcl_WrongNumArgs(interp, 2, objv, "?name?");
89        return TCL_ERROR;
90    } else if (db == NULL) {
91        return TCL_ERROR;
92    }
93    sqlite3_exec(db, "INSERT INTO items (refcount) VALUES (1)", NULL, NULL,
94            NULL);
95    item = sqlite3_last_insert_rowid(db);
96    if (objc == 3) {
97        /* item create name */
98        char* name = Tcl_GetString(objv[2]);
99        if (set_item(interp, name, item) == TCL_OK) {
100            Tcl_SetObjResult(interp, objv[2]);
101            return TCL_OK;
102        }
103    } else {
104        /* item create */
105        char* name = unique_name(interp, "registry::item");
106        if (set_item(interp, name, item) == TCL_OK) {
107            Tcl_Obj* res = Tcl_NewStringObj(name, -1);
108            Tcl_SetObjResult(interp, res);
109            free(name);
110            return TCL_OK;
111        }
112        free(name);
113    }
114    return TCL_ERROR;
115}
116
117/* item release ?name ...? */
118static int item_release(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) {
119    int i;
120    for (i=2; i<objc; i++) {
121        char* proc = Tcl_GetString(objv[i]);
122        item_t* item = get_item(interp, proc);
123        if (item == NULL) {
124            return TCL_ERROR;
125        } else {
126            /* decref */
127        }
128    }
129    return TCL_OK;
130}
131
132static const char* searchKeys[] = {
133    "name",
134    "url",
135    "path",
136    "worker",
137    "options",
138    "variants",
139    NULL
140};
141
142/**
143 * item search ?{key value} ...?
144 *
145 * TODO: rip this out and adapt `entry search`
146 */
147static int item_search(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) {
148    int i, r;
149    sqlite3* db = registry_db(interp, 0);
150    sqlite3_stmt* stmt;
151    Tcl_Obj* result;
152    /* 40 + 20 per clause is safe */
153    char* query = (char*)malloc((20*objc)*sizeof(char));
154    char* insert;
155    if (db == NULL) {
156        return TCL_ERROR;
157    }
158    strcpy(query, "SELECT proc FROM items");
159    insert = query + strlen("SELECT proc FROM items");
160    for (i=2; i<objc; i++) {
161        int len;
162        int index;
163        char* key;
164        Tcl_Obj* keyObj;
165        /* ensure each search clause is a 2-element list */
166        if (Tcl_ListObjLength(interp, objv[i], &len) != TCL_OK || len != 2) {
167            free(query);
168            Tcl_AppendResult(interp, "search clause \"", Tcl_GetString(objv[i]),
169                    "\" is not a list with 2 elements", NULL);
170            return TCL_ERROR;
171        }
172        /* this should't fail if Tcl_ListObjLength didn't */
173        Tcl_ListObjIndex(interp, objv[i], 0, &keyObj);
174        /* ensure that a valid search key was used */
175        if (Tcl_GetIndexFromObj(interp, keyObj, searchKeys, "search key", 0,
176                &index) != TCL_OK) {
177            free(query);
178            return TCL_ERROR;
179        }
180        key = Tcl_GetString(keyObj);
181        if (i == 2) {
182            sprintf(insert, " WHERE %s=?", key);
183            insert += 9 + strlen(key);
184        } else {
185            sprintf(insert, " AND %s=?", key);
186            insert += 7 + strlen(key);
187        }
188    }
189    r = sqlite3_prepare(db, query, -1, &stmt, NULL);
190    free(query);
191    for (i=2; i<objc; i++) {
192        char* val;
193        Tcl_Obj* valObj;
194        Tcl_ListObjIndex(interp, objv[i], 1, &valObj);
195        val = Tcl_GetString(valObj);
196        sqlite3_bind_text(stmt, i-1, val, -1, SQLITE_STATIC);
197    }
198    result = Tcl_NewListObj(0, NULL);
199    r = sqlite3_step(stmt);
200    while (r == SQLITE_ROW) {
201        /* avoid signedness warning */
202        const char* proc = sqlite3_column_text(stmt, 0);
203        int len = sqlite3_column_bytes(stmt, 0);
204        Tcl_Obj* procObj = Tcl_NewStringObj(proc, len);
205        Tcl_ListObjAppendElement(interp, result, procObj);
206        r = sqlite3_step(stmt);
207    }
208    Tcl_SetObjResult(interp, result);
209    return TCL_OK;
210}
211
212/* item exists name */
213static int item_exists(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) {
214    if (objc != 3) {
215        Tcl_WrongNumArgs(interp, 2, objv, "name");
216        return TCL_ERROR;
217    }
218    if (get_item(interp, Tcl_GetString(objv[2])) == NULL) {
219        Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0));
220    } else {
221        Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
222    }
223    return TCL_OK;
224}
225
226typedef struct {
227    char* name;
228    int (*function)(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]);
229} item_cmd_type;
230
231static item_cmd_type item_cmds[] = {
232    /* Global commands */
233    { "create", item_create },
234    { "search", item_search },
235    { "exists", item_exists },
236    /* Instance commands */
237    /*
238    { "retain", item_retain },
239    { "release", item_release },
240    { "name", item_name },
241    { "url", item_url },
242    { "path", item_path },
243    { "worker", item_worker },
244    { "options", item_options },
245    { "variants", item_variants },
246    */
247    { NULL, NULL }
248};
249
250/* item cmd ?arg ...? */
251int item_cmd(ClientData clientData UNUSED, Tcl_Interp* interp, int objc,
252        Tcl_Obj* CONST objv[]) {
253    int cmd_index;
254    if (objc < 2) {
255        Tcl_WrongNumArgs(interp, 1, objv, "cmd ?arg ...?");
256        return TCL_ERROR;
257    }
258    if (Tcl_GetIndexFromObjStruct(interp, objv[1], item_cmds,
259                sizeof(item_cmd_type), "cmd", 0, &cmd_index) == TCL_OK) {
260        item_cmd_type* cmd = &item_cmds[cmd_index];
261        return cmd->function(interp, objc, objv);
262    }
263    return TCL_ERROR;
264}
Note: See TracBrowser for help on using the repository browser.