new mutex functions.
[mpsl.git] / mpsl_f.c
blob7fcda0ee57493e738818be285ab4ed96822fb984
1 /*
3 MPSL - Minimum Profit Scripting Language
4 Copyright (C) 2003/2010 Angel Ortega <angel@triptico.com>
6 mpsl_f.c - Minimum Profit Scripting Language Function Library
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 <wchar.h>
32 #include <time.h>
34 #include "mpdm.h"
35 #include "mpsl.h"
37 /** code **/
39 #define F_ARGS mpdm_t a, mpdm_t l
41 #define A(n) mpdm_aget(a, n)
42 #define A0 A(0)
43 #define A1 A(1)
44 #define A2 A(2)
45 #define IA(n) mpdm_ival(A(n))
46 #define IA0 IA(0)
47 #define IA1 IA(1)
48 #define IA2 IA(2)
49 #define IA3 IA(3)
50 #define RA(n) mpdm_rval(A(n))
51 #define RA0 RA(0)
52 #define RA1 RA(1)
53 #define RA2 RA(2)
54 #define RA3 RA(3)
56 /**
57 * size - Returns the size of a value.
58 * @v: the value
60 * Returns the size of a value. For scalars, the size is the
61 * string length; for arrays, the number of elements, and
62 * for hashes, the number of buckets in the hash (which is
63 * probably not useful, see hsize() instead).
64 * [Value Management]
66 /** integer = size(v); */
67 /* ; */
68 static mpdm_t F_size(F_ARGS) {
69 return MPDM_I(mpdm_size(A0));
72 /**
73 * clone - Creates a clone of a value.
74 * @v: the value
76 * Creates a clone of a value. If the value is multiple, a new value will
77 * be created containing clones of all its elements; otherwise,
78 * the same unchanged value is returned.
79 * [Value Management]
81 /** v2 = clone(v); */
82 static mpdm_t F_clone(F_ARGS) {
83 return mpdm_clone(A0);
86 /**
87 * dump - Dumps a value to stdin.
88 * @v: The value
90 * Dumps a value to stdin. The value can be complex. This function
91 * is for debugging purposes only.
92 * [Debugging]
93 * [Input-Output]
95 /** dump(v); */
96 static mpdm_t F_dump(F_ARGS) {
97 mpdm_dump(A0); return NULL;
101 * dumper - Returns a visual representation of a complex value.
102 * @v: The value
104 * Returns a visual representation of a complex value.
105 * [Debugging]
106 * [Strings]
108 /** string = dumper(v); */
109 static mpdm_t F_dumper(F_ARGS) {
110 return mpdm_dumper(A0);
114 * cmp - Compares two values.
115 * @v1: the first value
116 * @v2: the second value
118 * Compares two values. If both are strings, a standard string
119 * comparison (using wcscmp()) is returned; if both are arrays,
120 * the size is compared first and, if they have the same number
121 * elements, each one is compared; otherwise, a simple pointer
122 * comparison is done.
124 * In either case, an integer is returned, which is < 0 if @v1
125 * is lesser than @v2, > 0 on the contrary or 0 if both are
126 * equal.
127 * [Strings]
128 * [Arrays]
130 /** integer = cmp(v); */
131 static mpdm_t F_cmp(F_ARGS) {
132 return MPDM_I(mpdm_cmp(A0, A1));
136 * is_array - Tests if a value is an array.
137 * @v: the value
139 * Returns non-zero if @v is an array.
140 * [Value Management]
141 * [Arrays]
143 /** bool = is_array(v); */
144 static mpdm_t F_is_array(F_ARGS) {
145 return mpsl_boolean(MPDM_IS_ARRAY(A0));
149 * is_hash - Tests if a value is a hash.
150 * @v: the value
152 * Returns non-zero if @v is a hash.
153 * [Value Management]
154 * [Hashes]
156 /** bool = is_hash(v); */
157 static mpdm_t F_is_hash(F_ARGS) {
158 return mpsl_boolean(MPDM_IS_HASH(A0));
162 * is_exec - Tests if a value is executable.
163 * @v: the value
165 * Returns non-zero if @v is a executable.
166 * [Value Management]
168 /** bool = is_exec(v); */
169 static mpdm_t F_is_exec(F_ARGS) {
170 return mpsl_boolean(MPDM_IS_EXEC(A0));
174 * splice - Creates a new string value from another.
175 * @v: the original value
176 * @i: the value to be inserted
177 * @offset: offset where the substring is to be inserted
178 * @del: number of characters to delete
180 * Creates a new string value from @v, deleting @del chars at @offset
181 * and substituting them by @i. If @del is 0, no deletion is done.
182 * both @offset and @del can be negative; if this is the case, it's
183 * assumed as counting from the end of @v. If @v is NULL, @i will become
184 * the new string, and both @offset and @del will be ignored. If @v is
185 * not NULL and @i is, no insertion process is done (only deletion, if
186 * applicable).
188 * Returns a two element array, with the new string in the first
189 * element and the deleted string in the second (with a NULL value
190 * if @del is 0).
191 * [Strings]
193 /** array = splice(v, i, offset, del); */
194 static mpdm_t F_splice(F_ARGS) {
195 return mpdm_splice(A0,A1,IA2,IA3);
199 * expand - Expands an array.
200 * @a: the array
201 * @offset: insertion offset
202 * @num: number of elements to insert
204 * Expands an array value, inserting @num elements (initialized
205 * to NULL) at the specified @offset.
206 * [Arrays]
208 /** expand(a, offset, num); */
209 static mpdm_t F_expand(F_ARGS) {
210 return mpdm_expand(A0,IA1,IA2);
214 * collapse - Collapses an array.
215 * @a: the array
216 * @offset: deletion offset
217 * @num: number of elements to collapse
219 * Collapses an array value, deleting @num elements at
220 * the specified @offset.
221 * [Arrays]
223 /** collapse(a, offset, num); */
224 static mpdm_t F_collapse(F_ARGS) {
225 return mpdm_collapse(A0,IA1,IA2);
229 * ins - Insert an element in an array.
230 * @a: the array
231 * @e: the element to be inserted
232 * @offset: subscript where the element is going to be inserted
234 * Inserts the @e value in the @a array at @offset.
235 * Further elements are pushed up, so the array increases its size
236 * by one. Returns the inserted element.
237 * [Arrays]
239 /** e = ins(a, e, offset); */
240 static mpdm_t F_ins(F_ARGS) {
241 return mpdm_ins(A0,A1,IA2);
245 * adel - Deletes an element of an array.
246 * @a: the array
247 * @offset: subscript of the element to be deleted
249 * Deletes the element at @offset of the @a array. The array
250 * is shrinked by one. If @offset is negative, is counted from
251 * the end of the array (so a value of -1 means delete the
252 * last element of the array).
254 * Returns NULL (previous versions returned the deleted element).
255 * [Arrays]
257 /** v = adel(a, offset); */
258 static mpdm_t F_adel(F_ARGS) {
259 return mpdm_adel(A0,IA1);
263 * shift - Extracts the first element of an array.
264 * @a: the array
266 * Extracts the first element of the array. The array
267 * is shrinked by one.
269 * Returns the deleted element.
270 * [Arrays]
272 /** v = shift(a); */
273 static mpdm_t F_shift(F_ARGS) {
274 return mpdm_shift(A0);
278 * push - Pushes a value into an array.
279 * @a: the array
280 * @e: the value
282 * Pushes a value into an array (i.e. inserts at the end).
283 * [Arrays]
285 /** e = push(a, e); */
286 static mpdm_t F_push(F_ARGS) {
287 return mpdm_push(A0,A1);
291 * pop - Pops a value from an array.
292 * @a: the array
294 * Pops a value from the array (i.e. deletes from the end
295 * and returns it).
296 * [Arrays]
298 /** v = pop(a); */
299 static mpdm_t F_pop(F_ARGS) {
300 return mpdm_pop(A0);
304 * queue - Implements a queue in an array.
305 * @a: the array
306 * @e: the element to be pushed
307 * @size: maximum size of array
309 * Pushes the @e element into the @a array. If the array already has
310 * @size elements, the first (oldest) element is deleted from the
311 * queue and returned.
313 * Returns the deleted element, or NULL if the array doesn't have
314 * @size elements yet.
315 * [Arrays]
317 /** v = queue(a, e, size); */
318 static mpdm_t F_queue(F_ARGS) {
319 return mpdm_queue(A0,A1,IA2);
323 * seek - Seeks a value in an array (sequential).
324 * @a: the array
325 * @k: the key
326 * @step: number of elements to step
328 * Seeks sequentially the value @k in the @a array in
329 * increments of @step. A complete search should use a step of 1.
330 * Returns the offset of the element if found, or -1 otherwise.
331 * [Arrays]
333 /** integer = seek(a, k, step); */
334 static mpdm_t F_seek(F_ARGS) {
335 return MPDM_I(mpdm_seek(A0,A1,IA2));
339 * sort - Sorts an array.
340 * @a: the array
341 * @sorting_func: sorting function
343 * Sorts the array. For each pair of elements being sorted, the
344 * @sorting_func is called with the two elements to be sorted as
345 * arguments. This function must return a signed integer value indicating
346 * the sorting order.
348 * If no function is supplied, the sorting is done using cmp().
350 * Returns the sorted array (the original one is left untouched).
351 * [Arrays]
353 /** array = sort(a); */
354 /** array = sort(a, sorting_func); */
355 static mpdm_t F_sort(F_ARGS) {
356 mpdm_t r, v;
358 v = mpdm_ref(A0);
359 r = mpdm_sort_cb(mpdm_clone(v), 1, A1);
360 mpdm_unref(v);
362 return r;
366 * split - Separates a string into an array of pieces.
367 * @s: the separator
368 * @v: the value to be separated
370 * Separates the @v string value into an array of pieces, using @s
371 * as a separator.
373 * If the separator is NULL, the string is splitted by characters.
375 * If the string does not contain the separator, an array holding
376 * the complete string as its unique argument is returned.
377 * [Arrays]
378 * [Strings]
380 /** array = split(s, v); */
381 static mpdm_t F_split(F_ARGS) {
382 return mpdm_split(A0,A1);
386 * join - Joins all elements of an array into one.
387 * @s: joiner string
388 * @a: array to be joined
390 * Joins all elements from @a into one string, using @s as a glue.
391 * [Arrays]
392 * [Strings]
394 /** string = join(s, a); */
395 static mpdm_t F_join(F_ARGS) {
396 return mpdm_join(A0,A1);
400 * hsize - Returns the number of pairs of a hash.
401 * @h: the hash
403 * Returns the number of key-value pairs of a hash.
404 * [Hashes]
406 /** integer = hsize(h); */
407 static mpdm_t F_hsize(F_ARGS) {
408 return MPDM_I(mpdm_hsize(A0));
412 * exists - Tests if a key exists.
413 * @h: the hash
414 * @k: the key
416 * Returns 1 if @k is defined in @h, or 0 othersize.
417 * [Hashes]
419 /** bool = exists(h, k); */
420 static mpdm_t F_exists(F_ARGS) {
421 return mpsl_boolean(mpdm_exists(A0, A1));
425 * hdel - Deletes a key from a hash.
426 * @h: the hash
427 * @k: the key
429 * Deletes the key @k from the hash @h. Returns the previous
430 * value, or NULL if the key was not defined.
431 * [Hashes]
433 /** v = hdel(h, k); */
434 static mpdm_t F_hdel(F_ARGS) {
435 return mpdm_hdel(A0, A1);
439 * keys - Returns the keys of a hash.
440 * @h: the hash
442 * Returns an array containing all the keys of the @h hash.
443 * [Hashes]
444 * [Arrays]
446 /** array = keys(h); */
447 static mpdm_t F_keys(F_ARGS) {
448 return mpdm_keys(A0);
452 * open - Opens a file.
453 * @filename: the file name
454 * @mode: an fopen-like mode string
456 * Opens a file. If @filename can be open in the specified @mode, a
457 * value will be returned containing the file descriptor, or NULL
458 * otherwise.
460 * If the file is open for reading, some charset detection methods are
461 * used. If any of them is successful, its name is stored in the
462 * `DETECTED_ENCODING' global variable. This value is
463 * suitable to be copied over `ENCODING' or `TEMP_ENCODING'.
465 * If the file is open for writing, the encoding to be used is read from
466 * the `ENCODING' global variable and, if not set, from the
467 * `TEMP_ENCODING' one. The latter will always be deleted afterwards.
468 * [Input-Output]
469 * [Character Set Conversion]
471 /** fd = open(filename, mode); */
472 static mpdm_t F_open(F_ARGS) {
473 return mpdm_open(A0, A1);
477 * close - Closes a file descriptor.
478 * @fd: the file descriptor
480 * Closes the file descriptor.
481 * [Input-Output]
483 /** close(fd); */
484 static mpdm_t F_close(F_ARGS) {
485 return mpdm_close(A0);
489 * read - Reads a line from a file descriptor.
490 * @fd: the file descriptor
492 * Reads a line from @fd. Returns the line, or NULL on EOF.
493 * [Input-Output]
494 * [Character Set Conversion]
496 /** string = read(fd); */
497 static mpdm_t F_read(F_ARGS) {
498 return mpdm_read(A0);
502 * getchar - Reads a character from a file descriptor.
503 * @fd: the file descriptor
505 * Returns a character read from @fd, or NULL on EOF. No
506 * charset conversion is done.
507 * [Input-Output]
509 /** string = getchar(fd); */
510 static mpdm_t F_getchar(F_ARGS) {
511 return mpdm_getchar(A0);
515 * putchar - Writes a character to a file descriptor.
516 * @fd: the file descriptor
517 * @s: the string
519 * Writes the first character in @s into @fd. No charset
520 * conversion is done.
522 * Returns the number of chars written (0 or 1).
523 * [Input-Output]
525 /** s = putchar(fd, s); */
526 static mpdm_t F_putchar(F_ARGS) {
527 return MPDM_I(mpdm_putchar(A0, A1));
531 * fseek - Sets a file pointer.
532 * @fd: the file descriptor
533 * @offset: the offset
534 * @whence: the position
536 * Sets the file pointer position of @fd to @offset. @whence can
537 * be: 0 for SEEK_SET, 1 for SEEK_CUR and 2 for SEEK_END.
539 * Returns the value from the fseek() C function call.
540 * [Input-Output]
542 /** integer = fseek(fd, offset, whence); */
543 static mpdm_t F_fseek(F_ARGS) {
544 return MPDM_I(mpdm_fseek(A0, IA1, IA2));
548 * ftell - Returns the current file pointer.
549 * @fd: the file descriptor
551 * Returns the position of the file pointer in @fd.
552 * [Input-Output]
554 /** integer = ftell(fd); */
555 static mpdm_t F_ftell(F_ARGS) {
556 return MPDM_I(mpdm_ftell(A0));
560 * unlink - Deletes a file.
561 * @filename: file name to be deleted
563 * Deletes a file.
564 * [Input-Output]
566 /** bool = unlink(filename); */
567 static mpdm_t F_unlink(F_ARGS) {
568 return mpsl_boolean(mpdm_unlink(A0));
572 * stat - Gives status from a file.
573 * @filename: file name to get the status from
575 * Returns a 14 element array of the status (permissions, onwer, etc.)
576 * from the desired @filename, or NULL if the file cannot be accessed.
577 * (man 2 stat).
579 * The values are: 0, device number of filesystem; 1, inode number;
580 * 2, file mode; 3, number of hard links to the file; 4, uid; 5, gid;
581 * 6, device identifier; 7, total size of file in bytes; 8, atime;
582 * 9, mtime; 10, ctime; 11, preferred block size for system I/O;
583 * 12, number of blocks allocated and 13, canonicalized file name.
584 * Not all elements have necesarily meaningful values, as most are
585 * system-dependent.
586 * [Input-Output]
588 /** array = stat(filename); */
589 static mpdm_t F_stat(F_ARGS) {
590 return mpdm_stat(A0);
594 * chmod - Changes a file's permissions.
595 * @filename: the file name
596 * @perms: permissions (element 2 from stat())
598 * Changes the permissions for a file.
599 * [Input-Output]
601 /** integer = chmod(filename, perms); */
602 static mpdm_t F_chmod(F_ARGS) {
603 return MPDM_I(mpdm_chmod(A0,A1));
607 * chown - Changes a file's owner.
608 * @filename: the file name
609 * @uid: user id (element 4 from stat())
610 * @gid: group id (element 5 from stat())
612 * Changes the owner and group id's for a file.
613 * [Input-Output]
615 /** integer = chown(filename, uid, gid); */
616 static mpdm_t F_chown(F_ARGS) {
617 return MPDM_I(mpdm_chown(A0,A1,A2));
621 * glob - Executes a file globbing.
622 * @spec: Globbing spec
623 * @base: Optional base directory
625 * Executes a file globbing. @spec is system-dependent, but usually
626 * the * and ? metacharacters work everywhere. @base can contain a
627 * directory; if that's the case, the output strings will include it.
628 * In any case, each returned value will be suitable for a call to
629 * open().
631 * Returns an array of files that match the globbing (can be an empty
632 * array if no file matches), or NULL if globbing is unsupported.
633 * Directories are returned first and their names end with a slash.
634 * [Input-Output]
636 /** array = glob(spec, base); */
637 static mpdm_t F_glob(F_ARGS) {
638 return mpdm_glob(A0, A1);
642 * encoding - Sets the current charset encoding for files.
643 * @charset: the charset name.
645 * Sets the current charset encoding for files. Future opened
646 * files will be assumed to be encoded with @charset, which can
647 * be any of the supported charset names (utf-8, iso-8859-1, etc.),
648 * and converted on each read / write. If charset is NULL, it
649 * is reverted to default charset conversion (i.e. the one defined
650 * in the locale).
652 * This function stores the @charset value into the `ENCODING' global
653 * variable.
655 * Returns a negative number if @charset is unsupported, or zero
656 * if no errors were found.
657 * [Input-Output]
658 * [Character Set Conversion]
660 /** integer = encoding(charset); */
661 static mpdm_t F_encoding(F_ARGS) {
662 return MPDM_I(mpdm_encoding(A0));
666 * popen - Opens a pipe.
667 * @prg: the program to pipe
668 * @mode: an fopen-like mode string
670 * Opens a pipe to a program. If @prg can be open in the specified @mode,
671 * return file descriptor, or NULL otherwise.
673 * The @mode can be `r' (for reading), `w' (for writing), or `r+' or `w+'
674 * for a special double pipe reading-writing mode.
675 * [Input-Output]
677 /** fd = popen(prg, mode); */
678 static mpdm_t F_popen(F_ARGS) {
679 return mpdm_popen(A0, A1);
683 * pclose - Closes a pipe.
684 * @fd: the value containing the file descriptor
686 * Closes a pipe.
687 * [Input-Output]
689 /** pclose(fd); */
690 static mpdm_t F_pclose(F_ARGS) {
691 return mpdm_pclose(A0);
695 * regex - Matches a regular expression.
696 * @r: the regular expression
697 * @ra: an array of regular expressions
698 * @v: the value to be matched
699 * @offset: offset from the start of the value
701 * Matches a regular expression against a value. Valid flags are `i',
702 * for case-insensitive matching, `m', to treat the string as a
703 * multiline string (i.e., one containing newline characters), so
704 * that ^ and $ match the boundaries of each line instead of the
705 * whole string, `l', to return the last matching instead of the
706 * first one, or `g', to match globally; in that last case, an array
707 * containing all matches is returned instead of a string scalar.
709 * If @r is a string, an ordinary regular expression matching is tried
710 * over the @v string. If the matching is possible, the match result
711 * is returned, or NULL otherwise.
713 * If @r is an array (of strings), each element is tried sequentially
714 * as an individual regular expression over the @v string, each one using
715 * the offset returned by the previous match. All regular expressions
716 * must match to be successful. If this is the case, an array (with
717 * the same number of arguments) is returned containing the matched
718 * strings, or NULL otherwise.
720 * If @r is NULL, the result of the previous regex matching
721 * is returned as a two element array. The first element will contain
722 * the character offset of the matching and the second the number of
723 * characters matched. If the previous regex was unsuccessful, NULL
724 * is returned.
725 * [Regular Expressions]
727 /** string = regex(r, v); */
728 /** string = regex(r, v, offset); */
729 /** array = regex(ra, v); */
730 /** array = regex(); */
731 static mpdm_t F_regex(F_ARGS) {
732 return mpdm_regex(A0,A1,IA2);
736 * sregex - Matches and substitutes a regular expression.
737 * @r: the regular expression
738 * @v: the value to be matched
739 * @s: the substitution string, hash or code
740 * @offset: offset from the start of v
742 * Matches a regular expression against a value, and substitutes the
743 * found substring with @s. Valid flags are `i', for case-insensitive
744 * matching, and `g', for global replacements (all ocurrences in @v
745 * will be replaced, instead of just the first found one).
747 * If @s is executable, it's executed with the matched part as
748 * the only argument and its return value is used as the
749 * substitution string.
751 * If @s is a hash, the matched string is used as a key to it and
752 * its value used as the substitution. If this value itself is
753 * executable, it's executed with the matched string as its only
754 * argument and its return value used as the substitution.
756 * If @r is NULL, returns the number of substitutions made in the
757 * previous call to sregex() (can be zero if none was done).
759 * Returns the modified string, or the original one if no substitutions
760 * were done.
761 * [Regular Expressions]
763 /** string = sregex(r, v, s); */
764 /** string = sregex(r, v, s, offset); */
765 /** integer = sregex(); */
766 static mpdm_t F_sregex(F_ARGS) {
767 return mpdm_sregex(A0,A1,A2,IA3);
771 * gettext - Translates a string to the current language.
772 * @str: the string
774 * Translates the @str string to the current language.
776 * This function can still be used even if there is no real gettext
777 * support by manually filling the __I18N__ hash.
779 * If the string is found in the current table, the translation is
780 * returned; otherwise, the same @str value is returned.
781 * [Strings]
782 * [Localization]
784 /** string = gettext(str); */
785 static mpdm_t F_gettext(F_ARGS) {
786 return mpdm_gettext(A0);
790 * gettext_domain - Sets domain and data directory for translations.
791 * @dom: the domain (application name)
792 * @data: directory contaning the .mo files
794 * Sets the domain (application name) and translation data for translating
795 * strings that will be returned by gettext(). @data must point to a
796 * directory containing the .mo (compiled .po) files.
798 * If there is no gettext support, returns 0, or 1 otherwise.
799 * [Strings]
800 * [Localization]
802 /** bool = gettext_domain(dom, data); */
803 static mpdm_t F_gettext_domain(F_ARGS) {
804 return MPDM_I(mpdm_gettext_domain(A0, A1));
808 * load - Loads an MPSL source code file.
809 * @source_file: the source code file
811 * Loads and executes an MPSL source code file and returns
812 * its value.
813 * [Code Control]
815 /** load(source_file); */
816 static mpdm_t F_load(F_ARGS) {
817 return mpdm_exec(mpsl_compile_file(A0,
818 mpsl_get_symbol(MPDM_LS(L"INC"), l)), NULL, l);
822 * compile - Compiles a string of MSPL source code file.
823 * @source: the source code string
825 * Compiles a string of MPSL source code and returns an
826 * executable value.
827 * [Code Control]
829 /** func = compile(source); */
830 static mpdm_t F_compile(F_ARGS) {
831 return mpsl_compile(A0);
835 * error - Simulates an error.
836 * @err: the error message
838 * Simulates an error. The @err error message is stored in the `ERROR'
839 * global variable and an internal abort global flag is set, so no further
840 * MPSL code can be executed until reset.
842 /** error(err); */
843 static mpdm_t F_error(F_ARGS) {
844 return mpsl_error(A0);
848 * uc - Converts a string to uppercase.
849 * @str: the string to be converted
851 * Returns @str converted to uppercase.
852 * [Strings]
854 /** string = uc(str); */
855 static mpdm_t F_uc(F_ARGS) {
856 return mpdm_ulc(A0, 1);
860 * lc - Converts a string to lowercase.
861 * @str: the string to be converted
863 * Returns @str converted to lowercase.
864 * [Strings]
866 /** string = uc(str); */
867 static mpdm_t F_lc(F_ARGS) {
868 return mpdm_ulc(A0, 0);
872 * time - Returns the current time.
874 * Returns the current time from the epoch (C library time()).
875 * [Miscellaneous]
877 /** integer = time(); */
878 static mpdm_t F_time(F_ARGS) {
879 return MPDM_I(time(NULL));
883 * chdir - Changes the working directory
884 * @dir: the new path
886 * Changes the working directory
887 * [Input-Output]
889 /** integer = chdir(dir); */
890 static mpdm_t F_chdir(F_ARGS) {
891 return MPDM_I(mpdm_chdir(A0));
895 * sscanf - Extracts data like sscanf().
896 * @fmt: the string format
897 * @str: the string to be parsed
898 * @offset: the character offset to start scanning
900 * Extracts data from a string using a special format pattern, very
901 * much like the scanf() series of functions in the C library. Apart
902 * from the standard percent-sign-commands (s, u, d, i, f, x,
903 * n, [, with optional size and * to ignore), it implements S,
904 * to match a string of characters upto what follows in the format
905 * string. Also, the [ set of characters can include other % formats.
907 * Returns an array with the extracted values. If %n is used, the
908 * position in the scanned string is returned as the value.
909 * [Strings]
911 /** array = sscanf(fmt, str); */
912 /** array = sscanf(fmt, str, offset); */
913 static mpdm_t F_sscanf(F_ARGS) {
914 return mpdm_sscanf(A0, A1, IA2);
918 * eval - Evaluates MSPL code.
919 * @code: A value containing a string of MPSL code, or executable code
920 * @args: optional arguments for @code
922 * Evaluates a piece of code. The @code can be a string containing MPSL
923 * source code (that will be compiled) or a direct executable value. If
924 * the compilation or the execution gives an error, the `ERROR' variable
925 * will be set to a printable value and NULL returned. Otherwise, the
926 * exit value from the code is returned and `ERROR' set to NULL. The
927 * internal abort flag is reset on exit.
929 * [Code Control]
931 /** v = eval(code, args); */
932 static mpdm_t F_eval(F_ARGS)
934 mpdm_t r, c;
936 a = mpdm_ref(mpdm_clone(a));
937 c = mpdm_shift(a);
939 r = mpsl_eval(c, a, l);
941 mpdm_unref(a);
943 return r;
948 * sprintf - Formats a sprintf()-like string.
949 * @fmt: the string format
950 * @arg1: first argument
951 * @arg2: second argument
952 * @argn: nth argument
954 * Formats a string using the sprintf() format taking the values from
955 * the variable arguments.
956 * [Strings]
958 /** string = sprintf(fmt, arg1 [,arg2 ... argn]); */
959 static mpdm_t F_sprintf(F_ARGS)
961 mpdm_t f, v, r;
963 a = mpdm_ref(mpdm_clone(a));
964 f = mpdm_shift(a);
966 /* if the first argument is an array, take it as the arguments */
967 if ((v = mpdm_aget(a, 0)) != NULL && MPDM_IS_ARRAY(v))
968 a = v;
970 r = mpdm_sprintf(f, a);
972 mpdm_unref(a);
974 return r;
979 * print - Writes values to stdout.
980 * @arg1: first argument
981 * @arg2: second argument
982 * @argn: nth argument
984 * Writes the variable arguments to stdout.
985 * [Input-Output]
987 /** print(arg1 [,arg2 ... argn]); */
988 static mpdm_t F_print(F_ARGS)
990 int n;
992 for (n = 0; n < mpdm_size(a); n++)
993 mpdm_write_wcs(stdout, mpdm_string(A(n)));
994 return NULL;
999 * write - Writes values to a file descriptor.
1000 * @fd: the file descriptor
1001 * @arg1: first argument
1002 * @arg2: second argument
1003 * @argn: nth argument
1005 * Writes the variable arguments to the file descriptor, doing
1006 * charset conversion in the process.
1008 * Returns the total size written to @fd.
1009 * [Input-Output]
1010 * [Character Set Conversion]
1012 /** integer = write(fd, arg1 [,arg2 ... argn]); */
1013 static mpdm_t F_write(F_ARGS)
1015 int n, r = 0;
1017 for (n = 1; n < mpdm_size(a); n++)
1018 r += mpdm_write(A0, A(n));
1020 return MPDM_I(r);
1025 * chr - Returns the Unicode character represented by the codepoint.
1026 * @c: the codepoint as an integer value
1028 * Returns a 1 character string containing the character which
1029 * Unicode codepoint is @c.
1030 * [Strings]
1032 /** string = chr(c); */
1033 static mpdm_t F_chr(F_ARGS)
1035 wchar_t tmp[2];
1037 tmp[0] = (wchar_t) mpdm_ival(mpdm_aget(a, 0));
1038 tmp[1] = L'\0';
1040 return MPDM_S(tmp);
1045 * ord - Returns the Unicode codepoint of a character.
1046 * @str: the string
1048 * Returns the Unicode codepoint for the first character in
1049 * the string.
1050 * [Strings]
1052 /** integer = ord(str); */
1053 static mpdm_t F_ord(F_ARGS)
1055 int ret = 0;
1056 mpdm_t v = mpdm_aget(a, 0);
1058 if (v != NULL) {
1059 wchar_t * ptr = mpdm_string(v);
1060 ret = (int) *ptr;
1063 return MPDM_I(ret);
1068 * map - Maps an array into another.
1069 * @filter: the filter
1070 * @a: the array
1072 * Returns a new array built by applying the @filter to all the
1073 * elements of the array @a. The filter can be an executable function
1074 * accepting one argument, in which case the return value of the function
1075 * will be used as the output element; @filt can also be a hash, in which
1076 * case the original element will be used as a key to the hash and the
1077 * associated value used as the output element.
1079 * [Arrays]
1081 /** array = map(filter, a); */
1082 static mpdm_t F_map(F_ARGS)
1084 mpdm_t key = mpdm_aget(a, 0);
1085 mpdm_t set = mpdm_aget(a, 1);
1086 mpdm_t out;
1088 /* map NULL to NULL */
1089 if (set == NULL)
1090 return NULL;
1092 out = mpdm_ref(MPDM_A(mpdm_size(set)));
1094 if (MPDM_IS_EXEC(key)) {
1095 int n;
1097 /* executes the code using the element as argument
1098 and stores the result in the output array */
1099 for (n = 0; n < mpdm_size(set); n++)
1100 mpdm_aset(out, mpdm_exec_1(key, mpdm_aget(set, n), l), n);
1102 else
1103 if(MPDM_IS_HASH(key)) {
1104 int n;
1106 /* maps each value using the element as key */
1107 for (n = 0; n < mpdm_size(set); n++)
1108 mpdm_aset(out, mpdm_hget(key, mpdm_aget(set, n)), n);
1111 return mpdm_unrefnd(out);
1116 * grep - Greps inside an array.
1117 * @filter: the filter
1118 * @a: the array
1120 * Greps inside an array and returns another one containing only the
1121 * elements that passed the filter. If @filter is a string, it's accepted
1122 * as a regular expression, which will be applied to each element.
1123 * If @filter is executable, it will be called with the element as its
1124 * only argument and its return value used as validation.
1126 * The new array will contain all elements that passed the filter.
1127 * [Arrays]
1128 * [Regular Expressions]
1130 /** array = grep(filter, a); */
1131 static mpdm_t F_grep(F_ARGS)
1133 mpdm_t key = mpdm_aget(a, 0);
1134 mpdm_t set = mpdm_aget(a, 1);
1135 mpdm_t out = mpdm_ref(MPDM_A(0));
1137 if (MPDM_IS_EXEC(key)) {
1138 int n;
1140 /* it's executable */
1141 for (n = 0; n < mpdm_size(set); n++) {
1142 mpdm_t v = mpdm_aget(set, n);
1143 mpdm_t w = mpdm_ref(mpdm_exec_1(key, v, l));
1145 if (mpsl_is_true(w))
1146 mpdm_push(out, v);
1148 mpdm_unref(w);
1151 else
1152 if(key->flags & MPDM_STRING) {
1153 int n;
1155 /* it's a string; use it as a regular expression */
1156 for (n = 0; n < mpdm_size(set); n++) {
1157 mpdm_t v = mpdm_aget(set, n);
1158 mpdm_t w = mpdm_ref(mpdm_regex(key, v, 0));
1160 if (w)
1161 mpdm_push(out, v);
1163 mpdm_unref(w);
1167 return mpdm_size(mpdm_unrefnd(out)) == 0 ? NULL : out;
1170 static mpdm_t F_getenv(F_ARGS)
1172 mpdm_t e = mpdm_hget_s(mpdm_root(), L"ENV");
1174 return mpdm_hget(e, mpdm_aget(a, 0));
1177 static mpdm_t F_bincall(F_ARGS) {
1178 return MPDM_X(mpdm_ival(mpdm_aget(a, 0)));
1182 * random - Returns a random value.
1184 * Returns a random number from 0 to value - 1.
1185 * [Miscellaneous]
1187 /** integer = random(value); */
1188 static mpdm_t F_random(F_ARGS)
1190 static unsigned int seed = 0;
1191 int r = 0;
1192 int range = mpdm_ival(mpdm_aget(a, 0));
1194 if (range == 0 || seed == 0)
1195 seed = time(NULL);
1196 else {
1197 seed = (seed * 58321) + 11113;
1198 r = (seed >> 16) % range;
1201 return MPDM_I(r);
1206 * sleep - Sleeps a number of milliseconds.
1208 * Sleeps a number of milliseconds.
1209 * [Threading]
1211 /** sleep(msecs); */
1212 static mpdm_t F_sleep(F_ARGS)
1214 mpdm_sleep(mpdm_ival(mpdm_aget(a, 0)));
1216 return NULL;
1221 * mutex - Returns a new mutex.
1223 * Returns a new mutex.
1224 * [Threading]
1226 /** var = mutex(); */
1227 static mpdm_t F_mutex(F_ARGS)
1229 return mpdm_new_mutex();
1234 * mutex_lock - Locks a mutex (possibly waiting).
1236 * Locks a mutex. If the mutex is already locked by
1237 * another process, it waits until it's unlocked.
1238 * [Threading]
1240 /** mutex_lock(mtx); */
1241 static mpdm_t F_mutex_lock(F_ARGS)
1243 mpdm_mutex_lock(A0);
1244 return NULL;
1249 * mutex_unlock - Unlocks a mutex.
1251 * Unlocks a mutex.
1252 * [Threading]
1254 /** mutex_unlock(mtx); */
1255 static mpdm_t F_mutex_unlock(F_ARGS)
1257 mpdm_mutex_unlock(A0);
1258 return NULL;
1262 static struct {
1263 wchar_t * name;
1264 mpdm_t (* func)(mpdm_t, mpdm_t);
1265 } mpsl_funcs[] = {
1266 { L"size", F_size },
1267 { L"clone", F_clone },
1268 { L"dump", F_dump },
1269 { L"dumper", F_dumper },
1270 { L"cmp", F_cmp },
1271 { L"is_array", F_is_array },
1272 { L"is_hash", F_is_hash },
1273 { L"is_exec", F_is_exec },
1274 { L"splice", F_splice },
1275 { L"expand", F_expand },
1276 { L"collapse", F_collapse },
1277 { L"ins", F_ins },
1278 { L"adel", F_adel },
1279 { L"shift", F_shift },
1280 { L"push", F_push },
1281 { L"pop", F_pop },
1282 { L"queue", F_queue },
1283 { L"seek", F_seek },
1284 { L"sort", F_sort },
1285 { L"split", F_split },
1286 { L"join", F_join },
1287 { L"hsize", F_hsize },
1288 { L"exists", F_exists },
1289 { L"hdel", F_hdel },
1290 { L"keys", F_keys },
1291 { L"open", F_open },
1292 { L"close", F_close },
1293 { L"read", F_read },
1294 { L"write", F_write },
1295 { L"getchar", F_getchar },
1296 { L"putchar", F_putchar },
1297 { L"fseek", F_fseek },
1298 { L"ftell", F_ftell },
1299 { L"unlink", F_unlink },
1300 { L"stat", F_stat },
1301 { L"chmod", F_chmod },
1302 { L"chown", F_chown },
1303 { L"glob", F_glob },
1304 { L"encoding", F_encoding },
1305 { L"popen", F_popen },
1306 { L"pclose", F_pclose },
1307 { L"regex", F_regex },
1308 { L"sregex", F_sregex },
1309 { L"load", F_load },
1310 { L"compile", F_compile },
1311 { L"error", F_error },
1312 { L"eval", F_eval },
1313 { L"print", F_print },
1314 { L"gettext", F_gettext },
1315 { L"gettext_domain", F_gettext_domain },
1316 { L"sprintf", F_sprintf },
1317 { L"chr", F_chr },
1318 { L"ord", F_ord },
1319 { L"map", F_map },
1320 { L"grep", F_grep },
1321 { L"getenv", F_getenv },
1322 { L"uc", F_uc },
1323 { L"lc", F_lc },
1324 { L"time", F_time },
1325 { L"chdir", F_chdir },
1326 { L"sscanf", F_sscanf },
1327 { L"bincall", F_bincall },
1328 { L"random", F_random },
1329 { L"sleep", F_sleep },
1330 { L"mutex", F_mutex },
1331 { L"mutex_lock", F_mutex_lock },
1332 { L"mutex_unlock", F_mutex_unlock },
1333 { NULL, NULL }
1337 mpdm_t mpsl_build_funcs(void)
1338 /* build all functions */
1340 mpdm_t c;
1341 int n;
1343 /* creates all the symbols in the CORE library */
1344 c = MPDM_H(0);
1346 mpdm_ref(c);
1348 for (n = 0; mpsl_funcs[n].name != NULL; n++) {
1349 mpdm_t f = MPDM_S(mpsl_funcs[n].name);
1350 mpdm_t x = MPDM_X(mpsl_funcs[n].func);
1352 mpdm_hset(mpdm_root(), f, x);
1353 mpdm_hset(c, f, x);
1356 mpdm_unrefnd(c);
1358 return c;