summaryrefslogtreecommitdiff
path: root/include/libwapcaplet/libwapcaplet.h
blob: d8cc8411b926f738755acc7052056080053889da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
/* libwapcaplet.h
 *
 * String internment and management tools.
 *
 * Copyright 2009 The NetSurf Browser Project.
 *		  Daniel Silverstone <dsilvers@netsurf-browser.org>
 */

#ifndef libwapcaplet_h_
#define libwapcaplet_h_

#ifdef __cplusplus
extern "C"
{
#endif

#include <sys/types.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <assert.h>

/**
 * The type of a reference counter used in libwapcaplet.
 */
typedef uint32_t lwc_refcounter;
	
/**
 * The type of a hash value used in libwapcaplet.
 */
typedef uint32_t lwc_hash;

/**
 * An interned string.
 *
 * NOTE: The contents of this struct are considered *PRIVATE* and may
 * change in future revisions.  Do not rely on them whatsoever.
 * They're only here at all so that the ref, unref and matches etc can
 * use them.
 */
typedef struct lwc_string_s {
        struct lwc_string_s **	prevptr;
        struct lwc_string_s *	next;
        size_t		len;
        lwc_hash	hash;
        lwc_refcounter	refcnt;
        struct lwc_string_s *	insensitive;
} lwc_string;
	
/**
 * String iteration function
 *
 * @param str A string which has been interned.
 * @param pw The private pointer for the allocator.
 */
typedef void (*lwc_iteration_callback_fn)(lwc_string *str, void *pw);

/**
 * Result codes which libwapcaplet might return.
 */
typedef enum lwc_error_e {
	lwc_error_ok		= 0,	/**< No error. */
	lwc_error_oom		= 1,	/**< Out of memory. */
	lwc_error_range		= 2	/**< Substring internment out of range. */
} lwc_error;

/**
 * Intern a string.
 *
 * Take a copy of the string data referred to by \a s and \a slen and
 * intern it.  The resulting ::lwc_string can be used for simple and
 * caseless comparisons by ::lwc_string_isequal and
 * ::lwc_string_caseless_isequal respectively.
 *
 * @param s    Pointer to the start of the string to intern.
 * @param slen Length of the string in characters. (Not including any 
 *	       terminators)
 * @param ret  Pointer to ::lwc_string pointer to fill out.
 * @return     Result of operation, if not OK then the value pointed
 *	       to by \a ret will not be valid.
 *
 * @note The memory pointed to by \a s is not referenced by the result.
 * @note If the string was already present, its reference count is
 * incremented rather than allocating more memory.
 *
 * @note The returned string is currently NULL-terminated but this
 *	 will not necessarily be the case in future.  Try not to rely
 *	 on it.
 */
extern lwc_error lwc_intern_string(const char *s, size_t slen,
                                   lwc_string **ret);

/**
 * Intern a substring.
 *
 * Intern a subsequence of the provided ::lwc_string.
 *
 * @param str	   String to acquire substring from.
 * @param ssoffset Substring offset into \a str.
 * @param sslen	   Substring length.
 * @param ret	   Pointer to pointer to ::lwc_string to fill out.
 * @return	   Result of operation, if not OK then the value
 *		   pointed to by \a ret will not be valid.
 */
extern lwc_error lwc_intern_substring(lwc_string *str,
                                      size_t ssoffset, size_t sslen,
                                      lwc_string **ret);

/**
 * Optain a lowercased lwc_string from given lwc_string.
 *
 * @param str  String to create lowercase string from.
 * @param ret  Pointer to ::lwc_string pointer to fill out.
 * @return     Result of operation, if not OK then the value pointed
 *             to by \a ret will not be valid.
 */
extern lwc_error lwc_string_tolower(lwc_string *str, lwc_string **ret);

/**
 * Increment the reference count on an lwc_string.
 *
 * This increases the reference count on the given string. You should
 * use this when copying a string pointer into a persistent data
 * structure.
 *
 * @verbatim
 *   myobject->str = lwc_string_ref(myparent->str);
 * @endverbatim
 *
 * @param str The string to create another reference to.
 * @return    The string pointer to use in your new data structure.
 *
 * @note Use this if copying the string and intending both sides to retain
 * ownership.
 */
#define lwc_string_ref(str) ({lwc_string *__lwc_s = (str); assert(__lwc_s != NULL); __lwc_s->refcnt++; __lwc_s;})

/**
 * Release a reference on an lwc_string.
 *
 * This decreases the reference count on the given ::lwc_string.
 *
 * @param str The string to unref.
 *
 * @note If the reference count reaches zero then the string will be
 *       freed. (Ref count of 1 where string is its own insensitve match
 *       will also result in the string being freed.)
 */
#define lwc_string_unref(str) {						\
		lwc_string *__lwc_s = (str);				\
		assert(__lwc_s != NULL);				\
		__lwc_s->refcnt--;						\
		if ((__lwc_s->refcnt == 0) ||					\
		    ((__lwc_s->refcnt == 1) && (__lwc_s->insensitive == __lwc_s)))	\
			lwc_string_destroy(__lwc_s);				\
	}
	
