Ref/unref all args in mpdm_strcat().
[mpdm.git] / mpdm_v.c
blob3e6011c46131ddc378d860bc9454dd49cf76ae30
1 /*
3 MPDM - Minimum Profit Data Manager
4 Copyright (C) 2003/2010 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"
36 /** data **/
38 /* control structure */
40 struct mpdm_control *mpdm = NULL;
43 /** code **/
45 static void cleanup_value(mpdm_t v)
46 /* cleans a value */
48 /* collapse multiple values */
49 if (v->flags & MPDM_MULTIPLE)
50 mpdm_collapse(v, 0, v->size);
52 /* free data if needed */
53 if (v->data != NULL && v->flags & MPDM_FREE) {
54 mpdm->memory_usage -= v->size;
55 free((void *)v->data);
56 v->data = NULL;
61 int mpdm_destroy(mpdm_t v)
62 /* destroys a value */
64 int ret = 0;
65 mpdm_t w;
67 if (v->ref == 0 && !(v->flags & MPDM_DELETED)) {
68 cleanup_value(v);
70 /* mark as deleted */
71 v->flags |= MPDM_DELETED;
73 ret = 1;
76 /* try to dequeue next one */
77 w = v->next;
79 if (w && w->flags & MPDM_DELETED) {
80 /* dequeue */
81 v->next = w->next;
83 /* if it's the current one, move to next */
84 if (mpdm->cur == w)
85 mpdm->cur = w->next;
87 /* account one value less */
88 mpdm->count--;
90 /* add to the deleted values queue */
91 w->next = mpdm->del;
92 mpdm->del = w;
95 return ret;
99 /**
100 * mpdm_new - Creates a new value.
101 * @flags: flags
102 * @data: pointer to real data
103 * @size: size of data
105 * Creates a new value. @flags is an or-ed set of flags, @data is a
106 * pointer to the data the value will store and @size the size of these
107 * data (if value is to be a multiple one, @size is a number of elements,
108 * or a number of bytes otherwise).
110 * This function is normally not directly used; use any of the type
111 * creation macros instead.
112 * [Value Creation]
114 mpdm_t mpdm_new(int flags, const void *data, int size)
116 mpdm_t v = NULL;
118 /* alloc */
119 if ((v = mpdm->del) != NULL)
120 mpdm->del = v->next;
121 else
122 if ((v = malloc(sizeof(struct mpdm_val))) == NULL)
123 return NULL;
125 /* add to the circular list */
126 if (mpdm->cur == NULL)
127 v->next = v;
128 else {
129 v->next = mpdm->cur->next;
130 mpdm->cur->next = v;
133 mpdm->cur = v->next;
135 /* account one value more */
136 mpdm->count++;
138 /* count memory if data is dynamic */
139 if (flags & MPDM_FREE)
140 mpdm->memory_usage += size;
142 v->flags = flags;
143 v->ref = 0;
144 v->data = data;
145 v->size = size;
147 return v;
152 * mpdm_ref - Increments the reference count of a value.
153 * @v: the value
155 * Increments the reference count of a value.
156 * [Value Management]
158 mpdm_t mpdm_ref(mpdm_t v)
160 if (v != NULL)
161 v->ref++;
162 return v;
167 * mpdm_unref - Decrements the reference count of a value.
168 * @v: the value
170 * Decrements the reference count of a value.
171 * [Value Management]
173 mpdm_t mpdm_unref(mpdm_t v)
175 if (v != NULL) {
176 v->ref--;
178 #ifdef DESTROY_ON_UNREF
179 if (v->ref <= 0) {
180 mpdm_destroy(v);
181 v = NULL;
183 #endif
186 return v;
191 * mpdm_unrefnd - Decrements the reference count of a value, without destroy.
192 * @v: the value
194 * Decrements the reference count of a value, without destroying
195 * the value if it's unreferenced.
196 * [Value Management]
198 mpdm_t mpdm_unrefnd(mpdm_t v)
200 if (v != NULL)
201 v->ref--;
202 return v;
207 * mpdm_sweep - Sweeps unreferenced values.
208 * @count: number of values to be swept
210 * Destroys values with a reference count of 0. @count is the
211 * number of values to be checked for deletion; special values of
212 * @count are -1, that forces a check of all currently known values
213 * (can be time-consuming) and 0, which tells mpdm_sweep() to check a
214 * small group of them on each call.
215 * [Value Management]
217 void mpdm_sweep(int count)
219 /* if count is zero, sweep 'some' values */
220 if (count == 0) {
221 if (mpdm->default_sweep < 0)
222 count = mpdm->count / -mpdm->default_sweep;
223 else
224 count = mpdm->default_sweep;
227 /* if count is -1, sweep all */
228 if (count == -1)
229 count = mpdm->count;
231 for (; count > 0 && mpdm->count > mpdm->low_threshold; count--) {
232 mpdm_destroy(mpdm->cur);
233 mpdm->cur = mpdm->cur->next;
239 * mpdm_size - Returns the size of an element.
240 * @v: the element
242 * Returns the size of an element.
243 * [Value Management]
245 int mpdm_size(const mpdm_t v)
247 /* NULL values have no size */
248 if (v == NULL)
249 return 0;
251 return v->size;
256 * mpdm_clone - Creates a clone of a value.
257 * @v: the value
259 * Creates a clone of a value. If the value is multiple, a new value will
260 * be created containing clones of all its elements; otherwise,
261 * the same unchanged value is returned.
262 * [Value Management]
264 mpdm_t mpdm_clone(const mpdm_t v)
266 mpdm_t r;
268 mpdm_ref(v);
270 if (MPDM_IS_ARRAY(v))
271 r = mpdm_aclone(v);
272 else
273 r = v;
275 mpdm_unref(v);
277 return r;
282 * mpdm_root - Returns the root hash.
284 * Returns the root hash. This hash is stored internally and can be used
285 * as a kind of global symbol table.
286 * [Value Management]
288 mpdm_t mpdm_root(void)
290 if (mpdm->root == NULL)
291 mpdm->root = mpdm_ref(MPDM_H(0));
293 return mpdm->root;
297 mpdm_t mpdm_set_ival(mpdm_t v, int ival)
298 /* sets an integer value to a value */
300 v->flags |= MPDM_IVAL;
301 v->ival = ival;
303 return v;
307 mpdm_t mpdm_set_rval(mpdm_t v, double rval)
308 /* sets a real value to a value */
310 v->flags |= MPDM_RVAL;
311 v->rval = rval;
313 return v;
318 * mpdm_exec - Executes an executable value.
319 * @c: the code value
320 * @args: the arguments
322 * Executes an executable value. If @c is a scalar value, its data
323 * should be a pointer to a directly executable C function with a
324 * prototype of mpdm_t func(mpdm_t args); if it's a multiple one,
325 * the first value's data should be a pointer to a directly executable C
326 * function with a prototype of mpdm_t func(mpdm_t b, mpdm_t args) and
327 * the second value will be passed as the @b argument. This value is used
328 * to store bytecode or so when implementing virtual machines or compilers.
330 * Returns the return value of the code. If @c is NULL or not executable,
331 * returns NULL.
332 * [Value Management]
334 mpdm_t mpdm_exec(mpdm_t c, mpdm_t args)
336 mpdm_t r = NULL;
338 if (c != NULL && (c->flags & MPDM_EXEC)) {
339 mpdm_ref(c);
340 mpdm_ref(args);
342 if (c->flags & MPDM_MULTIPLE) {
343 mpdm_t x;
344 mpdm_t(*func) (mpdm_t, mpdm_t);
346 /* value is multiple; first element is the
347 2 argument version of the executable function,
348 next its optional additional information and
349 finally the arguments */
350 x = mpdm_aget(c, 0);
352 if ((func = (mpdm_t(*)(mpdm_t, mpdm_t)) (x->data)) != NULL)
353 r = func(mpdm_aget(c, 1), args);
355 else {
356 mpdm_t(*func) (mpdm_t);
358 /* value is scalar; c is the 1 argument
359 version of the executable function */
360 if ((func = (mpdm_t(*)(mpdm_t)) (c->data)) != NULL)
361 r = func(args);
364 mpdm_unref(args);
365 mpdm_unref(c);
368 return r;
372 mpdm_t mpdm_exec_1(mpdm_t c, mpdm_t a1)
374 mpdm_t a = MPDM_A(1);
376 mpdm_aset(a, a1, 0);
377 return mpdm_exec(c, a);
381 mpdm_t mpdm_exec_2(mpdm_t c, mpdm_t a1, mpdm_t a2)
383 mpdm_t a = MPDM_A(2);
385 mpdm_aset(a, a1, 0);
386 mpdm_aset(a, a2, 1);
387 return mpdm_exec(c, a);
391 mpdm_t mpdm_exec_3(mpdm_t c, mpdm_t a1, mpdm_t a2, mpdm_t a3)
393 mpdm_t a = MPDM_A(3);
395 mpdm_aset(a, a1, 0);
396 mpdm_aset(a, a2, 1);
397 mpdm_aset(a, a3, 2);
398 return mpdm_exec(c, a);
402 mpdm_t mpdm_xnew(mpdm_t(*a1) (mpdm_t, mpdm_t), mpdm_t a2)
404 mpdm_t x;
406 x = MPDM_A(2);
407 x->flags |= MPDM_EXEC;
409 mpdm_aset(x, MPDM_X(a1), 0);
410 mpdm_aset(x, a2, 1);
412 return x;
416 static mpdm_t MPDM(const mpdm_t args)
417 /* accesor / mutator for MPDM internal data */
419 mpdm_t v;
420 int n, c = 0, d = 0;
422 mpdm_ref(args);
424 v = mpdm_aget(args, 0);
426 if (v != NULL) {
427 mpdm_t w;
429 /* do changes */
430 if ((w = mpdm_hget_s(v, L"low_threshold")) != NULL && mpdm_ival(w) > 0)
431 mpdm->low_threshold = mpdm_ival(w);
433 if ((w = mpdm_hget_s(v, L"default_sweep")) != NULL)
434 mpdm->default_sweep = mpdm_ival(w);
436 if ((w = mpdm_hget_s(v, L"hash_buckets")) != NULL)
437 mpdm->hash_buckets = mpdm_ival(w);
440 /* loop all values counting the unreferenced and deleted ones */
441 for (n = mpdm->count, v = mpdm->cur; n > 0; n--, v = v->next) {
442 if (v->ref)
443 continue;
445 if (v->flags & MPDM_DELETED)
446 d++;
447 else
448 c++;
451 /* now collect all information */
452 v = MPDM_H(0);
454 mpdm_hset_s(v, L"version", MPDM_MBS(VERSION));
455 mpdm_hset_s(v, L"count", MPDM_I(mpdm->count));
456 mpdm_hset_s(v, L"low_threshold", MPDM_I(mpdm->low_threshold));
457 mpdm_hset_s(v, L"default_sweep", MPDM_I(mpdm->default_sweep));
458 mpdm_hset_s(v, L"memory_usage", MPDM_I(mpdm->memory_usage));
459 mpdm_hset_s(v, L"hash_buckets", MPDM_I(mpdm->hash_buckets));
460 mpdm_hset_s(v, L"unreferenced", MPDM_I(c));
461 mpdm_hset_s(v, L"deleted", MPDM_I(d));
463 #ifdef DESTROY_ON_UNREF
464 mpdm_hset_s(v, L"destroy_on_unref",MPDM_I(1));
465 #endif
467 mpdm_unref(args);
469 return v;
472 extern char **environ;
474 static mpdm_t build_env(void)
475 /* builds a hash with the environment */
477 char **ptr;
478 mpdm_t e = MPDM_H(0);
480 for (ptr = environ; *ptr != NULL; ptr++) {
481 char *eq = strchr(*ptr, '=');
483 if (eq != NULL) {
484 mpdm_t k, v;
486 k = MPDM_NMBS((*ptr), eq - (*ptr));
487 v = MPDM_MBS(eq + 1);
489 mpdm_hset(e, k, v);
493 return e;
498 * mpdm_startup - Initializes MPDM.
500 * Initializes the Minimum Profit Data Manager. Returns 0 if
501 * everything went OK.
503 int mpdm_startup(void)
505 /* do the startup only unless done beforehand */
506 if (mpdm == NULL) {
507 /* alloc space */
508 if ((mpdm = malloc(sizeof(struct mpdm_control))) == NULL)
509 return -1;
511 /* cleans it */
512 memset(mpdm, '\0', sizeof(struct mpdm_control));
514 /* sets the defaults */
515 mpdm->low_threshold = 16;
516 mpdm->default_sweep = -50000;
517 mpdm->hash_buckets = 31;
519 /* sets the locale */
520 if (setlocale(LC_ALL, "") == NULL)
521 setlocale(LC_ALL, "C");
523 mpdm_encoding(NULL);
525 /* store the MPDM() function */
526 mpdm_hset_s(mpdm_root(), L"MPDM", MPDM_X(MPDM));
528 /* store the ENV hash */
529 mpdm_hset_s(mpdm_root(), L"ENV", build_env());
532 /* everything went OK */
533 return 0;
538 * mpdm_shutdown - Shuts down MPDM.
540 * Shuts down MPDM. No MPDM functions should be used from now on.
542 void mpdm_shutdown(void)
544 /* dummy, by now */
548 * MPDM_A - Creates an array value.
549 * @n: Number of elements
551 * Creates a new array value with @n elements.
552 * [Value Creation]
554 /** mpdm_t MPDM_A(int n); */
555 /* ; */
558 * MPDM_H - Creates a hash value.
559 * @n: Number of buckets in the hash (0: use default)
561 * Creates a new hash value with @n buckets. The number
562 * of buckets must be a prime number. If @n is 0, an
563 * optimal number of buckets will be used.
564 * [Value Creation]
566 /** mpdm_t MPDM_H(int n); */
567 /* ; */
570 * MPDM_LS - Creates a string value from a literal string.
571 * @wcs: the wide character string
573 * Creates a new string value from a literal, wide character string.
574 * A pointer to the string will be stored in the value (not a copy).
575 * [Value Creation]
577 /** mpdm_t MPDM_LS(wchar_t * wcs); */
578 /* ; */
581 * MPDM_S - Creates a string value from a string.
582 * @wcs: the wide character string
584 * Creates a new string value from a wide character string. The value
585 * will store a copy of the string that will be freed on destruction.
586 * [Value Creation]
588 /** mpdm_t MPDM_S(wchar_t * wcs); */
589 /* ; */
592 * MPDM_NS - Creates a string value from a string, with size.
593 * @wcs: the wide character string
594 * @s: the size in chars the string will hold
596 * Creates a new string value with a copy of the first @s characters
597 * from the @wcs string.
598 * [Value Creation]
600 /** mpdm_t MPDM_NS(wchar_t * wcs, int s); */
601 /* ; */
604 * MPDM_ENS - Creates a string value from an external string, with size.
605 * @wcs: the external wide character string
606 * @s: the size in chars the string will hold
608 * Creates a new string value with size @s. The @wcs string must be
609 * a dynamic value (i.e. allocated by malloc()) that will be freed on
610 * destruction.
611 * [Value Creation]
613 /** mpdm_t MPDM_ENS(wchar_t * wcs, int s); */
614 /* ; */
617 * MPDM_I - Creates an integer value.
618 * @i: the integer
620 * Creates a new integer value. MPDM integers are strings.
621 * [Value Creation]
623 /** mpdm_t MPDM_I(int i); */
624 /* ; */
627 * MPDM_R - Creates a real value.
628 * @r: the real number
630 * Creates a new real value. MPDM integers are strings.
631 * [Value Creation]
633 /** mpdm_t MPDM_R(double r); */
634 /* ; */
637 * MPDM_F - Creates a file value.
638 * @f: the file descriptor
640 * Creates a new file value.
641 * [Value Creation]
643 /** mpdm_t MPDM_F(FILE * f); */
644 /* ; */
647 * MPDM_MBS - Creates a string value from a multibyte string.
648 * @mbs: the multibyte string
650 * Creates a new string value from a multibyte string, that will be
651 * converted to wcs by mpdm_mbstowcs().
652 * [Value Creation]
654 /** mpdm_t MPDM_MBS(char * mbs); */
655 /* ; */
658 * MPDM_NMBS - Creates a string value from a multibyte string, with size.
659 * @mbs: the multibyte string
660 * @s: the size
662 * Creates a new string value with the first @s characters from the @mbs
663 * multibyte string, that will be converted to wcs by mpdm_mbstowcs().
664 * [Value Creation]
666 /** mpdm_t MPDM_NMBS(char * mbs, int s); */
667 /* ; */
670 * MPDM_2MBS - Creates a multibyte string value from a wide char string.
671 * @wcs: the wide char string
673 * Creates a multibyte string value from the @wcs wide char string,
674 * converting it by mpdm_wcstombs(). Take note that multibyte string values
675 * are not properly strings, so they cannot be used for string comparison
676 * and such.
677 * [Value Creation]
679 /** mpdm_t MPDM_2MBS(wchar_t * wcs); */
680 /* ; */
683 * MPDM_X - Creates a new executable value.
684 * @func: the C code function
686 * Creates a new executable value given a pointer to the @func C code function.
687 * The function must receive an mpdm_t array value (that will hold their
688 * arguments) and return another one.
689 * [Value Creation]
691 /** mpdm_t MPDM_X(mpdm_t (* func)(mpdm_t args)); */
692 /* ; */
695 * MPDM_IS_ARRAY - Tests if a value is an array.
696 * @v: the value
698 * Returns non-zero if @v is an array.
700 /** int MPDM_IS_ARRAY(mpdm_t v); */
701 /* ; */
704 * MPDM_IS_HASH - Tests if a value is a hash.
705 * @v: the value
707 * Returns non-zero if @v is a hash.
709 /** int MPDM_IS_HASH(mpdm_t v); */
710 /* ; */
713 * MPDM_IS_EXEC - Tests if a value is executable.
714 * @v: the value
716 * Returns non-zero if @v is executable.
718 /** int MPDM_IS_EXEC(mpdm_t v); */
719 /* ; */
722 * MPDM_IS_STRING - Tests if a value is a string.
723 * @v: the value
725 * Returns non-zero if @v is a string.
727 /** int MPDM_IS_STRING(mpdm_t v); */
728 /* ; */