Components in mpdm_sym() can be executable values (Closes: #1100).
[mpdm.git] / mpdm_v.c
blob0ec6d7ef8cc8419736a5f2c31bc28a19c22b5a01
1 /*
3 MPDM - Minimum Profit Data Manager
4 Copyright (C) 2003/2007 Angel Ortega <angel@triptico.com>
6 mpdm_t.c - Basic value management
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 http://www.triptico.com
26 #include "config.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <locale.h>
33 #include "mpdm.h"
35 /*******************
36 Data
37 ********************/
39 /* control structure */
41 struct mpdm_control * mpdm = NULL;
43 /*******************
44 Code
45 ********************/
47 int mpdm_destroy(mpdm_t v)
48 /* destroys a value */
50 /* if still referenced, don't do it */
51 if(v->ref)
52 return(0);
54 /* collapse multiple values */
55 if(v->flags & MPDM_MULTIPLE)
56 mpdm_collapse(v, 0, v->size);
58 /* free data if needed */
59 if(v->data != NULL && v->flags & MPDM_FREE)
61 mpdm->memory_usage -= v->size;
62 free(v->data);
65 /* dequeue */
66 v->next->prev = v->prev;
67 v->prev->next = v->next;
69 /* if it's the current one, move to next */
70 if(mpdm->cur == v)
71 mpdm->cur = v->next;
73 /* account one value less */
74 mpdm->count--;
76 /* finally free */
77 v->next = mpdm->del;
78 mpdm->del = v;
80 return(1);
84 /**
85 * mpdm_new - Creates a new value.
86 * @flags: flags
87 * @data: pointer to real data
88 * @size: size of data
90 * Creates a new value. @flags is an or-ed set of flags, @data is a
91 * pointer to the data the value will store and @size the size of these
92 * data (if value is to be a multiple one, @size is a number of elements,
93 * or a number of bytes otherwise).
95 * This function is normally not directly used; use any of the type
96 * creation macros instead.
97 * [Value Creation]
99 mpdm_t mpdm_new(int flags, void * data, int size)
101 mpdm_t v = NULL;
103 /* alloc */
104 if((v = mpdm->del) != NULL)
105 mpdm->del = v->next;
106 else
107 if((v = malloc(sizeof(struct mpdm_val))) == NULL)
108 return(NULL);
110 /* add to the circular list */
111 if(mpdm->cur == NULL)
112 v->next = v->prev = v;
113 else
115 v->prev = mpdm->cur;
116 v->next = mpdm->cur->next;
118 v->prev->next = v->next->prev = v;
121 mpdm->cur = v->next;
123 /* account one value more */
124 mpdm->count ++;
126 /* count memory if data is dynamic */
127 if(flags & MPDM_FREE)
128 mpdm->memory_usage += size;
130 v->flags = flags;
131 v->ref = 0;
132 v->data = data;
133 v->size = size;
135 return(v);
140 * mpdm_ref - Increments the reference count of a value.
141 * @v: the value
143 * Increments the reference count of a value.
144 * [Value Management]
146 mpdm_t mpdm_ref(mpdm_t v)
148 if(v != NULL) v->ref++;
149 return(v);
154 * mpdm_unref - Decrements the reference count of a value.
155 * @v: the value
157 * Decrements the reference count of a value.
158 * [Value Management]
160 mpdm_t mpdm_unref(mpdm_t v)
162 if(v != NULL) v->ref--;
163 return(v);
168 * mpdm_sweep - Sweeps unreferenced values.
169 * @count: number of values to be swept
171 * Destroys values with a reference count of 0. @count is the
172 * number of values to be checked for deletion; special values of
173 * @count are -1, that forces a check of all currently known values
174 * (can be time-consuming) and 0, which tells mpdm_sweep() to check a
175 * small group of them on each call.
176 * [Value Management]
178 void mpdm_sweep(int count)
180 /* if count is zero, sweep 'some' values */
181 if(count == 0) count = mpdm->default_sweep;
183 /* if count is -1, sweep all */
184 if(count == -1) count = mpdm->count;
186 for(;count > 0 && mpdm->count > mpdm->low_threshold;count --)
188 /* destroy it or skip it */
189 if(!mpdm_destroy(mpdm->cur))
190 mpdm->cur = mpdm->cur->next;
196 * mpdm_size - Returns the size of an element.
197 * @v: the element
199 * Returns the size of an element.
200 * [Value Management]
202 int mpdm_size(mpdm_t v)
204 /* NULL values have no size */
205 if(v == NULL) return(0);
207 return(v->size);
212 * mpdm_clone - Creates a clone of a value.
213 * @v: the value
215 * Creates a clone of a value. If the value is multiple, a new value will
216 * be created containing clones of all its elements; otherwise,
217 * the same unchanged value is returned.
218 * [Value Management]
220 mpdm_t mpdm_clone(mpdm_t v)
222 if(MPDM_IS_ARRAY(v))
223 v = mpdm_aclone(v);
225 return(v);
230 * mpdm_root - Returns the root hash.
232 * Returns the root hash. This hash is stored internally and can be used
233 * as a kind of global symbol table.
234 * [Value Management]
236 mpdm_t mpdm_root(void)
238 if(mpdm->root == NULL)
239 mpdm->root = mpdm_ref(MPDM_H(0));
241 return(mpdm->root);
246 * mpdm_exec - Executes an executable value.
247 * @c: the code value
248 * @args: the arguments
250 * Executes an executable value. If @c is a scalar value, its data
251 * should be a pointer to a directly executable C function with a
252 * prototype of mpdm_t func(mpdm_t args); if it's a multiple one,
253 * the first value's data should be a pointer to a directly executable C
254 * function with a prototype of mpdm_t func(mpdm_t b, mpdm_t args) and
255 * the second value will be passed as the @b argument. This value is used
256 * to store bytecode or so when implementing virtual machines or compilers.
258 * Returns the return value of the code. If @c is NULL or not executable,
259 * returns NULL.
260 * [Value Management]
262 mpdm_t mpdm_exec(mpdm_t c, mpdm_t args)
264 mpdm_t r = NULL;
266 if(c != NULL && (c->flags & MPDM_EXEC))
268 mpdm_ref(c);
269 mpdm_ref(args);
271 if(c->flags & MPDM_MULTIPLE)
273 mpdm_t x;
274 mpdm_t (* func)(mpdm_t, mpdm_t);
276 /* value is multiple; first element is the
277 2 argument version of the executable function,
278 next its optional additional information and
279 finally the arguments */
280 x = mpdm_aget(c, 0);
282 if((func = (mpdm_t (*)(mpdm_t, mpdm_t))(x->data)) != NULL)
283 r = func(mpdm_aget(c, 1), args);
285 else
287 mpdm_t (* func)(mpdm_t);
289 /* value is scalar; c is the 1 argument
290 version of the executable function */
291 if((func = (mpdm_t (*)(mpdm_t))(c->data)) != NULL)
292 r = func(args);
295 mpdm_unref(args);
296 mpdm_unref(c);
299 return(r);
303 mpdm_t mpdm_exec_1(mpdm_t c, mpdm_t a1)
305 mpdm_t r;
306 mpdm_t a = MPDM_A(1);
308 mpdm_aset(a, a1, 0);
309 r = mpdm_exec(c, a);
310 mpdm_destroy(a);
311 return(r);
315 mpdm_t mpdm_exec_2(mpdm_t c, mpdm_t a1, mpdm_t a2)
317 mpdm_t r;
318 mpdm_t a = MPDM_A(2);
320 mpdm_aset(a, a1, 0);
321 mpdm_aset(a, a2, 1);
322 r = mpdm_exec(c, a);
323 mpdm_destroy(a);
324 return(r);
328 mpdm_t mpdm_exec_3(mpdm_t c, mpdm_t a1, mpdm_t a2, mpdm_t a3)
330 mpdm_t r;
331 mpdm_t a = MPDM_A(3);
333 mpdm_aset(a, a1, 0);
334 mpdm_aset(a, a2, 1);
335 mpdm_aset(a, a3, 2);
336 r = mpdm_exec(c, a);
337 mpdm_destroy(a);
338 return(r);
342 mpdm_t mpdm_xnew(mpdm_t (* a1)(mpdm_t, mpdm_t), mpdm_t a2)
344 mpdm_t x;
346 x = MPDM_A(2);
347 x->flags |= MPDM_EXEC;
349 mpdm_aset(x, MPDM_X(a1), 0);
350 mpdm_aset(x, a2, 1);
352 return(x);
356 static mpdm_t MPDM(mpdm_t args)
357 /* accesor / mutator for MPDM internal data */
359 mpdm_t v = mpdm_aget(args, 0);
360 int n, c = 0;
362 if(v != NULL)
364 mpdm_t w;
366 /* do changes */
367 if((w = mpdm_hget_s(v, L"low_threshold")) != NULL &&
368 mpdm_ival(w) > 0)
369 mpdm->low_threshold = mpdm_ival(w);
371 if((w = mpdm_hget_s(v, L"default_sweep")) != NULL)
372 mpdm->default_sweep = mpdm_ival(w);
374 if((w = mpdm_hget_s(v, L"hash_buckets")) != NULL)
375 mpdm->hash_buckets = mpdm_ival(w);
378 /* loop all values counting the references ones */
379 for(n = mpdm->count, v = mpdm->cur;n > 0;n--, v = v->next)
380 if(v->ref == 0) c++;
382 /* now collect all information */
383 v = MPDM_H(0);
385 mpdm_hset_s(v, L"version", MPDM_MBS(VERSION));
386 mpdm_hset_s(v, L"count", MPDM_I(mpdm->count));
387 mpdm_hset_s(v, L"low_threshold", MPDM_I(mpdm->low_threshold));
388 mpdm_hset_s(v, L"default_sweep", MPDM_I(mpdm->default_sweep));
389 mpdm_hset_s(v, L"memory_usage", MPDM_I(mpdm->memory_usage));
390 mpdm_hset_s(v, L"hash_buckets", MPDM_I(mpdm->hash_buckets));
391 mpdm_hset_s(v, L"unreferenced", MPDM_I(c));
393 return(v);
398 * mpdm_startup - Initializes MPDM.
400 * Initializes the Minimum Profit Data Manager. Returns 0 if
401 * everything went OK.
403 int mpdm_startup(void)
405 /* do the startup only unless done beforehand */
406 if(mpdm == NULL)
408 /* alloc space */
409 if((mpdm = malloc(sizeof(struct mpdm_control))) == NULL)
410 return(-1);
412 /* cleans it */
413 memset(mpdm, '\0', sizeof(struct mpdm_control));
415 /* sets the defaults */
416 mpdm->low_threshold = 16;
417 mpdm->default_sweep = 16;
418 mpdm->hash_buckets = 31;
420 /* sets the locale */
421 if(setlocale(LC_ALL, "") == NULL)
422 setlocale(LC_ALL, "C");
424 /* store the MPDM() function */
425 mpdm_hset_s(mpdm_root(), L"MPDM", MPDM_X(MPDM));
428 /* everything went OK */
429 return(0);
434 * mpdm_shutdown - Shuts down MPDM.
436 * Shuts down MPDM. No MPDM functions should be used from now on.
438 void mpdm_shutdown(void)
440 /* dummy, by now */
444 * MPDM_A - Creates an array value.
445 * @n: Number of elements
447 * Creates a new array value with @n elements.
448 * [Value Creation]
450 /** mpdm_t MPDM_A(int n); */
451 /* ; */
454 * MPDM_H - Creates a hash value.
455 * @n: Number of buckets in the hash (0: use default)
457 * Creates a new hash value with @n buckets. The number
458 * of buckets must be a prime number. If @n is 0, an
459 * optimal number of buckets will be used.
460 * [Value Creation]
462 /** mpdm_t MPDM_H(int n); */
463 /* ; */
466 * MPDM_LS - Creates a string value from a literal string.
467 * @wcs: the wide character string
469 * Creates a new string value from a literal, wide character string.
470 * A pointer to the string will be stored in the value (not a copy).
471 * [Value Creation]
473 /** mpdm_t MPDM_LS(wchar_t * wcs); */
474 /* ; */
477 * MPDM_S - Creates a string value from a string.
478 * @wcs: the wide character string
480 * Creates a new string value from a wide character string. The value
481 * will store a copy of the string that will be freed on destruction.
482 * [Value Creation]
484 /** mpdm_t MPDM_S(wchar_t * wcs); */
485 /* ; */
488 * MPDM_NS - Creates a string value from a string, with size.
489 * @wcs: the wide character string
490 * @s: the size in chars the string will hold
492 * Creates a new string value with a copy of the first @s characters
493 * from the @wcs string.
494 * [Value Creation]
496 /** mpdm_t MPDM_NS(wchar_t * wcs, int s); */
497 /* ; */
500 * MPDM_ENS - Creates a string value from an external string, with size.
501 * @wcs: the external wide character string
502 * @s: the size in chars the string will hold
504 * Creates a new string value with size @s. The @wcs string must be
505 * a dynamic value (i.e. allocated by malloc()) that will be freed on
506 * destruction.
507 * [Value Creation]
509 /** mpdm_t MPDM_ENS(wchar_t * wcs, int s); */
510 /* ; */
513 * MPDM_I - Creates an integer value.
514 * @i: the integer
516 * Creates a new integer value. MPDM integers are strings.
517 * [Value Creation]
519 /** mpdm_t MPDM_I(int i); */
520 /* ; */
523 * MPDM_R - Creates a real value.
524 * @r: the real number
526 * Creates a new real value. MPDM integers are strings.
527 * [Value Creation]
529 /** mpdm_t MPDM_R(double r); */
530 /* ; */
533 * MPDM_F - Creates a file value.
534 * @f: the file descriptor
536 * Creates a new file value.
537 * [Value Creation]
539 /** mpdm_t MPDM_F(FILE * f); */
540 /* ; */
543 * MPDM_MBS - Creates a string value from a multibyte string.
544 * @mbs: the multibyte string
546 * Creates a new string value from a multibyte string, that will be
547 * converted to wcs by mpdm_mbstowcs().
548 * [Value Creation]
550 /** mpdm_t MPDM_MBS(char * mbs); */
551 /* ; */
554 * MPDM_NMBS - Creates a string value from a multibyte string, with size.
555 * @mbs: the multibyte string
556 * @s: the size
558 * Creates a new string value with the first @s characters from the @mbs
559 * multibyte string, that will be converted to wcs by mpdm_mbstowcs().
560 * [Value Creation]
562 /** mpdm_t MPDM_NMBS(char * mbs, int s); */
563 /* ; */
566 * MPDM_2MBS - Creates a multibyte string value from a wide char string.
567 * @wcs: the wide char string
569 * Creates a multibyte string value from the @wcs wide char string,
570 * converting it by mpdm_wcstombs(). Take note that multibyte string values
571 * are not properly strings, so they cannot be used for string comparison
572 * and such.
573 * [Value Creation]
575 /** mpdm_t MPDM_2MBS(wchar_t * wcs); */
576 /* ; */
579 * MPDM_X - Creates a new executable value.
580 * @func: the C code function
582 * Creates a new executable value given a pointer to the @func C code function.
583 * The function must receive an mpdm_t array value (that will hold their
584 * arguments) and return another one.
585 * [Value Creation]
587 /** mpdm_t MPDM_X(mpdm_t (* func)(mpdm_t args)); */
588 /* ; */
591 * MPDM_IS_ARRAY - Tests if a value is an array.
592 * @v: the value
594 * Returns non-zero if @v is an array.
596 /** int MPDM_IS_ARRAY(mpdm_t v); */
597 /* ; */
600 * MPDM_IS_HASH - Tests if a value is a hash.
601 * @v: the value
603 * Returns non-zero if @v is a hash.
605 /** int MPDM_IS_HASH(mpdm_t v); */
606 /* ; */
609 * MPDM_IS_EXEC - Tests if a value is executable.
610 * @v: the value
612 * Returns non-zero if @v is executable.
614 /** int MPDM_IS_EXEC(mpdm_t v); */
615 /* ; */
618 * MPDM_IS_STRING - Tests if a value is a string.
619 * @v: the value
621 * Returns non-zero if @v is a string.
623 /** int MPDM_IS_STRING(mpdm_t v); */
624 /* ; */