/**
 * Destroy an unreffed lwc_string.
 *
 * This destroys an lwc_string whose reference count indicates that it should be.
 *
 * @param str The string to unref.
 */
extern void lwc_string_destroy(lwc_string *str);

/**
 * Check if two interned strings are equal.
 *
 * @param str1 The first string in the comparison.
 * @param str2 The second string in the comparison.
 * @param ret  A pointer to a boolean to be filled out with the result.
 * @return     Result of operation, if not ok then value pointed to
 *	       by \a ret will not be valid.
 */
#define lwc_string_isequal(str1, str2, ret) \
	((*(ret) = ((str1) == (str2))), lwc_error_ok)

/**
 * Check if two interned strings are case-insensitively equal.
 *
 * @param _str1 The first string in the comparison.
 * @param _str2 The second string in the comparison.
 * @param _ret  A pointer to a boolean to be filled out with the result.
 * @return Result of operation, if not ok then value pointed to by \a ret will
 *	    not be valid.
 */
#define lwc_string_caseless_isequal(_str1,_str2,_ret) ({                \
            lwc_error __lwc_err = lwc_error_ok;                         \
            lwc_string *__lwc_str1 = (_str1);                           \
            lwc_string *__lwc_str2 = (_str2);                           \
            bool *__lwc_ret = (_ret);                                   \
                                                                        \
            if (__lwc_str1->insensitive == NULL) {                      \
                __lwc_err = lwc__intern_caseless_string(__lwc_str1);    \
            }                                                           \
            if (__lwc_err == lwc_error_ok && __lwc_str2->insensitive == NULL) { \
                __lwc_err = lwc__intern_caseless_string(__lwc_str2);    \
            }                                                           \
            if (__lwc_err == lwc_error_ok)                              \
                *__lwc_ret = (__lwc_str1->insensitive == __lwc_str2->insensitive); \
            __lwc_err;                                                  \
        })
	
/**
 * Intern a caseless copy of the passed string.
 *
 * @param str The string to intern the caseless copy of.
 *
 * @return    lwc_error_ok if successful, otherwise the
 *            error code describing the issue.,
 *
 * @note This is for "internal" use by the caseless comparison
 *       macro and not for users.
 */	
extern lwc_error
lwc__intern_caseless_string(lwc_string *str);
	
/**
 * Retrieve the data pointer for an interned string.
 *
 * @param str The string to retrieve the data pointer for.
 * @return    The C string data pointer for \a str.
 *
 * @note The data we point at belongs to the string and will
 *	 die with the string. Keep a ref if you need it.
 * @note You may not rely on the NULL termination of the strings
 *	 in future.  Any code relying on it currently should be
 *	 modified to use ::lwc_string_length if possible.
 */
#define lwc_string_data(str) ({assert(str != NULL); (const char *)((str)+1);})

/**
 * Retrieve the data length for an interned string.
 *
 * @param str The string to retrieve the length of.
 * @return    The length of \a str.
 */
#define lwc_string_length(str) ({assert(str != NULL); (str)->len;})

/**
 * Retrieve (or compute if unavailable) a hash value for the content of the string.
 *
 * @param str The string to get the hash for.
 * @return    The 32 bit hash of \a str.
 *
 * @note This API should only be used as a convenient way to retrieve a hash
 *	 value for the string. This hash value should not be relied on to be
 *	 unique within an invocation of the program, nor should it be relied upon
 *	 to be stable between invocations of the program. Never use the hash
 *	 value as a way to directly identify the value of the string.
 */
#define lwc_string_hash_value(str) ({assert(str != NULL); (str)->hash;})

/**
 * Retrieve a hash value for the caseless content of the string.
 *
 * @param str   The string to get caseless hash value for.
 * @param hash  A pointer to a hash value to be filled out with the result.
 * @return Result of operation, if not ok then value pointed to by \a ret will
 *      not be valid.
 */
static inline lwc_error lwc_string_caseless_hash_value(
	lwc_string *str, lwc_hash *hash)
{
	if (str->insensitive == NULL) {
		lwc_error err = lwc__intern_caseless_string(str);
		if (err != lwc_error_ok) {
			return err;
		}
	}

	*hash = str->insensitive->hash;
	return lwc_error_ok;
}


/**
 * Iterate the context and return every string in it.
 *
 * @param cb The callback to give the string to.
 * @param pw The private word for the callback.
 */
extern void lwc_iterate_strings(lwc_iteration_callback_fn cb, void *pw);

#ifdef __cplusplus
}
#endif

#endif /* libwapcaplet_h_ */