Updated TODO.
[mpdm.git] / mpdm_v.c
blob183e8f2dca2b4c74cf7737dac4390722afb3faef
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 if (!(v->flags & MPDM_NONDYN))
65 free(v);
69 static void destroy_value(mpdm_t v)
70 /* destroys a value */
72 cleanup_value(v);
76 /**
77 * mpdm_init - Initializes a value.
78 * @v: the value to initialize
79 * @flags: flags
80 * @data: pointer to real data
81 * @size: size of data
83 * Initializes a value.
85 * This function is normally not directly used; use any of the type
86 * creation macros instead.
87 * [Value Creation]
89 mpdm_t mpdm_init(mpdm_t v, int flags, const void *data, int size)
91 /* if v is NULL crash JUST NOW */
92 v->flags = flags;
93 v->ref = 0;
94 v->data = data;
95 v->size = size;
97 mpdm->count++;
99 return v;
104 * mpdm_new - Creates a new value.
105 * @flags: flags
106 * @data: pointer to real data
107 * @size: size of data
109 * Creates a new value. @flags is an or-ed set of flags, @data is a
110 * pointer to the data the value will store and @size the size of these
111 * data (if value is to be a multiple one, @size is a number of elements,
112 * or a number of bytes otherwise).
114 * This function is normally not directly used; use any of the type
115 * creation macros instead.
116 * [Value Creation]
118 mpdm_t mpdm_new(int flags, const void *data, int size)
120 return mpdm_init(malloc(sizeof(struct mpdm_val)),
121 flags & ~MPDM_NONDYN, data, size);
126 * mpdm_ref - Increments the reference count of a value.
127 * @v: the value
129 * Increments the reference count of a value.
130 * [Value Management]
132 mpdm_t mpdm_ref(mpdm_t v)
134 if (v != NULL)
135 v->ref++;
137 return v;
142 * mpdm_unref - Decrements the reference count of a value.
143 * @v: the value
145 * Decrements the reference count of a value. If the reference
146 * count of the value reaches 0, it's destroyed.
147 * [Value Management]
149 mpdm_t mpdm_unref(mpdm_t v)
151 if (v != NULL) {
152 v->ref--;
154 if (v->ref <= 0) {
155 destroy_value(v);
156 v = NULL;
160 return v;
165 * mpdm_unrefnd - Decrements the reference count of a value, without destroy.
166 * @v: the value
168 * Decrements the reference count of a value, without destroying
169 * the value if it's unreferenced.
170 * [Value Management]
172 mpdm_t mpdm_unrefnd(mpdm_t v)
174 if (v != NULL)
175 v->ref--;
177 return v;
182 * mpdm_size - Returns the size of an element.
183 * @v: the element
185 * Returns the size of an element. It does not change the
186 * reference count of the value.
187 * [Value Management]
189 int mpdm_size(const mpdm_t v)
191 int r = 0;
193 /* NULL values have no size */
194 if (v != NULL)
195 r = v->size;
197 return r;
202 * mpdm_clone - Creates a clone of a value.
203 * @v: the value
205 * Creates a clone of a value. If the value is multiple, a new value will
206 * be created containing clones of all its elements; otherwise,
207 * the same unchanged value is returned.
208 * [Value Management]
210 mpdm_t mpdm_clone(const mpdm_t v)
212 mpdm_t r;
214 if (MPDM_IS_ARRAY(v) && !MPDM_IS_EXEC(v))
215 r = mpdm_aclone(v);
216 else
217 r = v;
219 return r;
224 * mpdm_root - Returns the root hash.
226 * Returns the root hash. This hash is stored internally and can be used
227 * as a kind of global symbol table.
228 * [Value Management]
230 mpdm_t mpdm_root(void)
232 if (mpdm->root == NULL)
233 mpdm->root = mpdm_ref(MPDM_H(0));
235 return mpdm->root;
240 * mpdm_set_ival - Sets the integer value.
241 * @v: the value
242 * @ival: the integer
244 * Sets the integer value for @v. It does not change
245 * the reference count of @v.
247 mpdm_t mpdm_set_ival(mpdm_t v, int ival)
248 /* sets an integer value to a value */
250 v->flags |= MPDM_IVAL;
251 v->ival = ival;
253 return v;
258 * mpdm_set_rval - Sets the real value.
259 * @v: the value
260 * @rval: the real
262 * Sets the real value for @v. It does not change
263 * the reference count of @v.
265 mpdm_t mpdm_set_rval(mpdm_t v, double rval)
266 /* sets a real value to a value */
268 v->flags |= MPDM_RVAL;
269 v->rval = rval;
271 return v;
276 * mpdm_void - Refs then unrefs a value.
277 * @v: the value
279 * References and unreferences a value. To be used to receive
280 * the output of mpdm_exec() in case of it being void (i.e.
281 * its return value ignored).
283 void mpdm_void(mpdm_t v)
285 mpdm_ref(v);
286 mpdm_unref(v);
291 * mpdm_is_null - Returns 1 if a value is NULL.
292 * @v: the value
294 * Returns 1 if a value is NULL. The reference count is touched.
296 int mpdm_is_null(mpdm_t v)
298 int r;
300 mpdm_ref(v);
301 r = v == NULL ? 1 : 0;
302 mpdm_unref(v);
304 return r;
309 * mpdm_exec - Executes an executable value.
310 * @c: the code value
311 * @args: the arguments
312 * @ctxt: the context
314 * Executes an executable value. If @c is a scalar value, its data
315 * should be a pointer to a directly executable C function with a
316 * prototype of mpdm_t func(mpdm_t args, mpdm_t ctxt); if it's a multiple
317 * one, the first value's data should be a pointer to a directly executable
318 * C function with a prototype of
319 * mpdm_t func(mpdm_t b, mpdm_t args, mpdm_t ctxt) and
320 * the second value will be passed as the @b argument. This value is used
321 * to store bytecode or so when implementing virtual machines or compilers.
322 * The @ctxt is meant to be used as a special context to implement local
323 * symbol tables and such. Its meaning is free and can be NULL.
325 * Returns the return value of the code. If @c is NULL or not executable,
326 * returns NULL.
327 * [Value Management]
329 mpdm_t mpdm_exec(mpdm_t c, mpdm_t args, mpdm_t ctxt)
331 mpdm_t r = NULL;
333 mpdm_ref(c);
334 mpdm_ref(args);
335 mpdm_ref(ctxt);
337 if (c != NULL && (c->flags & MPDM_EXEC)) {
339 if (c->flags & MPDM_MULTIPLE) {
340 mpdm_t x;
341 mpdm_t(*func) (mpdm_t, mpdm_t, mpdm_t);
343 /* value is multiple; first element is the
344 3 argument version of the executable function,
345 next its optional additional information,
346 the arguments and the context */
347 x = mpdm_aget(c, 0);
349 if ((func =
350 (mpdm_t(*)(mpdm_t, mpdm_t, mpdm_t)) (x->data)) != NULL)
351 r = func(mpdm_aget(c, 1), args, ctxt);
353 else {
354 mpdm_t(*func) (mpdm_t, mpdm_t);
356 /* value is scalar; c is the 2 argument
357 version of the executable function */
358 if ((func = (mpdm_t(*)(mpdm_t, mpdm_t)) (c->data)) != NULL)
359 r = func(args, ctxt);
363 mpdm_unref(ctxt);
364 mpdm_unref(args);
365 mpdm_unref(c);
367 return r;
371 mpdm_t mpdm_exec_1(mpdm_t c, mpdm_t a1, mpdm_t ctxt)
373 mpdm_t r;
374 mpdm_t a = MPDM_AA(1);
376 mpdm_ref(a);
377 mpdm_aset(a, a1, 0);
379 r = mpdm_exec(c, a, ctxt);
381 mpdm_unref(a);
383 return r;
387 mpdm_t mpdm_exec_2(mpdm_t c, mpdm_t a1, mpdm_t a2, mpdm_t ctxt)
389 mpdm_t r;
390 mpdm_t a = MPDM_AA(2);
392 mpdm_ref(a);
393 mpdm_aset(a, a1, 0);
394 mpdm_aset(a, a2, 1);
396 r = mpdm_exec(c, a, ctxt);
398 mpdm_unref(a);
400 return r;
404 mpdm_t mpdm_exec_3(mpdm_t c, mpdm_t a1, mpdm_t a2, mpdm_t a3, mpdm_t ctxt)
406 mpdm_t r;
407 mpdm_t a = MPDM_AA(3);
409 mpdm_ref(a);
410 mpdm_aset(a, a1, 0);
411 mpdm_aset(a, a2, 1);
412 mpdm_aset(a, a3, 2);
414 r = mpdm_exec(c, a, ctxt);
416 mpdm_unref(a);
418 return r;
422 mpdm_t mpdm_xnew(mpdm_t(*a1) (mpdm_t, mpdm_t, mpdm_t), mpdm_t a2)
424 mpdm_t x;
426 x = MPDM_A(2);
427 x->flags |= MPDM_EXEC;
429 mpdm_ref(x);
431 mpdm_aset(x, MPDM_X(a1), 0);
432 mpdm_aset(x, a2, 1);
434 mpdm_unrefnd(x);
436 return x;
440 mpdm_t mpdm_new_copy(int flags, void *ptr, int size)
442 mpdm_t r = NULL;
444 if (ptr != NULL) {
445 char *ptr2 = malloc(size);
446 memcpy(ptr2, ptr, size);
448 r = mpdm_new(MPDM_FREE | flags, ptr2, size);
451 return r;
455 static mpdm_t MPDM(const mpdm_t args, mpdm_t ctxt)
456 /* accesor / mutator for MPDM internal data */
458 mpdm_t v;
460 mpdm_ref(args);
462 v = mpdm_aget(args, 0);
464 if (v != NULL) {
465 mpdm_t w;
467 /* do changes */
468 if ((w = mpdm_hget_s(v, L"hash_buckets")) != NULL)
469 mpdm->hash_buckets = mpdm_ival(w);
472 /* now collect all information */
473 v = MPDM_H(0);
475 mpdm_ref(v);
477 mpdm_hset_s(v, L"version", MPDM_MBS(VERSION));
478 mpdm_hset_s(v, L"count", MPDM_I(mpdm->count));
479 mpdm_hset_s(v, L"hash_buckets", MPDM_I(mpdm->hash_buckets));
481 mpdm_unref(args);
483 mpdm_unrefnd(v);
485 return v;
488 extern char **environ;
490 static mpdm_t build_env(void)
491 /* builds a hash with the environment */
493 char **ptr;
494 mpdm_t e = MPDM_H(0);
496 mpdm_ref(e);
498 for (ptr = environ; *ptr != NULL; ptr++) {
499 char *eq = strchr(*ptr, '=');
501 if (eq != NULL) {
502 mpdm_t k, v;
504 k = MPDM_NMBS((*ptr), eq - (*ptr));
505 v = MPDM_MBS(eq + 1);
507 mpdm_hset(e, k, v);
511 mpdm_unrefnd(e);
513 return e;
518 * mpdm_startup - Initializes MPDM.
520 * Initializes the Minimum Profit Data Manager. Returns 0 if
521 * everything went OK.
523 int mpdm_startup(void)
525 /* do the startup only unless done beforehand */
526 if (mpdm == NULL) {
527 /* alloc space */
528 if ((mpdm = malloc(sizeof(struct mpdm_control))) == NULL)
529 return -1;
531 /* cleans it */
532 memset(mpdm, '\0', sizeof(struct mpdm_control));
534 /* sets the defaults */
535 mpdm->hash_buckets = 31;
537 /* sets the locale */
538 if (setlocale(LC_ALL, "") == NULL)
539 setlocale(LC_ALL, "C");
541 mpdm_encoding(NULL);
543 /* store the MPDM() function */
544 mpdm_hset_s(mpdm_root(), L"MPDM", MPDM_X(MPDM));
546 /* store the ENV hash */
547 mpdm_hset_s(mpdm_root(), L"ENV", build_env());
550 /* everything went OK */
551 return 0;
556 * mpdm_shutdown - Shuts down MPDM.
558 * Shuts down MPDM. No MPDM functions should be used from now on.
560 void mpdm_shutdown(void)
562 /* dummy, by now */
566 * MPDM_A - Creates an array value.
567 * @n: Number of elements
569 * Creates a new array value with @n elements.
570 * [Value Creation]
572 /** mpdm_t MPDM_A(int n); */
573 /* ; */
576 * MPDM_AA - Creates an array value (using alloca()).
577 * @n: Number of elements
579 * Creates a new array value with @n elements on the local
580 * function's stack. These values are destroyed when the
581 * function exits. They should only be used for temporary
582 * issues.
583 * [Value Creation]
585 /** mpdm_t MPDM_AA(int n); */
586 /* ; */
589 * MPDM_H - Creates a hash value.
590 * @n: Number of buckets in the hash (0: use default)
592 * Creates a new hash value with @n buckets. The number
593 * of buckets must be a prime number. If @n is 0, an
594 * optimal number of buckets will be used.
595 * [Value Creation]
597 /** mpdm_t MPDM_H(int n); */
598 /* ; */
601 * MPDM_LS - Creates a string value from a literal string.
602 * @wcs: the wide character string
604 * Creates a new string value from a literal, wide character string.
605 * A pointer to the string will be stored in the value (not a copy).
606 * [Value Creation]
608 /** mpdm_t MPDM_LS(wchar_t * wcs); */
609 /* ; */
612 * MPDM_AS - Creates a string value from a literal string using alloca().
613 * @wcs: the wide character string
615 * Creates a new string value from a literal, wide character string.
616 * A pointer to the string will be stored in the value (not a copy).
617 * These values are destroyed when the function exits. They should
618 * only be used for temporary issues and cannot be assigned to arrays
619 * nor hashes.
620 * [Value Creation]
622 /** mpdm_t MPDM_AS(wchar_t * wcs); */
623 /* ; */
626 * MPDM_S - Creates a string value from a string.
627 * @wcs: the wide character string
629 * Creates a new string value from a wide character string. The value
630 * will store a copy of the string that will be freed on destruction.
631 * [Value Creation]
633 /** mpdm_t MPDM_S(wchar_t * wcs); */
634 /* ; */
637 * MPDM_NS - Creates a string value from a string, with size.
638 * @wcs: the wide character string
639 * @s: the size in chars the string will hold
641 * Creates a new string value with a copy of the first @s characters
642 * from the @wcs string.
643 * [Value Creation]
645 /** mpdm_t MPDM_NS(wchar_t * wcs, int s); */
646 /* ; */
649 * MPDM_ENS - Creates a string value from an external string, with size.
650 * @wcs: the external wide character string
651 * @s: the size in chars the string will hold
653 * Creates a new string value with size @s. The @wcs string must be
654 * a dynamic value (i.e. allocated by malloc()) that will be freed on
655 * destruction.
656 * [Value Creation]
658 /** mpdm_t MPDM_ENS(wchar_t * wcs, int s); */
659 /* ; */
662 * MPDM_I - Creates an integer value.
663 * @i: the integer
665 * Creates a new integer value. MPDM integers are strings.
666 * [Value Creation]
668 /** mpdm_t MPDM_I(int i); */
669 /* ; */
672 * MPDM_R - Creates a real value.
673 * @r: the real number
675 * Creates a new real value. MPDM integers are strings.
676 * [Value Creation]
678 /** mpdm_t MPDM_R(double r); */
679 /* ; */
682 * MPDM_F - Creates a file value.
683 * @f: the file descriptor
685 * Creates a new file value.
686 * [Value Creation]
688 /** mpdm_t MPDM_F(FILE * f); */
689 /* ; */
692 * MPDM_MBS - Creates a string value from a multibyte string.
693 * @mbs: the multibyte string
695 * Creates a new string value from a multibyte string, that will be
696 * converted to wcs by mpdm_mbstowcs().
697 * [Value Creation]
699 /** mpdm_t MPDM_MBS(char * mbs); */
700 /* ; */
703 * MPDM_NMBS - Creates a string value from a multibyte string, with size.
704 * @mbs: the multibyte string
705 * @s: the size
707 * Creates a new string value with the first @s characters from the @mbs
708 * multibyte string, that will be converted to wcs by mpdm_mbstowcs().
709 * [Value Creation]
711 /** mpdm_t MPDM_NMBS(char * mbs, int s); */
712 /* ; */
715 * MPDM_2MBS - Creates a multibyte string value from a wide char string.
716 * @wcs: the wide char string
718 * Creates a multibyte string value from the @wcs wide char string,
719 * converting it by mpdm_wcstombs(). Take note that multibyte string values
720 * are not properly strings, so they cannot be used for string comparison
721 * and such.
722 * [Value Creation]
724 /** mpdm_t MPDM_2MBS(wchar_t * wcs); */
725 /* ; */
728 * MPDM_X - Creates a new executable value.
729 * @func: the C code function
731 * Creates a new executable value given a pointer to the @func C code function.
732 * The function must receive an mpdm_t array value (that will hold their
733 * arguments) and return another one.
734 * [Value Creation]
736 /** mpdm_t MPDM_X(mpdm_t (* func)(mpdm_t args)); */
737 /* ; */
740 * MPDM_C - Creates a new value with a copy of a buffer.
741 * @flags: additional flags
742 * @ptr: pointer to data
743 * @size: data size
745 * Create a new value with a copy of a buffer. The value will store a copy
746 * of @ptr and have the additional @flags.
747 * [Value Creation]
749 /** mpdm_t MPDM_C(int flags, void *ptr, int size); */
750 /* ; */
753 * MPDM_IS_ARRAY - Tests if a value is an array.
754 * @v: the value
756 * Returns non-zero if @v is an array.
758 /** int MPDM_IS_ARRAY(mpdm_t v); */
759 /* ; */
762 * MPDM_IS_HASH - Tests if a value is a hash.
763 * @v: the value
765 * Returns non-zero if @v is a hash.
767 /** int MPDM_IS_HASH(mpdm_t v); */
768 /* ; */
771 * MPDM_IS_EXEC - Tests if a value is executable.
772 * @v: the value
774 * Returns non-zero if @v is executable.
776 /** int MPDM_IS_EXEC(mpdm_t v); */
777 /* ; */
780 * MPDM_IS_STRING - Tests if a value is a string.
781 * @v: the value
783 * Returns non-zero if @v is a string.
785 /** int MPDM_IS_STRING(mpdm_t v); */
786 /* ; */