Avoid using yet another buffer.
[mpdm.git] / mpdm_v.c
bloba256c53a6db223ed067417ab173494fa26e81ddf
1 /*
3 MPDM - Minimum Profit Data Manager
4 Copyright (C) 2003/2007 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"
35 /*******************
36 Data
37 ********************/
39 /* control structure */
41 struct mpdm_control *mpdm = NULL;
43 /*******************
44 Code
45 ********************/
47 static void cleanup_value(mpdm_t v)
48 /* cleans a value */
50 /* collapse multiple values */
51 if (v->flags & MPDM_MULTIPLE)
52 mpdm_collapse(v, 0, v->size);
54 /* free data if needed */
55 if (v->data != NULL && v->flags & MPDM_FREE) {
56 mpdm->memory_usage -= v->size;
57 free((void *)v->data);
58 v->data = NULL;
63 int mpdm_destroy(mpdm_t v)
64 /* destroys a value */
66 /* if still referenced or deleted, do nothing */
67 if (v->ref || v->flags & MPDM_DELETED)
68 return 0;
70 /* dequeue */
71 v->next->prev = v->prev;
72 v->prev->next = v->next;
74 /* if it's the current one, move to next */
75 if (mpdm->cur == v)
76 mpdm->cur = v->next;
78 /* account one value less */
79 mpdm->count--;
81 /* add to the deleted values queue */
82 v->next = mpdm->del;
83 mpdm->del = v;
85 cleanup_value(v);
87 /* mark as deleted */
88 v->flags |= MPDM_DELETED;
90 return 1;
94 /**
95 * mpdm_new - Creates a new value.
96 * @flags: flags
97 * @data: pointer to real data
98 * @size: size of data
100 * Creates a new value. @flags is an or-ed set of flags, @data is a
101 * pointer to the data the value will store and @size the size of these
102 * data (if value is to be a multiple one, @size is a number of elements,
103 * or a number of bytes otherwise).
105 * This function is normally not directly used; use any of the type
106 * creation macros instead.
107 * [Value Creation]
109 mpdm_t mpdm_new(int flags, const void *data, int size)
111 mpdm_t v = NULL;
113 /* alloc */
114 if ((v = mpdm->del) != NULL)
115 mpdm->del = v->next;
116 else
117 if ((v = malloc(sizeof(struct mpdm_val))) == NULL)
118 return NULL;
120 /* add to the circular list */
121 if (mpdm->cur == NULL)
122 v->next = v->prev = v;
123 else {
124 v->prev = mpdm->cur;
125 v->next = mpdm->cur->next;
127 v->prev->next = v->next->prev = v;
130 mpdm->cur = v->next;
132 /* account one value more */
133 mpdm->count++;
135 /* count memory if data is dynamic */
136 if (flags & MPDM_FREE)
137 mpdm->memory_usage += size;
139 v->flags = flags;
140 v->ref = 0;
141 v->data = data;
142 v->size = size;
144 return v;
149 * mpdm_ref - Increments the reference count of a value.
150 * @v: the value
152 * Increments the reference count of a value.
153 * [Value Management]
155 mpdm_t mpdm_ref(mpdm_t v)
157 if (v != NULL)
158 v->ref++;
159 return v;
164 * mpdm_unref - Decrements the reference count of a value.
165 * @v: the value
167 * Decrements the reference count of a value.
168 * [Value Management]
170 mpdm_t mpdm_unref(mpdm_t v)
172 if (v != NULL)
173 v->ref--;
174 return v;
179 * mpdm_sweep - Sweeps unreferenced values.
180 * @count: number of values to be swept
182 * Destroys values with a reference count of 0. @count is the
183 * number of values to be checked for deletion; special values of
184 * @count are -1, that forces a check of all currently known values
185 * (can be time-consuming) and 0, which tells mpdm_sweep() to check a
186 * small group of them on each call.
187 * [Value Management]
189 void mpdm_sweep(int count)
191 /* if count is zero, sweep 'some' values */
192 if (count == 0) {
193 if (mpdm->default_sweep < 0)
194 count = mpdm->count / -mpdm->default_sweep;
195 else
196 count = mpdm->default_sweep;
199 /* if count is -1, sweep all */
200 if (count == -1)
201 count = mpdm->count;
203 for (; count > 0 && mpdm->count > mpdm->low_threshold; count--) {
204 /* destroy it or skip it */
205 if (!mpdm_destroy(mpdm->cur))
206 mpdm->cur = mpdm->cur->next;
212 * mpdm_size - Returns the size of an element.
213 * @v: the element
215 * Returns the size of an element.
216 * [Value Management]
218 int mpdm_size(const mpdm_t v)
220 /* NULL values have no size */
221 if (v == NULL)
222 return 0;
224 return v->size;
229 * mpdm_clone - Creates a clone of a value.
230 * @v: the value
232 * Creates a clone of a value. If the value is multiple, a new value will
233 * be created containing clones of all its elements; otherwise,
234 * the same unchanged value is returned.
235 * [Value Management]
237 mpdm_t mpdm_clone(const mpdm_t v)
239 if (MPDM_IS_ARRAY(v))
240 return mpdm_aclone(v);
242 return v;
247 * mpdm_root - Returns the root hash.
249 * Returns the root hash. This hash is stored internally and can be used
250 * as a kind of global symbol table.
251 * [Value Management]
253 mpdm_t mpdm_root(void)
255 if (mpdm->root == NULL)
256 mpdm->root = mpdm_ref(MPDM_H(0));
258 return mpdm->root;
262 mpdm_t mpdm_set_ival(mpdm_t v, int ival)
263 /* sets an integer value to a value */
265 v->flags |= MPDM_IVAL;
266 v->ival = ival;
268 return v;
272 mpdm_t mpdm_set_rval(mpdm_t v, double rval)
273 /* sets a real value to a value */
275 v->flags |= MPDM_RVAL;
276 v->rval = rval;
278 return v;
283 * mpdm_exec - Executes an executable value.
284 * @c: the code value
285 * @args: the arguments
287 * Executes an executable value. If @c is a scalar value, its data
288 * should be a pointer to a directly executable C function with a
289 * prototype of mpdm_t func(mpdm_t args); if it's a multiple one,
290 * the first value's data should be a pointer to a directly executable C
291 * function with a prototype of mpdm_t func(mpdm_t b, mpdm_t args) and
292 * the second value will be passed as the @b argument. This value is used
293 * to store bytecode or so when implementing virtual machines or compilers.
295 * Returns the return value of the code. If @c is NULL or not executable,
296 * returns NULL.
297 * [Value Management]
299 mpdm_t mpdm_exec(mpdm_t c, mpdm_t args)
301 mpdm_t r = NULL;
303 if (c != NULL && (c->flags & MPDM_EXEC)) {
304 mpdm_ref(c);
305 mpdm_ref(args);
307 if (c->flags & MPDM_MULTIPLE) {
308 mpdm_t x;
309 mpdm_t(*func) (mpdm_t, mpdm_t);
311 /* value is multiple; first element is the
312 2 argument version of the executable function,
313 next its optional additional information and
314 finally the arguments */
315 x = mpdm_aget(c, 0);
317 if ((func = (mpdm_t(*)(mpdm_t, mpdm_t)) (x->data)) != NULL)
318 r = func(mpdm_aget(c, 1), args);
320 else {
321 mpdm_t(*func) (mpdm_t);
323 /* value is scalar; c is the 1 argument
324 version of the executable function */
325 if ((func = (mpdm_t(*)(mpdm_t)) (c->data)) != NULL)
326 r = func(args);
329 mpdm_unref(args);
330 mpdm_unref(c);
333 return r;
337 mpdm_t mpdm_exec_1(mpdm_t c, mpdm_t a1)
339 mpdm_t r;
340 mpdm_t a = MPDM_A(1);
342 mpdm_aset(a, a1, 0);
343 r = mpdm_exec(c, a);
344 mpdm_destroy(a);
345 return r;
349 mpdm_t mpdm_exec_2(mpdm_t c, mpdm_t a1, mpdm_t a2)
351 mpdm_t r;
352 mpdm_t a = MPDM_A(2);
354 mpdm_aset(a, a1, 0);
355 mpdm_aset(a, a2, 1);
356 r = mpdm_exec(c, a);
357 mpdm_destroy(a);
358 return r;
362 mpdm_t mpdm_exec_3(mpdm_t c, mpdm_t a1, mpdm_t a2, mpdm_t a3)
364 mpdm_t r;
365 mpdm_t a = MPDM_A(3);
367 mpdm_aset(a, a1, 0);
368 mpdm_aset(a, a2, 1);
369 mpdm_aset(a, a3, 2);
370 r = mpdm_exec(c, a);
371 mpdm_destroy(a);
372 return r;
376 mpdm_t mpdm_xnew(mpdm_t(*a1) (mpdm_t, mpdm_t), mpdm_t a2)
378 mpdm_t x;
380 x = MPDM_A(2);
381 x->flags |= MPDM_EXEC;
383 mpdm_aset(x, MPDM_X(a1), 0);
384 mpdm_aset(x, a2, 1);
386 return x;
390 static mpdm_t MPDM(const mpdm_t args)
391 /* accesor / mutator for MPDM internal data */
393 mpdm_t v = mpdm_aget(args, 0);
394 int n, c = 0;
396 if (v != NULL) {
397 mpdm_t w;
399 /* do changes */
400 if ((w = mpdm_hget_s(v, L"low_threshold")) != NULL && mpdm_ival(w) > 0)
401 mpdm->low_threshold = mpdm_ival(w);
403 if ((w = mpdm_hget_s(v, L"default_sweep")) != NULL)
404 mpdm->default_sweep = mpdm_ival(w);
406 if ((w = mpdm_hget_s(v, L"hash_buckets")) != NULL)
407 mpdm->hash_buckets = mpdm_ival(w);
410 /* loop all values counting the references ones */
411 for (n = mpdm->count, v = mpdm->cur; n > 0; n--, v = v->next)
412 if (v->ref == 0)
413 c++;
415 /* now collect all information */
416 v = MPDM_H(0);
418 mpdm_hset_s(v, L"version", MPDM_MBS(VERSION));
419 mpdm_hset_s(v, L"count", MPDM_I(mpdm->count));
420 mpdm_hset_s(v, L"low_threshold", MPDM_I(mpdm->low_threshold));
421 mpdm_hset_s(v, L"default_sweep", MPDM_I(mpdm->default_sweep));
422 mpdm_hset_s(v, L"memory_usage", MPDM_I(mpdm->memory_usage));
423 mpdm_hset_s(v, L"hash_buckets", MPDM_I(mpdm->hash_buckets));
424 mpdm_hset_s(v, L"unreferenced", MPDM_I(c));
426 return v;
429 extern char **environ;
431 static mpdm_t build_env(void)
432 /* builds a hash with the environment */
434 char **ptr;
435 mpdm_t e = MPDM_H(0);
437 for (ptr = environ; *ptr != NULL; ptr++) {
438 char *eq = strchr(*ptr, '=');
440 if (eq != NULL) {
441 mpdm_t k, v;
443 k = MPDM_NMBS((*ptr), eq - (*ptr));
444 v = MPDM_MBS(eq + 1);
446 mpdm_hset(e, k, v);
450 return e;
455 * mpdm_startup - Initializes MPDM.
457 * Initializes the Minimum Profit Data Manager. Returns 0 if
458 * everything went OK.
460 int mpdm_startup(void)
462 /* do the startup only unless done beforehand */
463 if (mpdm == NULL) {
464 /* alloc space */
465 if ((mpdm = malloc(sizeof(struct mpdm_control))) == NULL)
466 return -1;
468 /* cleans it */
469 memset(mpdm, '\0', sizeof(struct mpdm_control));
471 /* sets the defaults */
472 mpdm->low_threshold = 16;
473 mpdm->default_sweep = -50000;
474 mpdm->hash_buckets = 31;
476 /* sets the locale */
477 if (setlocale(LC_ALL, "") == NULL)
478 setlocale(LC_ALL, "C");
480 mpdm_encoding(NULL);
482 /* store the MPDM() function */
483 mpdm_hset_s(mpdm_root(), L"MPDM", MPDM_X(MPDM));
485 /* store the ENV hash */
486 mpdm_hset_s(mpdm_root(), L"ENV", build_env());
489 /* everything went OK */
490 return 0;
495 * mpdm_shutdown - Shuts down MPDM.
497 * Shuts down MPDM. No MPDM functions should be used from now on.
499 void mpdm_shutdown(void)
501 /* dummy, by now */
505 * MPDM_A - Creates an array value.
506 * @n: Number of elements
508 * Creates a new array value with @n elements.
509 * [Value Creation]
511 /** mpdm_t MPDM_A(int n); */
512 /* ; */
515 * MPDM_H - Creates a hash value.
516 * @n: Number of buckets in the hash (0: use default)
518 * Creates a new hash value with @n buckets. The number
519 * of buckets must be a prime number. If @n is 0, an
520 * optimal number of buckets will be used.
521 * [Value Creation]
523 /** mpdm_t MPDM_H(int n); */
524 /* ; */
527 * MPDM_LS - Creates a string value from a literal string.
528 * @wcs: the wide character string
530 * Creates a new string value from a literal, wide character string.
531 * A pointer to the string will be stored in the value (not a copy).
532 * [Value Creation]
534 /** mpdm_t MPDM_LS(wchar_t * wcs); */
535 /* ; */
538 * MPDM_S - Creates a string value from a string.
539 * @wcs: the wide character string
541 * Creates a new string value from a wide character string. The value
542 * will store a copy of the string that will be freed on destruction.
543 * [Value Creation]
545 /** mpdm_t MPDM_S(wchar_t * wcs); */
546 /* ; */
549 * MPDM_NS - Creates a string value from a string, with size.
550 * @wcs: the wide character string
551 * @s: the size in chars the string will hold
553 * Creates a new string value with a copy of the first @s characters
554 * from the @wcs string.
555 * [Value Creation]
557 /** mpdm_t MPDM_NS(wchar_t * wcs, int s); */
558 /* ; */
561 * MPDM_ENS - Creates a string value from an external string, with size.
562 * @wcs: the external wide character string
563 * @s: the size in chars the string will hold
565 * Creates a new string value with size @s. The @wcs string must be
566 * a dynamic value (i.e. allocated by malloc()) that will be freed on
567 * destruction.
568 * [Value Creation]
570 /** mpdm_t MPDM_ENS(wchar_t * wcs, int s); */
571 /* ; */
574 * MPDM_I - Creates an integer value.
575 * @i: the integer
577 * Creates a new integer value. MPDM integers are strings.
578 * [Value Creation]
580 /** mpdm_t MPDM_I(int i); */
581 /* ; */
584 * MPDM_R - Creates a real value.
585 * @r: the real number
587 * Creates a new real value. MPDM integers are strings.
588 * [Value Creation]
590 /** mpdm_t MPDM_R(double r); */
591 /* ; */
594 * MPDM_F - Creates a file value.
595 * @f: the file descriptor
597 * Creates a new file value.
598 * [Value Creation]
600 /** mpdm_t MPDM_F(FILE * f); */
601 /* ; */
604 * MPDM_MBS - Creates a string value from a multibyte string.
605 * @mbs: the multibyte string
607 * Creates a new string value from a multibyte string, that will be
608 * converted to wcs by mpdm_mbstowcs().
609 * [Value Creation]
611 /** mpdm_t MPDM_MBS(char * mbs); */
612 /* ; */
615 * MPDM_NMBS - Creates a string value from a multibyte string, with size.
616 * @mbs: the multibyte string
617 * @s: the size
619 * Creates a new string value with the first @s characters from the @mbs
620 * multibyte string, that will be converted to wcs by mpdm_mbstowcs().
621 * [Value Creation]
623 /** mpdm_t MPDM_NMBS(char * mbs, int s); */
624 /* ; */
627 * MPDM_2MBS - Creates a multibyte string value from a wide char string.
628 * @wcs: the wide char string
630 * Creates a multibyte string value from the @wcs wide char string,
631 * converting it by mpdm_wcstombs(). Take note that multibyte string values
632 * are not properly strings, so they cannot be used for string comparison
633 * and such.
634 * [Value Creation]
636 /** mpdm_t MPDM_2MBS(wchar_t * wcs); */
637 /* ; */
640 * MPDM_X - Creates a new executable value.
641 * @func: the C code function
643 * Creates a new executable value given a pointer to the @func C code function.
644 * The function must receive an mpdm_t array value (that will hold their
645 * arguments) and return another one.
646 * [Value Creation]
648 /** mpdm_t MPDM_X(mpdm_t (* func)(mpdm_t args)); */
649 /* ; */
652 * MPDM_IS_ARRAY - Tests if a value is an array.
653 * @v: the value
655 * Returns non-zero if @v is an array.
657 /** int MPDM_IS_ARRAY(mpdm_t v); */
658 /* ; */
661 * MPDM_IS_HASH - Tests if a value is a hash.
662 * @v: the value
664 * Returns non-zero if @v is a hash.
666 /** int MPDM_IS_HASH(mpdm_t v); */
667 /* ; */
670 * MPDM_IS_EXEC - Tests if a value is executable.
671 * @v: the value
673 * Returns non-zero if @v is executable.
675 /** int MPDM_IS_EXEC(mpdm_t v); */
676 /* ; */
679 * MPDM_IS_STRING - Tests if a value is a string.
680 * @v: the value
682 * Returns non-zero if @v is a string.
684 /** int MPDM_IS_STRING(mpdm_t v); */
685 /* ; */