Some fixes to previous indentation.
[mpdm.git] / mpdm_v.c
blobd2f40c8477609527578678c326481323c705ac05
1 /*
3 MPDM - Minimum Profit Data Manager
4 Copyright (C) 2003/2010 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 mpdm_collapse(v, 0, v->size);
52 /* free data if needed */
53 if (v->data != NULL && v->flags & MPDM_FREE) {
54 free((void *) v->data);
55 v->data = NULL;
58 mpdm->count--;
60 free(v);
64 /**
65 * mpdm_new - Creates a new value.
66 * @flags: flags
67 * @data: pointer to real data
68 * @size: size of data
70 * Creates a new value. @flags is an or-ed set of flags, @data is a
71 * pointer to the data the value will store and @size the size of these
72 * data (if value is to be a multiple one, @size is a number of elements,
73 * or a number of bytes otherwise).
75 * This function is normally not directly used; use any of the type
76 * creation macros instead.
77 * [Value Creation]
79 mpdm_t mpdm_new(int flags, const void *data, int size)
81 mpdm_t v = NULL;
83 /* alloc */
84 if ((v = malloc(sizeof(struct mpdm_val))) != NULL) {
85 /* account one value more */
86 mpdm->count++;
88 v->flags = flags;
89 v->ref = 0;
90 v->data = data;
91 v->size = size;
94 return v;
98 /**
99 * mpdm_ref - Increments the reference count of a value.
100 * @v: the value
102 * Increments the reference count of a value.
103 * [Value Management]
105 mpdm_t mpdm_ref(mpdm_t v)
107 if (v != NULL)
108 v->ref++;
110 return v;
115 * mpdm_unref - Decrements the reference count of a value.
116 * @v: the value
118 * Decrements the reference count of a value. If the reference
119 * count of the value reaches 0, it's destroyed.
120 * [Value Management]
122 mpdm_t mpdm_unref(mpdm_t v)
124 if (v != NULL) {
125 v->ref--;
127 if (v->ref <= 0) {
128 cleanup_value(v);
129 v = NULL;
133 return v;
138 * mpdm_unrefnd - Decrements the reference count of a value, without destroy.
139 * @v: the value
141 * Decrements the reference count of a value, without destroying
142 * the value if it's unreferenced.
143 * [Value Management]
145 mpdm_t mpdm_unrefnd(mpdm_t v)
147 if (v != NULL)
148 v->ref--;
150 return v;
155 * mpdm_size - Returns the size of an element.
156 * @v: the element
158 * Returns the size of an element. It does not change the
159 * reference count of the value.
160 * [Value Management]
162 int mpdm_size(const mpdm_t v)
164 int r = 0;
166 /* NULL values have no size */
167 if (v != NULL)
168 r = v->size;
170 return r;
175 * mpdm_clone - Creates a clone of a value.
176 * @v: the value
178 * Creates a clone of a value. If the value is multiple, a new value will
179 * be created containing clones of all its elements; otherwise,
180 * the same unchanged value is returned.
181 * [Value Management]
183 mpdm_t mpdm_clone(const mpdm_t v)
185 mpdm_t r;
187 mpdm_ref(v);
189 if (MPDM_IS_ARRAY(v))
190 r = mpdm_aclone(v);
191 else
192 r = v;
194 mpdm_unref(v);
196 return r;
201 * mpdm_root - Returns the root hash.
203 * Returns the root hash. This hash is stored internally and can be used
204 * as a kind of global symbol table.
205 * [Value Management]
207 mpdm_t mpdm_root(void)
209 if (mpdm->root == NULL)
210 mpdm->root = mpdm_ref(MPDM_H(0));
212 return mpdm->root;
217 * mpdm_set_ival - Sets the integer value.
218 * @v: the value
219 * @ival: the integer
221 * Sets the integer value for @v. It does not change
222 * the reference count of @v.
224 mpdm_t mpdm_set_ival(mpdm_t v, int ival)
225 /* sets an integer value to a value */
227 v->flags |= MPDM_IVAL;
228 v->ival = ival;
230 return v;
235 * mpdm_set_rval - Sets the real value.
236 * @v: the value
237 * @rval: the real
239 * Sets the real value for @v. It does not change
240 * the reference count of @v.
242 mpdm_t mpdm_set_rval(mpdm_t v, double rval)
243 /* sets a real value to a value */
245 v->flags |= MPDM_RVAL;
246 v->rval = rval;
248 return v;
253 * mpdm_void - Refs then unrefs a value.
254 * @v: the value
256 * References and unreferences a value. To be used to receive
257 * the output of mpdm_exec() in case of it being void (i.e.
258 * its return value ignored).
260 void mpdm_void(mpdm_t v)
262 mpdm_ref(v);
263 mpdm_unref(v);
268 * mpdm_is_null - Returns 1 if a value is NULL.
269 * @v: the value
271 * Returns 1 if a value is NULL. The reference count is touched.
273 int mpdm_is_null(mpdm_t v)
275 int r;
277 mpdm_ref(v);
278 r = v == NULL ? 1 : 0;
279 mpdm_unref(v);
281 return r;
286 * mpdm_exec - Executes an executable value.
287 * @c: the code value
288 * @args: the arguments
289 * @ctxt: the context
291 * Executes an executable value. If @c is a scalar value, its data
292 * should be a pointer to a directly executable C function with a
293 * prototype of mpdm_t func(mpdm_t args, mpdm_t ctxt); if it's a multiple
294 * one, the first value's data should be a pointer to a directly executable
295 * C function with a prototype of
296 * mpdm_t func(mpdm_t b, mpdm_t args, mpdm_t ctxt) and
297 * the second value will be passed as the @b argument. This value is used
298 * to store bytecode or so when implementing virtual machines or compilers.
299 * The @ctxt is meant to be used as a special context to implement local
300 * symbol tables and such. Its meaning is free and can be NULL.
302 * Returns the return value of the code. If @c is NULL or not executable,
303 * returns NULL.
304 * [Value Management]
306 mpdm_t mpdm_exec(mpdm_t c, mpdm_t args, mpdm_t ctxt)
308 mpdm_t r = NULL;
310 mpdm_ref(c);
311 mpdm_ref(args);
312 mpdm_ref(ctxt);
314 if (c != NULL && (c->flags & MPDM_EXEC)) {
316 if (c->flags & MPDM_MULTIPLE) {
317 mpdm_t x;
318 mpdm_t(*func) (mpdm_t, mpdm_t, mpdm_t);
320 /* value is multiple; first element is the
321 3 argument version of the executable function,
322 next its optional additional information,
323 the arguments and the context */
324 x = mpdm_aget(c, 0);
326 if ((func =
327 (mpdm_t(*)(mpdm_t, mpdm_t, mpdm_t)) (x->data)) != NULL)
328 r = func(mpdm_aget(c, 1), args, ctxt);
330 else {
331 mpdm_t(*func) (mpdm_t, mpdm_t);
333 /* value is scalar; c is the 2 argument
334 version of the executable function */
335 if ((func = (mpdm_t(*)(mpdm_t, mpdm_t)) (c->data)) != NULL)
336 r = func(args, ctxt);
340 mpdm_unref(ctxt);
341 mpdm_unref(args);
342 mpdm_unref(c);
344 return r;
348 mpdm_t mpdm_exec_1(mpdm_t c, mpdm_t a1, mpdm_t ctxt)
350 mpdm_t r;
351 mpdm_t a = MPDM_A(1);
353 mpdm_ref(a);
354 mpdm_aset(a, a1, 0);
356 r = mpdm_exec(c, a, ctxt);
358 mpdm_unref(a);
360 return r;
364 mpdm_t mpdm_exec_2(mpdm_t c, mpdm_t a1, mpdm_t a2, mpdm_t ctxt)
366 mpdm_t r;
367 mpdm_t a = MPDM_A(2);
369 mpdm_ref(a);
370 mpdm_aset(a, a1, 0);
371 mpdm_aset(a, a2, 1);
373 r = mpdm_exec(c, a, ctxt);
375 mpdm_unref(a);
377 return r;
381 mpdm_t mpdm_exec_3(mpdm_t c, mpdm_t a1, mpdm_t a2, mpdm_t a3, mpdm_t ctxt)
383 mpdm_t r;
384 mpdm_t a = MPDM_A(3);
386 mpdm_ref(a);
387 mpdm_aset(a, a1, 0);
388 mpdm_aset(a, a2, 1);
389 mpdm_aset(a, a3, 2);
391 r = mpdm_exec(c, a, ctxt);
393 mpdm_unref(a);
395 return r;
399 mpdm_t mpdm_xnew(mpdm_t(*a1) (mpdm_t, mpdm_t, mpdm_t), mpdm_t a2)
401 mpdm_t x;
403 x = MPDM_A(2);
404 x->flags |= MPDM_EXEC;
406 mpdm_ref(x);
408 mpdm_aset(x, MPDM_X(a1), 0);
409 mpdm_aset(x, a2, 1);
411 mpdm_unrefnd(x);
413 return x;
417 mpdm_t mpdm_new_copy(int flags, void *ptr, int size)
419 mpdm_t r = NULL;
421 if (ptr != NULL) {
422 char *ptr2 = malloc(size);
423 memcpy(ptr2, ptr, size);
425 r = mpdm_new(MPDM_FREE | flags, ptr2, size);
428 return r;
432 static mpdm_t MPDM(const mpdm_t args, mpdm_t ctxt)
433 /* accesor / mutator for MPDM internal data */
435 mpdm_t v;
437 mpdm_ref(args);
439 v = mpdm_aget(args, 0);
441 if (v != NULL) {
442 mpdm_t w;
444 /* do changes */
445 if ((w = mpdm_hget_s(v, L"hash_buckets")) != NULL)
446 mpdm->hash_buckets = mpdm_ival(w);
449 /* now collect all information */
450 v = MPDM_H(0);
452 mpdm_ref(v);
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"hash_buckets", MPDM_I(mpdm->hash_buckets));
457 mpdm_hset_s(v, L"destroy_on_unref", MPDM_I(1));
459 mpdm_unref(args);
461 mpdm_unrefnd(v);
463 return v;
466 extern char **environ;
468 static mpdm_t build_env(void)
469 /* builds a hash with the environment */
471 char **ptr;
472 mpdm_t e = MPDM_H(0);
474 mpdm_ref(e);
476 for (ptr = environ; *ptr != NULL; ptr++) {
477 char *eq = strchr(*ptr, '=');
479 if (eq != NULL) {
480 mpdm_t k, v;
482 k = MPDM_NMBS((*ptr), eq - (*ptr));
483 v = MPDM_MBS(eq + 1);
485 mpdm_hset(e, k, v);
489 mpdm_unrefnd(e);
491 return e;
496 * mpdm_startup - Initializes MPDM.
498 * Initializes the Minimum Profit Data Manager. Returns 0 if
499 * everything went OK.
501 int mpdm_startup(void)
503 /* do the startup only unless done beforehand */
504 if (mpdm == NULL) {
505 /* alloc space */
506 if ((mpdm = malloc(sizeof(struct mpdm_control))) == NULL)
507 return -1;
509 /* cleans it */
510 memset(mpdm, '\0', sizeof(struct mpdm_control));
512 /* sets the defaults */
513 mpdm->hash_buckets = 31;
515 /* sets the locale */
516 if (setlocale(LC_ALL, "") == NULL)
517 setlocale(LC_ALL, "C");
519 mpdm_encoding(NULL);
521 /* store the MPDM() function */
522 mpdm_hset_s(mpdm_root(), L"MPDM", MPDM_X(MPDM));
524 /* store the ENV hash */
525 mpdm_hset_s(mpdm_root(), L"ENV", build_env());
528 /* everything went OK */
529 return 0;
534 * mpdm_shutdown - Shuts down MPDM.
536 * Shuts down MPDM. No MPDM functions should be used from now on.
538 void mpdm_shutdown(void)
540 /* dummy, by now */
544 * MPDM_A - Creates an array value.
545 * @n: Number of elements
547 * Creates a new array value with @n elements.
548 * [Value Creation]
550 /** mpdm_t MPDM_A(int n); */
551 /* ; */
554 * MPDM_H - Creates a hash value.
555 * @n: Number of buckets in the hash (0: use default)
557 * Creates a new hash value with @n buckets. The number
558 * of buckets must be a prime number. If @n is 0, an
559 * optimal number of buckets will be used.
560 * [Value Creation]
562 /** mpdm_t MPDM_H(int n); */
563 /* ; */
566 * MPDM_LS - Creates a string value from a literal string.
567 * @wcs: the wide character string
569 * Creates a new string value from a literal, wide character string.
570 * A pointer to the string will be stored in the value (not a copy).
571 * [Value Creation]
573 /** mpdm_t MPDM_LS(wchar_t * wcs); */
574 /* ; */
577 * MPDM_S - Creates a string value from a string.
578 * @wcs: the wide character string
580 * Creates a new string value from a wide character string. The value
581 * will store a copy of the string that will be freed on destruction.
582 * [Value Creation]
584 /** mpdm_t MPDM_S(wchar_t * wcs); */
585 /* ; */
588 * MPDM_NS - Creates a string value from a string, with size.
589 * @wcs: the wide character string
590 * @s: the size in chars the string will hold
592 * Creates a new string value with a copy of the first @s characters
593 * from the @wcs string.
594 * [Value Creation]
596 /** mpdm_t MPDM_NS(wchar_t * wcs, int s); */
597 /* ; */
600 * MPDM_ENS - Creates a string value from an external string, with size.
601 * @wcs: the external wide character string
602 * @s: the size in chars the string will hold
604 * Creates a new string value with size @s. The @wcs string must be
605 * a dynamic value (i.e. allocated by malloc()) that will be freed on
606 * destruction.
607 * [Value Creation]
609 /** mpdm_t MPDM_ENS(wchar_t * wcs, int s); */
610 /* ; */
613 * MPDM_I - Creates an integer value.
614 * @i: the integer
616 * Creates a new integer value. MPDM integers are strings.
617 * [Value Creation]
619 /** mpdm_t MPDM_I(int i); */
620 /* ; */
623 * MPDM_R - Creates a real value.
624 * @r: the real number
626 * Creates a new real value. MPDM integers are strings.
627 * [Value Creation]
629 /** mpdm_t MPDM_R(double r); */
630 /* ; */
633 * MPDM_F - Creates a file value.
634 * @f: the file descriptor
636 * Creates a new file value.
637 * [Value Creation]
639 /** mpdm_t MPDM_F(FILE * f); */
640 /* ; */
643 * MPDM_MBS - Creates a string value from a multibyte string.
644 * @mbs: the multibyte string
646 * Creates a new string value from a multibyte string, that will be
647 * converted to wcs by mpdm_mbstowcs().
648 * [Value Creation]
650 /** mpdm_t MPDM_MBS(char * mbs); */
651 /* ; */
654 * MPDM_NMBS - Creates a string value from a multibyte string, with size.
655 * @mbs: the multibyte string
656 * @s: the size
658 * Creates a new string value with the first @s characters from the @mbs
659 * multibyte string, that will be converted to wcs by mpdm_mbstowcs().
660 * [Value Creation]
662 /** mpdm_t MPDM_NMBS(char * mbs, int s); */
663 /* ; */
666 * MPDM_2MBS - Creates a multibyte string value from a wide char string.
667 * @wcs: the wide char string
669 * Creates a multibyte string value from the @wcs wide char string,
670 * converting it by mpdm_wcstombs(). Take note that multibyte string values
671 * are not properly strings, so they cannot be used for string comparison
672 * and such.
673 * [Value Creation]
675 /** mpdm_t MPDM_2MBS(wchar_t * wcs); */
676 /* ; */
679 * MPDM_X - Creates a new executable value.
680 * @func: the C code function
682 * Creates a new executable value given a pointer to the @func C code function.
683 * The function must receive an mpdm_t array value (that will hold their
684 * arguments) and return another one.
685 * [Value Creation]
687 /** mpdm_t MPDM_X(mpdm_t (* func)(mpdm_t args)); */
688 /* ; */
691 * MPDM_C - Creates a new value with a copy of a buffer.
692 * @flags: additional flags
693 * @ptr: pointer to data
694 * @size: data size
696 * Create a new value with a copy of a buffer. The value will store a copy
697 * of @ptr and have the additional @flags.
698 * [Value Creation]
700 /** mpdm_t MPDM_C(int flags, void *ptr, int size); */
701 /* ; */
704 * MPDM_IS_ARRAY - Tests if a value is an array.
705 * @v: the value
707 * Returns non-zero if @v is an array.
709 /** int MPDM_IS_ARRAY(mpdm_t v); */
710 /* ; */
713 * MPDM_IS_HASH - Tests if a value is a hash.
714 * @v: the value
716 * Returns non-zero if @v is a hash.
718 /** int MPDM_IS_HASH(mpdm_t v); */
719 /* ; */
722 * MPDM_IS_EXEC - Tests if a value is executable.
723 * @v: the value
725 * Returns non-zero if @v is executable.
727 /** int MPDM_IS_EXEC(mpdm_t v); */
728 /* ; */
731 * MPDM_IS_STRING - Tests if a value is a string.
732 * @v: the value
734 * Returns non-zero if @v is a string.
736 /** int MPDM_IS_STRING(mpdm_t v); */
737 /* ; */