Do not call mpdm_aclone() in executable values.
[mpdm.git] / mpdm_v.c
blobae28ba1173f24662082f4480d0e2d650ca06f961
1 /*
3 MPDM - Minimum Profit Data Manager
4 Copyright (C) 2003/2011 Angel Ortega <angel@triptico.com>
6 mpdm_v.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 int n;
52 for (n = 0; n < mpdm_size(v); n++)
53 mpdm_unref(mpdm_aget(v, n));
56 /* free data if needed */
57 if (v->data != NULL && v->flags & MPDM_FREE) {
58 free((void *) v->data);
59 v->data = NULL;
62 mpdm->count--;
64 free(v);
68 static void destroy_value(mpdm_t v)
69 /* destroys a value */
71 if (mpdm->threaded_delete) {
72 /* atomically enqueue this value */
73 mpdm_mutex_lock(mpdm->del_queue_mutex);
75 v->next = mpdm->del;
76 mpdm->del = v;
78 mpdm_mutex_unlock(mpdm->del_queue_mutex);
80 /* notify the del queue thread */
81 mpdm_semaphore_post(mpdm->del_queue_sem);
83 else
84 cleanup_value(v);
88 static mpdm_t del_queue_thread(mpdm_t args, mpdm_t ctxt)
89 /* delete queue processing thread */
91 for (;;) {
92 mpdm_t v;
94 /* wait for next value */
95 mpdm_semaphore_wait(mpdm->del_queue_sem);
97 /* do nothing if the queue is empty (should't happen) */
98 if (mpdm->del == NULL)
99 continue;
101 /* atomically dequeue */
102 mpdm_mutex_lock(mpdm->del_queue_mutex);
104 v = mpdm->del;
105 mpdm->del = v->next;
107 mpdm_mutex_unlock(mpdm->del_queue_mutex);
109 cleanup_value(v);
112 return NULL;
117 * mpdm_new - Creates a new value.
118 * @flags: flags
119 * @data: pointer to real data
120 * @size: size of data
122 * Creates a new value. @flags is an or-ed set of flags, @data is a
123 * pointer to the data the value will store and @size the size of these
124 * data (if value is to be a multiple one, @size is a number of elements,
125 * or a number of bytes otherwise).
127 * This function is normally not directly used; use any of the type
128 * creation macros instead.
129 * [Value Creation]
131 mpdm_t mpdm_new(int flags, const void *data, int size)
133 mpdm_t v = NULL;
135 /* alloc */
136 if ((v = malloc(sizeof(struct mpdm_val))) != NULL) {
137 /* account one value more */
138 mpdm->count++;
140 v->flags = flags;
141 v->ref = 0;
142 v->data = data;
143 v->size = size;
144 v->next = NULL;
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++;
163 return v;
168 * mpdm_unref - Decrements the reference count of a value.
169 * @v: the value
171 * Decrements the reference count of a value. If the reference
172 * count of the value reaches 0, it's destroyed.
173 * [Value Management]
175 mpdm_t mpdm_unref(mpdm_t v)
177 if (v != NULL) {
178 v->ref--;
180 if (v->ref <= 0) {
181 destroy_value(v);
182 v = NULL;
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--;
203 return v;
208 * mpdm_size - Returns the size of an element.
209 * @v: the element
211 * Returns the size of an element. It does not change the
212 * reference count of the value.
213 * [Value Management]
215 int mpdm_size(const mpdm_t v)
217 int r = 0;
219 /* NULL values have no size */
220 if (v != NULL)
221 r = v->size;
223 return r;
228 * mpdm_clone - Creates a clone of a value.
229 * @v: the value
231 * Creates a clone of a value. If the value is multiple, a new value will
232 * be created containing clones of all its elements; otherwise,
233 * the same unchanged value is returned.
234 * [Value Management]
236 mpdm_t mpdm_clone(const mpdm_t v)
238 mpdm_t r;
240 mpdm_ref(v);
242 if (MPDM_IS_ARRAY(v) && !MPDM_IS_EXEC(v))
243 r = mpdm_aclone(v);
244 else
245 r = v;
247 mpdm_unref(v);
249 return r;
254 * mpdm_root - Returns the root hash.
256 * Returns the root hash. This hash is stored internally and can be used
257 * as a kind of global symbol table.
258 * [Value Management]
260 mpdm_t mpdm_root(void)
262 if (mpdm->root == NULL)
263 mpdm->root = mpdm_ref(MPDM_H(0));
265 return mpdm->root;
270 * mpdm_set_ival - Sets the integer value.
271 * @v: the value
272 * @ival: the integer
274 * Sets the integer value for @v. It does not change
275 * the reference count of @v.
277 mpdm_t mpdm_set_ival(mpdm_t v, int ival)
278 /* sets an integer value to a value */
280 v->flags |= MPDM_IVAL;
281 v->ival = ival;
283 return v;
288 * mpdm_set_rval - Sets the real value.
289 * @v: the value
290 * @rval: the real
292 * Sets the real value for @v. It does not change
293 * the reference count of @v.
295 mpdm_t mpdm_set_rval(mpdm_t v, double rval)
296 /* sets a real value to a value */
298 v->flags |= MPDM_RVAL;
299 v->rval = rval;
301 return v;
306 * mpdm_void - Refs then unrefs a value.
307 * @v: the value
309 * References and unreferences a value. To be used to receive
310 * the output of mpdm_exec() in case of it being void (i.e.
311 * its return value ignored).
313 void mpdm_void(mpdm_t v)
315 mpdm_ref(v);
316 mpdm_unref(v);
321 * mpdm_is_null - Returns 1 if a value is NULL.
322 * @v: the value
324 * Returns 1 if a value is NULL. The reference count is touched.
326 int mpdm_is_null(mpdm_t v)
328 int r;
330 mpdm_ref(v);
331 r = v == NULL ? 1 : 0;
332 mpdm_unref(v);
334 return r;
339 * mpdm_exec - Executes an executable value.
340 * @c: the code value
341 * @args: the arguments
342 * @ctxt: the context
344 * Executes an executable value. If @c is a scalar value, its data
345 * should be a pointer to a directly executable C function with a
346 * prototype of mpdm_t func(mpdm_t args, mpdm_t ctxt); if it's a multiple
347 * one, the first value's data should be a pointer to a directly executable
348 * C function with a prototype of
349 * mpdm_t func(mpdm_t b, mpdm_t args, mpdm_t ctxt) and
350 * the second value will be passed as the @b argument. This value is used
351 * to store bytecode or so when implementing virtual machines or compilers.
352 * The @ctxt is meant to be used as a special context to implement local
353 * symbol tables and such. Its meaning is free and can be NULL.
355 * Returns the return value of the code. If @c is NULL or not executable,
356 * returns NULL.
357 * [Value Management]
359 mpdm_t mpdm_exec(mpdm_t c, mpdm_t args, mpdm_t ctxt)
361 mpdm_t r = NULL;
363 mpdm_ref(c);
364 mpdm_ref(args);
365 mpdm_ref(ctxt);
367 if (c != NULL && (c->flags & MPDM_EXEC)) {
369 if (c->flags & MPDM_MULTIPLE) {
370 mpdm_t x;
371 mpdm_t(*func) (mpdm_t, mpdm_t, mpdm_t);
373 /* value is multiple; first element is the
374 3 argument version of the executable function,
375 next its optional additional information,
376 the arguments and the context */
377 x = mpdm_aget(c, 0);
379 if ((func =
380 (mpdm_t(*)(mpdm_t, mpdm_t, mpdm_t)) (x->data)) != NULL)
381 r = func(mpdm_aget(c, 1), args, ctxt);
383 else {
384 mpdm_t(*func) (mpdm_t, mpdm_t);
386 /* value is scalar; c is the 2 argument
387 version of the executable function */
388 if ((func = (mpdm_t(*)(mpdm_t, mpdm_t)) (c->data)) != NULL)
389 r = func(args, ctxt);
393 mpdm_unref(ctxt);
394 mpdm_unref(args);
395 mpdm_unref(c);
397 return r;
401 mpdm_t mpdm_exec_1(mpdm_t c, mpdm_t a1, mpdm_t ctxt)
403 mpdm_t r;
404 mpdm_t a = MPDM_A(1);
406 mpdm_ref(a);
407 mpdm_aset(a, a1, 0);
409 r = mpdm_exec(c, a, ctxt);
411 mpdm_unref(a);
413 return r;
417 mpdm_t mpdm_exec_2(mpdm_t c, mpdm_t a1, mpdm_t a2, mpdm_t ctxt)
419 mpdm_t r;
420 mpdm_t a = MPDM_A(2);
422 mpdm_ref(a);
423 mpdm_aset(a, a1, 0);
424 mpdm_aset(a, a2, 1);
426 r = mpdm_exec(c, a, ctxt);
428 mpdm_unref(a);
430 return r;
434 mpdm_t mpdm_exec_3(mpdm_t c, mpdm_t a1, mpdm_t a2, mpdm_t a3, mpdm_t ctxt)
436 mpdm_t r;
437 mpdm_t a = MPDM_A(3);
439 mpdm_ref(a);
440 mpdm_aset(a, a1, 0);
441 mpdm_aset(a, a2, 1);
442 mpdm_aset(a, a3, 2);
444 r = mpdm_exec(c, a, ctxt);
446 mpdm_unref(a);
448 return r;
452 mpdm_t mpdm_xnew(mpdm_t(*a1) (mpdm_t, mpdm_t, mpdm_t), mpdm_t a2)
454 mpdm_t x;
456 x = MPDM_A(2);
457 x->flags |= MPDM_EXEC;
459 mpdm_ref(x);
461 mpdm_aset(x, MPDM_X(a1), 0);
462 mpdm_aset(x, a2, 1);
464 mpdm_unrefnd(x);
466 return x;
470 mpdm_t mpdm_new_copy(int flags, void *ptr, int size)
472 mpdm_t r = NULL;
474 if (ptr != NULL) {
475 char *ptr2 = malloc(size);
476 memcpy(ptr2, ptr, size);
478 r = mpdm_new(MPDM_FREE | flags, ptr2, size);
481 return r;
485 static mpdm_t MPDM(const mpdm_t args, mpdm_t ctxt)
486 /* accesor / mutator for MPDM internal data */
488 mpdm_t v;
490 mpdm_ref(args);
492 v = mpdm_aget(args, 0);
494 if (v != NULL) {
495 mpdm_t w;
497 /* do changes */
498 if ((w = mpdm_hget_s(v, L"hash_buckets")) != NULL)
499 mpdm->hash_buckets = mpdm_ival(w);
500 else
501 if ((w = mpdm_hget_s(v, L"threaded_delete")) != NULL)
502 mpdm->threaded_delete = mpdm_ival(w);
505 /* now collect all information */
506 v = MPDM_H(0);
508 mpdm_ref(v);
510 mpdm_hset_s(v, L"version", MPDM_MBS(VERSION));
511 mpdm_hset_s(v, L"count", MPDM_I(mpdm->count));
512 mpdm_hset_s(v, L"hash_buckets", MPDM_I(mpdm->hash_buckets));
513 mpdm_hset_s(v, L"threaded_delete", MPDM_I(mpdm->threaded_delete));
515 mpdm_unref(args);
517 mpdm_unrefnd(v);
519 return v;
522 extern char **environ;
524 static mpdm_t build_env(void)
525 /* builds a hash with the environment */
527 char **ptr;
528 mpdm_t e = MPDM_H(0);
530 mpdm_ref(e);
532 for (ptr = environ; *ptr != NULL; ptr++) {
533 char *eq = strchr(*ptr, '=');
535 if (eq != NULL) {
536 mpdm_t k, v;
538 k = MPDM_NMBS((*ptr), eq - (*ptr));
539 v = MPDM_MBS(eq + 1);
541 mpdm_hset(e, k, v);
545 mpdm_unrefnd(e);
547 return e;
552 * mpdm_startup - Initializes MPDM.
554 * Initializes the Minimum Profit Data Manager. Returns 0 if
555 * everything went OK.
557 int mpdm_startup(void)
559 /* do the startup only unless done beforehand */
560 if (mpdm == NULL) {
561 /* alloc space */
562 if ((mpdm = malloc(sizeof(struct mpdm_control))) == NULL)
563 return -1;
565 /* cleans it */
566 memset(mpdm, '\0', sizeof(struct mpdm_control));
568 /* sets the defaults */
569 mpdm->hash_buckets = 31;
571 /* sets the threaded delete control */
572 mpdm->threaded_delete = 0;
574 /* create the threaded delete thread and control */
575 mpdm->del_queue_mutex = mpdm_new_mutex();
576 mpdm->del_queue_sem = mpdm_new_semaphore(0);
577 mpdm_exec_thread(MPDM_X(del_queue_thread), NULL, NULL);
579 /* sets the locale */
580 if (setlocale(LC_ALL, "") == NULL)
581 setlocale(LC_ALL, "C");
583 mpdm_encoding(NULL);
585 /* store the MPDM() function */
586 mpdm_hset_s(mpdm_root(), L"MPDM", MPDM_X(MPDM));
588 /* store the ENV hash */
589 mpdm_hset_s(mpdm_root(), L"ENV", build_env());
592 /* everything went OK */
593 return 0;
598 * mpdm_shutdown - Shuts down MPDM.
600 * Shuts down MPDM. No MPDM functions should be used from now on.
602 void mpdm_shutdown(void)
604 /* dummy, by now */
608 * MPDM_A - Creates an array value.
609 * @n: Number of elements
611 * Creates a new array value with @n elements.
612 * [Value Creation]
614 /** mpdm_t MPDM_A(int n); */
615 /* ; */
618 * MPDM_H - Creates a hash value.
619 * @n: Number of buckets in the hash (0: use default)
621 * Creates a new hash value with @n buckets. The number
622 * of buckets must be a prime number. If @n is 0, an
623 * optimal number of buckets will be used.
624 * [Value Creation]
626 /** mpdm_t MPDM_H(int n); */
627 /* ; */
630 * MPDM_LS - Creates a string value from a literal string.
631 * @wcs: the wide character string
633 * Creates a new string value from a literal, wide character string.
634 * A pointer to the string will be stored in the value (not a copy).
635 * [Value Creation]
637 /** mpdm_t MPDM_LS(wchar_t * wcs); */
638 /* ; */
641 * MPDM_S - Creates a string value from a string.
642 * @wcs: the wide character string
644 * Creates a new string value from a wide character string. The value
645 * will store a copy of the string that will be freed on destruction.
646 * [Value Creation]
648 /** mpdm_t MPDM_S(wchar_t * wcs); */
649 /* ; */
652 * MPDM_NS - Creates a string value from a string, with size.
653 * @wcs: the wide character string
654 * @s: the size in chars the string will hold
656 * Creates a new string value with a copy of the first @s characters
657 * from the @wcs string.
658 * [Value Creation]
660 /** mpdm_t MPDM_NS(wchar_t * wcs, int s); */
661 /* ; */
664 * MPDM_ENS - Creates a string value from an external string, with size.
665 * @wcs: the external wide character string
666 * @s: the size in chars the string will hold
668 * Creates a new string value with size @s. The @wcs string must be
669 * a dynamic value (i.e. allocated by malloc()) that will be freed on
670 * destruction.
671 * [Value Creation]
673 /** mpdm_t MPDM_ENS(wchar_t * wcs, int s); */
674 /* ; */
677 * MPDM_I - Creates an integer value.
678 * @i: the integer
680 * Creates a new integer value. MPDM integers are strings.
681 * [Value Creation]
683 /** mpdm_t MPDM_I(int i); */
684 /* ; */
687 * MPDM_R - Creates a real value.
688 * @r: the real number
690 * Creates a new real value. MPDM integers are strings.
691 * [Value Creation]
693 /** mpdm_t MPDM_R(double r); */
694 /* ; */
697 * MPDM_F - Creates a file value.
698 * @f: the file descriptor
700 * Creates a new file value.
701 * [Value Creation]
703 /** mpdm_t MPDM_F(FILE * f); */
704 /* ; */
707 * MPDM_MBS - Creates a string value from a multibyte string.
708 * @mbs: the multibyte string
710 * Creates a new string value from a multibyte string, that will be
711 * converted to wcs by mpdm_mbstowcs().
712 * [Value Creation]
714 /** mpdm_t MPDM_MBS(char * mbs); */
715 /* ; */
718 * MPDM_NMBS - Creates a string value from a multibyte string, with size.
719 * @mbs: the multibyte string
720 * @s: the size
722 * Creates a new string value with the first @s characters from the @mbs
723 * multibyte string, that will be converted to wcs by mpdm_mbstowcs().
724 * [Value Creation]
726 /** mpdm_t MPDM_NMBS(char * mbs, int s); */
727 /* ; */
730 * MPDM_2MBS - Creates a multibyte string value from a wide char string.
731 * @wcs: the wide char string
733 * Creates a multibyte string value from the @wcs wide char string,
734 * converting it by mpdm_wcstombs(). Take note that multibyte string values
735 * are not properly strings, so they cannot be used for string comparison
736 * and such.
737 * [Value Creation]
739 /** mpdm_t MPDM_2MBS(wchar_t * wcs); */
740 /* ; */
743 * MPDM_X - Creates a new executable value.
744 * @func: the C code function
746 * Creates a new executable value given a pointer to the @func C code function.
747 * The function must receive an mpdm_t array value (that will hold their
748 * arguments) and return another one.
749 * [Value Creation]
751 /** mpdm_t MPDM_X(mpdm_t (* func)(mpdm_t args)); */
752 /* ; */
755 * MPDM_C - Creates a new value with a copy of a buffer.
756 * @flags: additional flags
757 * @ptr: pointer to data
758 * @size: data size
760 * Create a new value with a copy of a buffer. The value will store a copy
761 * of @ptr and have the additional @flags.
762 * [Value Creation]
764 /** mpdm_t MPDM_C(int flags, void *ptr, int size); */
765 /* ; */
768 * MPDM_IS_ARRAY - Tests if a value is an array.
769 * @v: the value
771 * Returns non-zero if @v is an array.
773 /** int MPDM_IS_ARRAY(mpdm_t v); */
774 /* ; */
777 * MPDM_IS_HASH - Tests if a value is a hash.
778 * @v: the value
780 * Returns non-zero if @v is a hash.
782 /** int MPDM_IS_HASH(mpdm_t v); */
783 /* ; */
786 * MPDM_IS_EXEC - Tests if a value is executable.
787 * @v: the value
789 * Returns non-zero if @v is executable.
791 /** int MPDM_IS_EXEC(mpdm_t v); */
792 /* ; */
795 * MPDM_IS_STRING - Tests if a value is a string.
796 * @v: the value
798 * Returns non-zero if @v is a string.
800 /** int MPDM_IS_STRING(mpdm_t v); */
801 /* ; */