source: branches/gsoc11-statistics/base/src/cregistry/util.c @ 140222

Last change on this file since 140222 was 105085, checked in by snc@…, 7 years ago

merge from trunk

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 6.6 KB
Line 
1/*
2 * util.c
3 * vim:tw=80:expandtab
4 * $Id: util.c 105085 2013-04-09 18:46:31Z snc@macports.org $
5 *
6 * Copyright (c) 2007 Chris Pickel <sfiera@macports.org>
7 * Copyright (c) 2012 The MacPorts Project
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "util.h"
32
33#include <stdlib.h>
34#include <string.h>
35
36/**
37 * Concatenates `src` to string `dst`. Simple concatenation. Only guaranteed to
38 * work with strings that have been allocated with `malloc`. Amortizes cost of
39 * expanding string buffer for O(N) concatenation and such. Uses `memcpy` in
40 * favor of `strcpy` in hopes it will perform a bit better.
41 *
42 * @param [in,out] dst       a reference to a null-terminated string
43 * @param [in,out] dst_len   number of characters currently in `dst`
44 * @param [in,out] dst_space number of characters `dst` can hold
45 * @param [in] src           string to concatenate to `dst`
46 */
47int reg_strcat(char** dst, size_t* dst_len, size_t* dst_space, char* src) {
48    size_t src_len = strlen(src);
49    size_t result_len = *dst_len + src_len;
50    if (result_len > *dst_space) {
51        char* new_dst;
52        *dst_space *= 2;
53        if (*dst_space < result_len) {
54            *dst_space = result_len;
55        }
56        new_dst = realloc(*dst, *dst_space * sizeof(char) + 1);
57        if (!new_dst)
58            return 0;
59        else
60            *dst = new_dst;
61    }
62    memcpy(*dst + *dst_len, src, src_len+1);
63    *dst_len = result_len;
64    return 1;
65}
66
67/**
68 * Appends element `src` to the list `dst`. It's like `reg_strcat`, except `src`
69 * represents a single element and not a sequence of `char`s.
70 *
71 * @param [in,out] dst       a reference to a list of pointers
72 * @param [in,out] dst_len   number of elements currently in `dst`
73 * @param [in,out] dst_space number of elements `dst` can hold
74 * @param [in] src           elements to append to `dst`
75 */
76int reg_listcat(void*** dst, int* dst_len, int* dst_space, void* src) {
77    if (*dst_len == *dst_space) {
78        void** new_dst;
79        *dst_space *= 2;
80        new_dst = realloc(*dst, *dst_space * sizeof(void*));
81        if (!new_dst)
82            return 0;
83        else
84            *dst = new_dst;
85    }
86    (*dst)[*dst_len] = src;
87    (*dst_len)++;
88    return 1;
89}
90
91/**
92 * Returns an expression to use for the given strategy. This should be passed as
93 * the `fmt` argument of `sqlite3_mprintf`, with the key and value following.
94 *
95 * @param [in] strategy a strategy (one of the `reg_strategy_*` constants)
96 * @param [out] errPtr  on error, a description of the error that occurred
97 * @return              a sqlite3 expression if success; NULL if failure
98 */
99char* reg_strategy_op(reg_strategy strategy, reg_error* errPtr) {
100    switch (strategy) {
101        case reg_strategy_exact:
102            return "%q = '%q'";
103        case reg_strategy_glob:
104            return "%q GLOB '%q'";
105        case reg_strategy_regexp:
106            return "REGEXP(%q, '%q')";
107        case reg_strategy_null:
108            return "%q IS NULL";
109        default:
110            errPtr->code = REG_INVALID;
111            errPtr->description = "invalid matching strategy specified";
112            errPtr->free = NULL;
113            return NULL;
114    }
115}
116
117/**
118 * Convenience method for returning all objects of a given type from the
119 * registry.
120 *
121 * @param [in] reg       registry to select objects from
122 * @param [in] query     the select query to execute
123 * @param [in] query_len length of the query (or -1 for automatic)
124 * @param [out] objects  the objects selected
125 * @param [in] fn        a function to convert sqlite3_stmts to the desired type
126 * @param [inout] data   data passed along to the cast function
127 * @param [in] del       a function to delete the desired type of object
128 * @param [out] errPtr   on error, a description of the error that occurred
129 * @return               the number of objects if success; negative if failure
130 */
131int reg_all_objects(reg_registry* reg, char* query, int query_len,
132        void*** objects, cast_function* fn, void* castcalldata,
133        free_function* del, reg_error* errPtr) {
134    void** results = malloc(10*sizeof(void*));
135    int result_count = 0;
136    int result_space = 10;
137    sqlite3_stmt* stmt = NULL;
138    if (!results || !fn) {
139        return -1;
140    }
141    if (sqlite3_prepare_v2(reg->db, query, query_len, &stmt, NULL) == SQLITE_OK) {
142        int r;
143        void* row;
144        do {
145            r = sqlite3_step(stmt);
146            switch (r) {
147                case SQLITE_ROW:
148                    if (fn(reg, &row, stmt, castcalldata, errPtr)) {
149                        if (!reg_listcat(&results, &result_count, &result_space, row)) {
150                            r = SQLITE_ERROR;
151                        }
152                    } else {
153                        r = SQLITE_ERROR;
154                    }
155                    break;
156                case SQLITE_DONE:
157                    break;
158                case SQLITE_BUSY:
159                    continue;
160                default:
161                    reg_sqlite_error(reg->db, errPtr, query);
162                    break;
163            }
164        } while (r == SQLITE_ROW || r == SQLITE_BUSY);
165        sqlite3_finalize(stmt);
166        if (r == SQLITE_DONE) {
167            *objects = results;
168            return result_count;
169        } else if (del) {
170            int i;
171            for (i=0; i<result_count; i++) {
172                del(NULL, results[i]);
173            }
174        }
175    } else {
176        if (stmt) {
177            sqlite3_finalize(stmt);
178        }
179        reg_sqlite_error(reg->db, errPtr, query);
180    }
181    free(results);
182    return -1;
183}
184
Note: See TracBrowser for help on using the repository browser.