Got rid of the threaded_delete code and the 'next' pointer in values.
[mpdm.git] / mpdm_v.c
blob0664d1bf8e9b5078fbe5059bc317be4492f95c7a
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 cleanup_value(v);
75 /**
76 * mpdm_new - Creates a new value.
77 * @flags: flags
78 * @data: pointer to real data
79 * @size: size of data
81 * Creates a new value. @flags is an or-ed set of flags, @data is a
82 * pointer to the data the value will store and @size the size of these
83 * data (if value is to be a multiple one, @size is a number of elements,
84 * or a number of bytes otherwise).
86 * This function is normally not directly used; use any of the type
87 * creation macros instead.
88 * [Value Creation]
90 mpdm_t mpdm_new(int flags, const void *data, int size)
92 mpdm_t v = NULL;
94 /* alloc */
95 if ((v = malloc(sizeof(struct mpdm_val))) != NULL) {
96 /* account one value more */
97 mpdm->count++;
99 v->flags = flags;
100 v->ref = 0;
101 v->data = data;
102 v->size = size;
105 return v;
110 * mpdm_ref - Increments the reference count of a value.
111 * @v: the value
113 * Increments the reference count of a value.
114 * [Value Management]
116 mpdm_t mpdm_ref(mpdm_t v)
118 if (v != NULL)
119 v->ref++;
121 return v;
126 * mpdm_unref - Decrements the reference count of a value.
127 * @v: the value
129 * Decrements the reference count of a value. If the reference
130 * count of the value reaches 0, it's destroyed.
131 * [Value Management]
133 mpdm_t mpdm_unref(mpdm_t v)
135 if (v != NULL) {
136 v->ref--;
138 if (v->ref <= 0) {
139 destroy_value(v);
140 v = NULL;
144 return v;
149 * mpdm_unrefnd - Decrements the reference count of a value, without destroy.
150 * @v: the value
152 * Decrements the reference count of a value, without destroying
153 * the value if it's unreferenced.
154 * [Value Management]
156 mpdm_t mpdm_unrefnd(mpdm_t v)
158 if (v != NULL)
159 v->ref--;
161 return v;
166 * mpdm_size - Returns the size of an element.
167 * @v: the element
169 * Returns the size of an element. It does not change the
170 * reference count of the value.
171 * [Value Management]
173 int mpdm_size(const mpdm_t v)
175 int r = 0;
177 /* NULL values have no size */
178 if (v != NULL)
179 r = v->size;
181 return r;
186 * mpdm_clone - Creates a clone of a value.
187 * @v: the value
189 * Creates a clone of a value. If the value is multiple, a new value will
190 * be created containing clones of all its elements; otherwise,
191 * the same unchanged value is returned.
192 * [Value Management]
194 mpdm_t mpdm_clone(const mpdm_t v)
196 mpdm_t r;
198 if (MPDM_IS_ARRAY(v) && !MPDM_IS_EXEC(v))
199 r = mpdm_aclone(v);
200 else
201 r = v;
203 return r;
208 * mpdm_root - Returns the root hash.
210 * Returns the root hash. This hash is stored internally and can be used
211 * as a kind of global symbol table.
212 * [Value Management]
214 mpdm_t mpdm_root(void)
216 if (mpdm->root == NULL)
217 mpdm->root = mpdm_ref(MPDM_H(0));
219 return mpdm->root;
224 * mpdm_set_ival - Sets the integer value.
225 * @v: the value
226 * @ival: the integer
228 * Sets the integer value for @v. It does not change
229 * the reference count of @v.
231 mpdm_t mpdm_set_ival(mpdm_t v, int ival)
232 /* sets an integer value to a value */
234 v->flags |= MPDM_IVAL;
235 v->ival = ival;
237 return v;
242 * mpdm_set_rval - Sets the real value.
243 * @v: the value
244 * @rval: the real
246 * Sets the real value for @v. It does not change
247 * the reference count of @v.
249 mpdm_t mpdm_set_rval(mpdm_t v, double rval)
250 /* sets a real value to a value */
252 v->flags |= MPDM_RVAL;
253 v->rval = rval;
255 return v;
260 * mpdm_void - Refs then unrefs a value.
261 * @v: the value
263 * References and unreferences a value. To be used to receive
264 * the output of mpdm_exec() in case of it being void (i.e.
265 * its return value ignored).
267 void mpdm_void(mpdm_t v)
269 mpdm_ref(v);
270 mpdm_unref(v);
275 * mpdm_is_null - Returns 1 if a value is NULL.
276 * @v: the value
278 * Returns 1 if a value is NULL. The reference count is touched.
280 int mpdm_is_null(mpdm_t v)
282 int r;
284 mpdm_ref(v);
285 r = v == NULL ? 1 : 0;
286 mpdm_unref(v);
288 return r;
293 * mpdm_exec - Executes an executable value.
294 * @c: the code value
295 * @args: the arguments
296 * @ctxt: the context
298 * Executes an executable value. If @c is a scalar value, its data
299 * should be a pointer to a directly executable C function with a
300 * prototype of mpdm_t func(mpdm_t args, mpdm_t ctxt); if it's a multiple
301 * one, the first value's data should be a pointer to a directly executable
302 * C function with a prototype of
303 * mpdm_t func(mpdm_t b, mpdm_t args, mpdm_t ctxt) and
304 * the second value will be passed as the @b argument. This value is used
305 * to store bytecode or so when implementing virtual machines or compilers.
306 * The @ctxt is meant to be used as a special context to implement local
307 * symbol tables and such. Its meaning is free and can be NULL.
309 * Returns the return value of the code. If @c is NULL or not executable,
310 * returns NULL.
311 * [Value Management]
313 mpdm_t mpdm_exec(mpdm_t c, mpdm_t args, mpdm_t ctxt)
315 mpdm_t r = NULL;
317 mpdm_ref(c);
318 mpdm_ref(args);
319 mpdm_ref(ctxt);
321 if (c != NULL && (c->flags & MPDM_EXEC)) {
323 if (c->flags & MPDM_MULTIPLE) {
324 mpdm_t x;
325 mpdm_t(*func) (mpdm_t, mpdm_t, mpdm_t);
327 /* value is multiple; first element is the
328 3 argument version of the executable function,
329 next its optional additional information,
330 the arguments and the context */
331 x = mpdm_aget(c, 0);
333 if ((func =
334 (mpdm_t(*)(mpdm_t, mpdm_t, mpdm_t)) (x->data)) != NULL)
335 r = func(mpdm_aget(c, 1), args, ctxt);
337 else {
338 mpdm_t(*func) (mpdm_t, mpdm_t);
340 /* value is scalar; c is the 2 argument
341 version of the executable function */
342 if ((func = (mpdm_t(*)(mpdm_t, mpdm_t)) (c->data)) != NULL)
343 r = func(args, ctxt);
347 mpdm_unref(ctxt);
348 mpdm_unref(args);
349 mpdm_unref(c);
351 return r;
355 mpdm_t mpdm_exec_1(mpdm_t c, mpdm_t a1, mpdm_t ctxt)
357 mpdm_t r;
358 mpdm_t a = MPDM_A(1);
360 mpdm_ref(a);
361 mpdm_aset(a, a1, 0);
363 r = mpdm_exec(c, a, ctxt);
365 mpdm_unref(a);
367 return r;
371 mpdm_t mpdm_exec_2(mpdm_t c, mpdm_t a1, mpdm_t a2, mpdm_t ctxt)
373 mpdm_t r;
374 mpdm_t a = MPDM_A(2);
376 mpdm_ref(a);
377 mpdm_aset(a, a1, 0);
378 mpdm_aset(a, a2, 1);
380 r = mpdm_exec(c, a, ctxt);
382 mpdm_unref(a);
384 return r;
388 mpdm_t mpdm_exec_3(mpdm_t c, mpdm_t a1, mpdm_t a2, mpdm_t a3, mpdm_t ctxt)
390 mpdm_t r;
391 mpdm_t a = MPDM_A(3);
393 mpdm_ref(a);
394 mpdm_aset(a, a1, 0);
395 mpdm_aset(a, a2, 1);
396 mpdm_aset(a, a3, 2);
398 r = mpdm_exec(c, a, ctxt);
400 mpdm_unref(a);
402 return r;
406 mpdm_t mpdm_xnew(mpdm_t(*a1) (mpdm_t, mpdm_t, mpdm_t), mpdm_t a2)
408 mpdm_t x;
410 x = MPDM_A(2);
411 x->flags |= MPDM_EXEC;
413 mpdm_ref(x);
415 mpdm_aset(x, MPDM_X(a1), 0);
416 mpdm_aset(x, a2, 1);
418 mpdm_unrefnd(x);
420 return x;
424 mpdm_t mpdm_new_copy(int flags, void *ptr, int size)
426 mpdm_t r = NULL;
428 if (ptr != NULL) {
429 char *ptr2 = malloc(size);
430 memcpy(ptr2, ptr, size);
432 r = mpdm_new(MPDM_FREE | flags, ptr2, size);
435 return r;
439 static mpdm_t MPDM(const mpdm_t args, mpdm_t ctxt)
440 /* accesor / mutator for MPDM internal data */
442 mpdm_t v;
444 mpdm_ref(args);
446 v = mpdm_aget(args, 0);
448 if (v != NULL) {
449 mpdm_t w;
451 /* do changes */
452 if ((w = mpdm_hget_s(v, L"hash_buckets")) != NULL)
453 mpdm->hash_buckets = mpdm_ival(w);
456 /* now collect all information */
457 v = MPDM_H(0);
459 mpdm_ref(v);
461 mpdm_hset_s(v, L"version", MPDM_MBS(VERSION));
462 mpdm_hset_s(v, L"count", MPDM_I(mpdm->count));
463 mpdm_hset_s(v, L"hash_buckets", MPDM_I(mpdm->hash_buckets));
465 mpdm_unref(args);
467 mpdm_unrefnd(v);
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 mpdm_ref(e);
482 for (ptr = environ; *ptr != NULL; ptr++) {
483 char *eq = strchr(*ptr, '=');
485 if (eq != NULL) {
486 mpdm_t k, v;
488 k = MPDM_NMBS((*ptr), eq - (*ptr));
489 v = MPDM_MBS(eq + 1);
491 mpdm_hset(e, k, v);
495 mpdm_unrefnd(e);
497 return e;
502 * mpdm_startup - Initializes MPDM.
504 * Initializes the Minimum Profit Data Manager. Returns 0 if
505 * everything went OK.
507 int mpdm_startup(void)
509 /* do the startup only unless done beforehand */
510 if (mpdm == NULL) {
511 /* alloc space */
512 if ((mpdm = malloc(sizeof(struct mpdm_control))) == NULL)
513 return -1;
515 /* cleans it */
516 memset(mpdm, '\0', sizeof(struct mpdm_control));
518 /* sets the defaults */
519 mpdm->hash_buckets = 31;
521 /* sets the locale */
522 if (setlocale(LC_ALL, "") == NULL)
523 setlocale(LC_ALL, "C");
525 mpdm_encoding(NULL);
527 /* store the MPDM() function */
528 mpdm_hset_s(mpdm_root(), L"MPDM", MPDM_X(MPDM));
530 /* store the ENV hash */
531 mpdm_hset_s(mpdm_root(), L"ENV", build_env());
534 /* everything went OK */
535 return 0;
540 * mpdm_shutdown - Shuts down MPDM.
542 * Shuts down MPDM. No MPDM functions should be used from now on.
544 void mpdm_shutdown(void)
546 /* dummy, by now */
550 * MPDM_A - Creates an array value.
551 * @n: Number of elements
553 * Creates a new array value with @n elements.
554 * [Value Creation]
556 /** mpdm_t MPDM_A(int n); */
557 /* ; */
560 * MPDM_H - Creates a hash value.
561 * @n: Number of buckets in the hash (0: use default)
563 * Creates a new hash value with @n buckets. The number
564 * of buckets must be a prime number. If @n is 0, an
565 * optimal number of buckets will be used.
566 * [Value Creation]
568 /** mpdm_t MPDM_H(int n); */
569 /* ; */
572 * MPDM_LS - Creates a string value from a literal string.
573 * @wcs: the wide character string
575 * Creates a new string value from a literal, wide character string.
576 * A pointer to the string will be stored in the value (not a copy).
577 * [Value Creation]
579 /** mpdm_t MPDM_LS(wchar_t * wcs); */
580 /* ; */
583 * MPDM_S - Creates a string value from a string.
584 * @wcs: the wide character string
586 * Creates a new string value from a wide character string. The value
587 * will store a copy of the string that will be freed on destruction.
588 * [Value Creation]
590 /** mpdm_t MPDM_S(wchar_t * wcs); */
591 /* ; */
594 * MPDM_NS - Creates a string value from a string, with size.
595 * @wcs: the wide character string
596 * @s: the size in chars the string will hold
598 * Creates a new string value with a copy of the first @s characters
599 * from the @wcs string.
600 * [Value Creation]
602 /** mpdm_t MPDM_NS(wchar_t * wcs, int s); */
603 /* ; */
606 * MPDM_ENS - Creates a string value from an external string, with size.
607 * @wcs: the external wide character string
608 * @s: the size in chars the string will hold
610 * Creates a new string value with size @s. The @wcs string must be
611 * a dynamic value (i.e. allocated by malloc()) that will be freed on
612 * destruction.
613 * [Value Creation]
615 /** mpdm_t MPDM_ENS(wchar_t * wcs, int s); */
616 /* ; */
619 * MPDM_I - Creates an integer value.
620 * @i: the integer
622 * Creates a new integer value. MPDM integers are strings.
623 * [Value Creation]
625 /** mpdm_t MPDM_I(int i); */
626 /* ; */
629 * MPDM_R - Creates a real value.
630 * @r: the real number
632 * Creates a new real value. MPDM integers are strings.
633 * [Value Creation]
635 /** mpdm_t MPDM_R(double r); */
636 /* ; */
639 * MPDM_F - Creates a file value.
640 * @f: the file descriptor
642 * Creates a new file value.
643 * [Value Creation]
645 /** mpdm_t MPDM_F(FILE * f); */
646 /* ; */
649 * MPDM_MBS - Creates a string value from a multibyte string.
650 * @mbs: the multibyte string
652 * Creates a new string value from a multibyte string, that will be
653 * converted to wcs by mpdm_mbstowcs().
654 * [Value Creation]
656 /** mpdm_t MPDM_MBS(char * mbs); */
657 /* ; */
660 * MPDM_NMBS - Creates a string value from a multibyte string, with size.
661 * @mbs: the multibyte string
662 * @s: the size
664 * Creates a new string value with the first @s characters from the @mbs
665 * multibyte string, that will be converted to wcs by mpdm_mbstowcs().
666 * [Value Creation]
668 /** mpdm_t MPDM_NMBS(char * mbs, int s); */
669 /* ; */
672 * MPDM_2MBS - Creates a multibyte string value from a wide char string.
673 * @wcs: the wide char string
675 * Creates a multibyte string value from the @wcs wide char string,
676 * converting it by mpdm_wcstombs(). Take note that multibyte string values
677 * are not properly strings, so they cannot be used for string comparison
678 * and such.
679 * [Value Creation]
681 /** mpdm_t MPDM_2MBS(wchar_t * wcs); */
682 /* ; */
685 * MPDM_X - Creates a new executable value.
686 * @func: the C code function
688 * Creates a new executable value given a pointer to the @func C code function.
689 * The function must receive an mpdm_t array value (that will hold their
690 * arguments) and return another one.
691 * [Value Creation]
693 /** mpdm_t MPDM_X(mpdm_t (* func)(mpdm_t args)); */
694 /* ; */
697 * MPDM_C - Creates a new value with a copy of a buffer.
698 * @flags: additional flags
699 * @ptr: pointer to data
700 * @size: data size
702 * Create a new value with a copy of a buffer. The value will store a copy
703 * of @ptr and have the additional @flags.
704 * [Value Creation]
706 /** mpdm_t MPDM_C(int flags, void *ptr, int size); */
707 /* ; */
710 * MPDM_IS_ARRAY - Tests if a value is an array.
711 * @v: the value
713 * Returns non-zero if @v is an array.
715 /** int MPDM_IS_ARRAY(mpdm_t v); */
716 /* ; */
719 * MPDM_IS_HASH - Tests if a value is a hash.
720 * @v: the value
722 * Returns non-zero if @v is a hash.
724 /** int MPDM_IS_HASH(mpdm_t v); */
725 /* ; */
728 * MPDM_IS_EXEC - Tests if a value is executable.
729 * @v: the value
731 * Returns non-zero if @v is executable.
733 /** int MPDM_IS_EXEC(mpdm_t v); */
734 /* ; */
737 * MPDM_IS_STRING - Tests if a value is a string.
738 * @v: the value
740 * Returns non-zero if @v is a string.
742 /** int MPDM_IS_STRING(mpdm_t v); */
743 /* ; */