Fixed F_eval() and F_sprintf() for 2.0.
[mpsl.git] / mpsl_f.c
blob11748cee0f671c15d885ca32400b0acfb2b6db98
1 /*
3 MPSL - Minimum Profit Scripting Language
4 Copyright (C) 2003/2009 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 A(n) mpdm_aget(a, n)
40 #define A0 A(0)
41 #define A1 A(1)
42 #define A2 A(2)
43 #define IA(n) mpdm_ival(A(n))
44 #define IA0 IA(0)
45 #define IA1 IA(1)
46 #define IA2 IA(2)
47 #define IA3 IA(3)
48 #define RA(n) mpdm_rval(A(n))
49 #define RA0 RA(0)
50 #define RA1 RA(1)
51 #define RA2 RA(2)
52 #define RA3 RA(3)
54 /**
55 * size - Returns the size of a value.
56 * @v: the value
58 * Returns the size of a value. For scalars, the size is the
59 * string length; for arrays, the number of elements, and
60 * for hashes, the number of buckets in the hash (which is
61 * probably not useful, see hsize() instead).
62 * [Value Management]
64 /** integer = size(v); */
65 /* ; */
66 static mpdm_t F_size(mpdm_t a) {
67 return MPDM_I(mpdm_size(A0));
70 /**
71 * clone - Creates a clone of a value.
72 * @v: the value
74 * Creates a clone of a value. If the value is multiple, a new value will
75 * be created containing clones of all its elements; otherwise,
76 * the same unchanged value is returned.
77 * [Value Management]
79 /** v2 = clone(v); */
80 static mpdm_t F_clone(mpdm_t a) {
81 return mpdm_clone(A0);
84 /**
85 * dump - Dumps a value to stdin.
86 * @v: The value
88 * Dumps a value to stdin. The value can be complex. This function
89 * is for debugging purposes only.
90 * [Debugging]
91 * [Input-Output]
93 /** dump(v); */
94 static mpdm_t F_dump(mpdm_t a) {
95 mpdm_dump(A0); return NULL;
98 /**
99 * dumper - Returns a visual representation of a complex value.
100 * @v: The value
102 * Returns a visual representation of a complex value.
103 * [Debugging]
104 * [Strings]
106 /** string = dumper(v); */
107 static mpdm_t F_dumper(mpdm_t a) {
108 return mpdm_dumper(A0);
112 * cmp - Compares two values.
113 * @v1: the first value
114 * @v2: the second value
116 * Compares two values. If both are strings, a standard string
117 * comparison (using wcscmp()) is returned; if both are arrays,
118 * the size is compared first and, if they have the same number
119 * elements, each one is compared; otherwise, a simple pointer
120 * comparison is done.
122 * In either case, an integer is returned, which is < 0 if @v1
123 * is lesser than @v2, > 0 on the contrary or 0 if both are
124 * equal.
125 * [Strings]
126 * [Arrays]
128 /** integer = cmp(v); */
129 static mpdm_t F_cmp(mpdm_t a) {
130 return MPDM_I(mpdm_cmp(A0, A1));
134 * is_array - Tests if a value is an array.
135 * @v: the value
137 * Returns non-zero if @v is an array.
138 * [Value Management]
139 * [Arrays]
141 /** bool = is_array(v); */
142 static mpdm_t F_is_array(mpdm_t a) {
143 return mpsl_boolean(MPDM_IS_ARRAY(A0));
147 * is_hash - Tests if a value is a hash.
148 * @v: the value
150 * Returns non-zero if @v is a hash.
151 * [Value Management]
152 * [Hashes]
154 /** bool = is_hash(v); */
155 static mpdm_t F_is_hash(mpdm_t a) {
156 return mpsl_boolean(MPDM_IS_HASH(A0));
160 * is_exec - Tests if a value is executable.
161 * @v: the value
163 * Returns non-zero if @v is a executable.
164 * [Value Management]
166 /** bool = is_exec(v); */
167 static mpdm_t F_is_exec(mpdm_t a) {
168 return mpsl_boolean(MPDM_IS_EXEC(A0));
172 * splice - Creates a new string value from another.
173 * @v: the original value
174 * @i: the value to be inserted
175 * @offset: offset where the substring is to be inserted
176 * @del: number of characters to delete
178 * Creates a new string value from @v, deleting @del chars at @offset
179 * and substituting them by @i. If @del is 0, no deletion is done.
180 * both @offset and @del can be negative; if this is the case, it's
181 * assumed as counting from the end of @v. If @v is NULL, @i will become
182 * the new string, and both @offset and @del will be ignored. If @v is
183 * not NULL and @i is, no insertion process is done (only deletion, if
184 * applicable).
186 * Returns a two element array, with the new string in the first
187 * element and the deleted string in the second (with a NULL value
188 * if @del is 0).
189 * [Strings]
191 /** array = splice(v, i, offset, del); */
192 static mpdm_t F_splice(mpdm_t a) {
193 return mpdm_splice(A0,A1,IA2,IA3);
197 * expand - Expands an array.
198 * @a: the array
199 * @offset: insertion offset
200 * @num: number of elements to insert
202 * Expands an array value, inserting @num elements (initialized
203 * to NULL) at the specified @offset.
204 * [Arrays]
206 /** expand(a, offset, num); */
207 static mpdm_t F_expand(mpdm_t a) {
208 return mpdm_expand(A0,IA1,IA2);
212 * collapse - Collapses an array.
213 * @a: the array
214 * @offset: deletion offset
215 * @num: number of elements to collapse
217 * Collapses an array value, deleting @num elements at
218 * the specified @offset.
219 * [Arrays]
221 /** collapse(a, offset, num); */
222 static mpdm_t F_collapse(mpdm_t a) {
223 return mpdm_collapse(A0,IA1,IA2);
227 * ins - Insert an element in an array.
228 * @a: the array
229 * @e: the element to be inserted
230 * @offset: subscript where the element is going to be inserted
232 * Inserts the @e value in the @a array at @offset.
233 * Further elements are pushed up, so the array increases its size
234 * by one. Returns the inserted element.
235 * [Arrays]
237 /** e = ins(a, e, offset); */
238 static mpdm_t F_ins(mpdm_t a) {
239 return mpdm_ins(A0,A1,IA2);
243 * adel - Deletes an element of an array.
244 * @a: the array
245 * @offset: subscript of the element to be deleted
247 * Deletes the element at @offset of the @a array. The array
248 * is shrinked by one. If @offset is negative, is counted from
249 * the end of the array (so a value of -1 means delete the
250 * last element of the array).
252 * Returns NULL (previous versions returned the deleted element).
253 * [Arrays]
255 /** v = adel(a, offset); */
256 static mpdm_t F_adel(mpdm_t a) {
257 return mpdm_adel(A0,IA1);
261 * shift - Extracts the first element of an array.
262 * @a: the array
264 * Extracts the first element of the array. The array
265 * is shrinked by one.
267 * Returns the deleted element.
268 * [Arrays]
270 /** v = shift(a); */
271 static mpdm_t F_shift(mpdm_t a) {
272 return mpdm_shift(A0);
276 * push - Pushes a value into an array.
277 * @a: the array
278 * @e: the value
280 * Pushes a value into an array (i.e. inserts at the end).
281 * [Arrays]
283 /** e = push(a, e); */
284 static mpdm_t F_push(mpdm_t a) {
285 return mpdm_push(A0,A1);
289 * pop - Pops a value from an array.
290 * @a: the array
292 * Pops a value from the array (i.e. deletes from the end
293 * and returns it).
294 * [Arrays]
296 /** v = pop(a); */
297 static mpdm_t F_pop(mpdm_t a) {
298 return mpdm_pop(A0);
302 * queue - Implements a queue in an array.
303 * @a: the array
304 * @e: the element to be pushed
305 * @size: maximum size of array
307 * Pushes the @e element into the @a array. If the array already has
308 * @size elements, the first (oldest) element is deleted from the
309 * queue and returned.
311 * Returns the deleted element, or NULL if the array doesn't have
312 * @size elements yet.
313 * [Arrays]
315 /** v = queue(a, e, size); */
316 static mpdm_t F_queue(mpdm_t a) {
317 return mpdm_queue(A0,A1,IA2);
321 * seek - Seeks a value in an array (sequential).
322 * @a: the array
323 * @k: the key
324 * @step: number of elements to step
326 * Seeks sequentially the value @k in the @a array in
327 * increments of @step. A complete search should use a step of 1.
328 * Returns the offset of the element if found, or -1 otherwise.
329 * [Arrays]
331 /** integer = seek(a, k, step); */
332 static mpdm_t F_seek(mpdm_t a) {
333 return MPDM_I(mpdm_seek(A0,A1,IA2));
337 * sort - Sorts an array.
338 * @a: the array
339 * @sorting_func: sorting function
341 * Sorts the array. For each pair of elements being sorted, the
342 * @sorting_func is called with the two elements to be sorted as
343 * arguments. This function must return a signed integer value indicating
344 * the sorting order.
346 * If no function is supplied, the sorting is done using cmp().
348 * Returns the same array (previous versions returned a new array).
349 * [Arrays]
351 /** array = sort(a); */
352 /** array = sort(a, sorting_func); */
353 static mpdm_t F_sort(mpdm_t a) {
354 return mpdm_sort_cb(A0,1,A1);
358 * split - Separates a string into an array of pieces.
359 * @s: the separator
360 * @v: the value to be separated
362 * Separates the @v string value into an array of pieces, using @s
363 * as a separator.
365 * If the separator is NULL, the string is splitted by characters.
367 * If the string does not contain the separator, an array holding
368 * the complete string as its unique argument is returned.
369 * [Arrays]
370 * [Strings]
372 /** array = split(s, v); */
373 static mpdm_t F_split(mpdm_t a) {
374 return mpdm_split(A0,A1);
378 * join - Joins all elements of an array into one.
379 * @s: joiner string
380 * @a: array to be joined
382 * Joins all elements from @a into one string, using @s as a glue.
383 * [Arrays]
384 * [Strings]
386 /** string = join(s, a); */
387 static mpdm_t F_join(mpdm_t a) {
388 return mpdm_join(A0,A1);
392 * hsize - Returns the number of pairs of a hash.
393 * @h: the hash
395 * Returns the number of key-value pairs of a hash.
396 * [Hashes]
398 /** integer = hsize(h); */
399 static mpdm_t F_hsize(mpdm_t a) {
400 return MPDM_I(mpdm_hsize(A0));
404 * exists - Tests if a key exists.
405 * @h: the hash
406 * @k: the key
408 * Returns 1 if @k is defined in @h, or 0 othersize.
409 * [Hashes]
411 /** bool = exists(h, k); */
412 static mpdm_t F_exists(mpdm_t a) {
413 return mpsl_boolean(mpdm_exists(A0, A1));
417 * hdel - Deletes a key from a hash.
418 * @h: the hash
419 * @k: the key
421 * Deletes the key @k from the hash @h. Returns the previous
422 * value, or NULL if the key was not defined.
423 * [Hashes]
425 /** v = hdel(h, k); */
426 static mpdm_t F_hdel(mpdm_t a) {
427 return mpdm_hdel(A0, A1);
431 * keys - Returns the keys of a hash.
432 * @h: the hash
434 * Returns an array containing all the keys of the @h hash.
435 * [Hashes]
436 * [Arrays]
438 /** array = keys(h); */
439 static mpdm_t F_keys(mpdm_t a) {
440 return mpdm_keys(A0);
444 * open - Opens a file.
445 * @filename: the file name
446 * @mode: an fopen-like mode string
448 * Opens a file. If @filename can be open in the specified @mode, a
449 * value will be returned containing the file descriptor, or NULL
450 * otherwise.
452 * If the file is open for reading, some charset detection methods are
453 * used. If any of them is successful, its name is stored in the
454 * `DETECTED_ENCODING' global variable. This value is
455 * suitable to be copied over `ENCODING' or `TEMP_ENCODING'.
457 * If the file is open for writing, the encoding to be used is read from
458 * the `ENCODING' global variable and, if not set, from the
459 * `TEMP_ENCODING' one. The latter will always be deleted afterwards.
460 * [Input-Output]
461 * [Character Set Conversion]
463 /** fd = open(filename, mode); */
464 static mpdm_t F_open(mpdm_t a) {
465 return mpdm_open(A0, A1);
469 * close - Closes a file descriptor.
470 * @fd: the file descriptor
472 * Closes the file descriptor.
473 * [Input-Output]
475 /** close(fd); */
476 static mpdm_t F_close(mpdm_t a) {
477 return mpdm_close(A0);
481 * read - Reads a line from a file descriptor.
482 * @fd: the file descriptor
484 * Reads a line from @fd. Returns the line, or NULL on EOF.
485 * [Input-Output]
486 * [Character Set Conversion]
488 /** string = read(fd); */
489 static mpdm_t F_read(mpdm_t a) {
490 return mpdm_read(A0);
494 * getchar - Reads a character from a file descriptor.
495 * @fd: the file descriptor
497 * Returns a character read from @fd, or NULL on EOF. No
498 * charset conversion is done.
499 * [Input-Output]
501 /** string = getchar(fd); */
502 static mpdm_t F_getchar(mpdm_t a) {
503 return mpdm_getchar(A0);
507 * putchar - Writes a character to a file descriptor.
508 * @fd: the file descriptor
509 * @s: the string
511 * Writes the first character in @s into @fd. No charset
512 * conversion is done.
514 * Returns @s or NULL if the writing failed.
515 * [Input-Output]
517 /** s = putchar(fd, s); */
518 static mpdm_t F_putchar(mpdm_t a) {
519 return mpdm_putchar(A0, A1);
523 * fseek - Sets a file pointer.
524 * @fd: the file descriptor
525 * @offset: the offset
526 * @whence: the position
528 * Sets the file pointer position of @fd to @offset. @whence can
529 * be: 0 for SEEK_SET, 1 for SEEK_CUR and 2 for SEEK_END.
531 * Returns the value from the fseek() C function call.
532 * [Input-Output]
534 /** integer = fseek(fd, offset, whence); */
535 static mpdm_t F_fseek(mpdm_t a) {
536 return MPDM_I(mpdm_fseek(A0, IA1, IA2));
540 * ftell - Returns the current file pointer.
541 * @fd: the file descriptor
543 * Returns the position of the file pointer in @fd.
544 * [Input-Output]
546 /** integer = ftell(fd); */
547 static mpdm_t F_ftell(mpdm_t a) {
548 return MPDM_I(mpdm_ftell(A0));
552 * unlink - Deletes a file.
553 * @filename: file name to be deleted
555 * Deletes a file.
556 * [Input-Output]
558 /** bool = unlink(filename); */
559 static mpdm_t F_unlink(mpdm_t a) {
560 return mpsl_boolean(mpdm_unlink(A0));
564 * stat - Gives status from a file.
565 * @filename: file name to get the status from
567 * Returns a 14 element array of the status (permissions, onwer, etc.)
568 * from the desired @filename, or NULL if the file cannot be accessed.
569 * (man 2 stat).
571 * The values are: 0, device number of filesystem; 1, inode number;
572 * 2, file mode; 3, number of hard links to the file; 4, uid; 5, gid;
573 * 6, device identifier; 7, total size of file in bytes; 8, atime;
574 * 9, mtime; 10, ctime; 11, preferred block size for system I/O;
575 * 12, number of blocks allocated and 13, canonicalized file name.
576 * Not all elements have necesarily meaningful values, as most are
577 * system-dependent.
578 * [Input-Output]
580 /** array = stat(filename); */
581 static mpdm_t F_stat(mpdm_t a) {
582 return mpdm_stat(A0);
586 * chmod - Changes a file's permissions.
587 * @filename: the file name
588 * @perms: permissions (element 2 from stat())
590 * Changes the permissions for a file.
591 * [Input-Output]
593 /** integer = chmod(filename, perms); */
594 static mpdm_t F_chmod(mpdm_t a) {
595 return MPDM_I(mpdm_chmod(A0,A1));
599 * chown - Changes a file's owner.
600 * @filename: the file name
601 * @uid: user id (element 4 from stat())
602 * @gid: group id (element 5 from stat())
604 * Changes the owner and group id's for a file.
605 * [Input-Output]
607 /** integer = chown(filename, uid, gid); */
608 static mpdm_t F_chown(mpdm_t a) {
609 return MPDM_I(mpdm_chown(A0,A1,A2));
613 * glob - Executes a file globbing.
614 * @spec: Globbing spec
615 * @base: Optional base directory
617 * Executes a file globbing. @spec is system-dependent, but usually
618 * the * and ? metacharacters work everywhere. @base can contain a
619 * directory; if that's the case, the output strings will include it.
620 * In any case, each returned value will be suitable for a call to
621 * open().
623 * Returns an array of files that match the globbing (can be an empty
624 * array if no file matches), or NULL if globbing is unsupported.
625 * Directories are returned first and their names end with a slash.
626 * [Input-Output]
628 /** array = glob(spec, base); */
629 static mpdm_t F_glob(mpdm_t a) {
630 return mpdm_glob(A0, A1);
634 * encoding - Sets the current charset encoding for files.
635 * @charset: the charset name.
637 * Sets the current charset encoding for files. Future opened
638 * files will be assumed to be encoded with @charset, which can
639 * be any of the supported charset names (utf-8, iso-8859-1, etc.),
640 * and converted on each read / write. If charset is NULL, it
641 * is reverted to default charset conversion (i.e. the one defined
642 * in the locale).
644 * This function stores the @charset value into the `ENCODING' global
645 * variable.
647 * Returns a negative number if @charset is unsupported, or zero
648 * if no errors were found.
649 * [Input-Output]
650 * [Character Set Conversion]
652 /** integer = encoding(charset); */
653 static mpdm_t F_encoding(mpdm_t a) {
654 return MPDM_I(mpdm_encoding(A0));
658 * popen - Opens a pipe.
659 * @prg: the program to pipe
660 * @mode: an fopen-like mode string
662 * Opens a pipe to a program. If @prg can be open in the specified @mode,
663 * return file descriptor, or NULL otherwise.
665 * The @mode can be `r' (for reading), `w' (for writing), or `r+' or `w+'
666 * for a special double pipe reading-writing mode.
667 * [Input-Output]
669 /** fd = popen(prg, mode); */
670 static mpdm_t F_popen(mpdm_t a) {
671 return mpdm_popen(A0, A1);
675 * pclose - Closes a pipe.
676 * @fd: the value containing the file descriptor
678 * Closes a pipe.
679 * [Input-Output]
681 /** pclose(fd); */
682 static mpdm_t F_pclose(mpdm_t a) {
683 return mpdm_pclose(A0);
687 * regex - Matches a regular expression.
688 * @r: the regular expression
689 * @ra: an array of regular expressions
690 * @v: the value to be matched
691 * @offset: offset from the start of the value
693 * Matches a regular expression against a value. Valid flags are `i',
694 * for case-insensitive matching, `m', to treat the string as a
695 * multiline string (i.e., one containing newline characters), so
696 * that ^ and $ match the boundaries of each line instead of the
697 * whole string, `l', to return the last matching instead of the
698 * first one, or `g', to match globally; in that last case, an array
699 * containing all matches is returned instead of a string scalar.
701 * If @r is a string, an ordinary regular expression matching is tried
702 * over the @v string. If the matching is possible, the match result
703 * is returned, or NULL otherwise.
705 * If @r is an array (of strings), each element is tried sequentially
706 * as an individual regular expression over the @v string, each one using
707 * the offset returned by the previous match. All regular expressions
708 * must match to be successful. If this is the case, an array (with
709 * the same number of arguments) is returned containing the matched
710 * strings, or NULL otherwise.
712 * If @r is NULL, the result of the previous regex matching
713 * is returned as a two element array. The first element will contain
714 * the character offset of the matching and the second the number of
715 * characters matched. If the previous regex was unsuccessful, NULL
716 * is returned.
717 * [Regular Expressions]
719 /** string = regex(r, v); */
720 /** string = regex(r, v, offset); */
721 /** array = regex(ra, v); */
722 /** array = regex(); */
723 static mpdm_t F_regex(mpdm_t a) {
724 return mpdm_regex(A0,A1,IA2);
728 * sregex - Matches and substitutes a regular expression.
729 * @r: the regular expression
730 * @v: the value to be matched
731 * @s: the substitution string, hash or code
732 * @offset: offset from the start of v
734 * Matches a regular expression against a value, and substitutes the
735 * found substring with @s. Valid flags are `i', for case-insensitive
736 * matching, and `g', for global replacements (all ocurrences in @v
737 * will be replaced, instead of just the first found one).
739 * If @s is executable, it's executed with the matched part as
740 * the only argument and its return value is used as the
741 * substitution string.
743 * If @s is a hash, the matched string is used as a key to it and
744 * its value used as the substitution. If this value itself is
745 * executable, it's executed with the matched string as its only
746 * argument and its return value used as the substitution.
748 * If @r is NULL, returns the number of substitutions made in the
749 * previous call to sregex() (can be zero if none was done).
751 * Returns the modified string, or the original one if no substitutions
752 * were done.
753 * [Regular Expressions]
755 /** string = sregex(r, v, s); */
756 /** string = sregex(r, v, s, offset); */
757 /** integer = sregex(); */
758 static mpdm_t F_sregex(mpdm_t a) {
759 return mpdm_sregex(A0,A1,A2,IA3);
763 * gettext - Translates a string to the current language.
764 * @str: the string
766 * Translates the @str string to the current language.
768 * This function can still be used even if there is no real gettext
769 * support by manually filling the __I18N__ hash.
771 * If the string is found in the current table, the translation is
772 * returned; otherwise, the same @str value is returned.
773 * [Strings]
774 * [Localization]
776 /** string = gettext(str); */
777 static mpdm_t F_gettext(mpdm_t a) {
778 return mpdm_gettext(A0);
782 * gettext_domain - Sets domain and data directory for translations.
783 * @dom: the domain (application name)
784 * @data: directory contaning the .mo files
786 * Sets the domain (application name) and translation data for translating
787 * strings that will be returned by gettext(). @data must point to a
788 * directory containing the .mo (compiled .po) files.
790 * If there is no gettext support, returns 0, or 1 otherwise.
791 * [Strings]
792 * [Localization]
794 /** bool = gettext_domain(dom, data); */
795 static mpdm_t F_gettext_domain(mpdm_t a) {
796 return MPDM_I(mpdm_gettext_domain(A0, A1));
800 * load - Loads an MPSL source code file.
801 * @source_file: the source code file
803 * Loads and executes an MPSL source code file and returns
804 * its value.
805 * [Code Control]
807 /** load(source_file); */
808 static mpdm_t F_load(mpdm_t a) {
809 return mpdm_exec(mpsl_compile_file(A0), NULL);
813 * compile - Compiles a string of MSPL source code file.
814 * @source: the source code string
816 * Compiles a string of MPSL source code and returns an
817 * executable value.
818 * [Code Control]
820 /** func = compile(source); */
821 static mpdm_t F_compile(mpdm_t a) {
822 return mpsl_compile(A0);
826 * error - Simulates an error.
827 * @err: the error message
829 * Simulates an error. The @err error message is stored in the `ERROR'
830 * global variable and an internal abort global flag is set, so no further
831 * MPSL code can be executed until reset.
833 /** error(err); */
834 static mpdm_t F_error(mpdm_t a) {
835 return mpsl_error(A0);
839 * sweep - Sweeps unreferenced values.
840 * @count: number of values to be swept
842 * Destroys values with a reference count of 0. @count is the
843 * number of values to be checked for deletion; special values of
844 * @count are -1, that forces a check of all currently known values
845 * (can be time-consuming) and 0, which tells sweep() to check a
846 * small group of them on each call.
847 * [Value Management]
849 /** sweep(count); */
850 static mpdm_t F_sweep(mpdm_t a) {
851 mpdm_sweep(IA0); return NULL;
855 * uc - Converts a string to uppercase.
856 * @str: the string to be converted
858 * Returns @str converted to uppercase.
859 * [Strings]
861 /** string = uc(str); */
862 static mpdm_t F_uc(mpdm_t a) {
863 return mpdm_ulc(A0, 1);
867 * lc - Converts a string to lowercase.
868 * @str: the string to be converted
870 * Returns @str converted to lowercase.
871 * [Strings]
873 /** string = uc(str); */
874 static mpdm_t F_lc(mpdm_t a) {
875 return mpdm_ulc(A0, 0);
879 * time - Returns the current time.
881 * Returns the current time from the epoch (C library time()).
882 * [Miscellaneous]
884 /** integer = time(); */
885 static mpdm_t F_time(mpdm_t a) {
886 return MPDM_I(time(NULL));
890 * chdir - Changes the working directory
891 * @dir: the new path
893 * Changes the working directory
894 * [Input-Output]
896 /** integer = chdir(dir); */
897 static mpdm_t F_chdir(mpdm_t a) {
898 return MPDM_I(mpdm_chdir(A0));
902 * sscanf - Extracts data like sscanf().
903 * @fmt: the string format
904 * @str: the string to be parsed
905 * @offset: the character offset to start scanning
907 * Extracts data from a string using a special format pattern, very
908 * much like the scanf() series of functions in the C library. Apart
909 * from the standard percent-sign-commands (s, u, d, i, f, x,
910 * n, [, with optional size and * to ignore), it implements S,
911 * to match a string of characters upto what follows in the format
912 * string. Also, the [ set of characters can include other % formats.
914 * Returns an array with the extracted values. If %n is used, the
915 * position in the scanned string is returned as the value.
916 * [Strings]
918 /** array = sscanf(fmt, str); */
919 /** array = sscanf(fmt, str, offset); */
920 static mpdm_t F_sscanf(mpdm_t a) {
921 return mpdm_sscanf(A0, A1, IA2);
925 * eval - Evaluates MSPL code.
926 * @code: A value containing a string of MPSL code, or executable code
927 * @args: optional arguments for @code
929 * Evaluates a piece of code. The @code can be a string containing MPSL
930 * source code (that will be compiled) or a direct executable value. If
931 * the compilation or the execution gives an error, the `ERROR' variable
932 * will be set to a printable value and NULL returned. Otherwise, the
933 * exit value from the code is returned and `ERROR' set to NULL. The
934 * internal abort flag is reset on exit.
936 * [Code Control]
938 /** v = eval(code, args); */
939 static mpdm_t F_eval(mpdm_t a)
941 mpdm_t r, c;
943 a = mpdm_ref(mpdm_clone(a));
944 c = mpdm_shift(a);
946 r = mpsl_eval(c, a);
948 mpdm_unref(a);
950 return r;
955 * sprintf - Formats a sprintf()-like string.
956 * @fmt: the string format
957 * @arg1: first argument
958 * @arg2: second argument
959 * @argn: nth argument
961 * Formats a string using the sprintf() format taking the values from
962 * the variable arguments.
963 * [Strings]
965 /** string = sprintf(fmt, arg1 [,arg2 ... argn]); */
966 static mpdm_t F_sprintf(mpdm_t a)
968 mpdm_t f, v, r;
970 a = mpdm_ref(mpdm_clone(a));
971 f = mpdm_shift(a);
973 /* if the first argument is an array, take it as the arguments */
974 if ((v = mpdm_aget(a, 0)) != NULL && MPDM_IS_ARRAY(v))
975 a = v;
977 r = mpdm_sprintf(f, a);
979 mpdm_unref(a);
981 return r;
986 * print - Writes values to stdout.
987 * @arg1: first argument
988 * @arg2: second argument
989 * @argn: nth argument
991 * Writes the variable arguments to stdout.
992 * [Input-Output]
994 /** print(arg1 [,arg2 ... argn]); */
995 static mpdm_t F_print(mpdm_t a)
997 int n;
999 for (n = 0; n < mpdm_size(a); n++)
1000 mpdm_write_wcs(stdout, mpdm_string(A(n)));
1001 return NULL;
1006 * write - Writes values to a file descriptor.
1007 * @fd: the file descriptor
1008 * @arg1: first argument
1009 * @arg2: second argument
1010 * @argn: nth argument
1012 * Writes the variable arguments to the file descriptor, doing
1013 * charset conversion in the process.
1015 * Returns the total size written to @fd.
1016 * [Input-Output]
1017 * [Character Set Conversion]
1019 /** integer = write(fd, arg1 [,arg2 ... argn]); */
1020 static mpdm_t F_write(mpdm_t a)
1022 int n, r = 0;
1024 for (n = 1; n < mpdm_size(a); n++)
1025 r += mpdm_write(A0, A(n));
1027 return MPDM_I(r);
1032 * chr - Returns the Unicode character represented by the codepoint.
1033 * @c: the codepoint as an integer value
1035 * Returns a 1 character string containing the character which
1036 * Unicode codepoint is @c.
1037 * [Strings]
1039 /** string = chr(c); */
1040 static mpdm_t F_chr(mpdm_t a)
1042 wchar_t tmp[2];
1044 tmp[0] = (wchar_t) mpdm_ival(mpdm_aget(a, 0));
1045 tmp[1] = L'\0';
1047 return MPDM_S(tmp);
1052 * ord - Returns the Unicode codepoint of a character.
1053 * @str: the string
1055 * Returns the Unicode codepoint for the first character in
1056 * the string.
1057 * [Strings]
1059 /** integer = ord(str); */
1060 static mpdm_t F_ord(mpdm_t a)
1062 int ret = 0;
1063 mpdm_t v = mpdm_aget(a, 0);
1065 if (v != NULL) {
1066 wchar_t * ptr = mpdm_string(v);
1067 ret = (int) *ptr;
1070 return MPDM_I(ret);
1075 * map - Maps an array into another.
1076 * @filter: the filter
1077 * @a: the array
1079 * Returns a new array built by applying the @filter to all the
1080 * elements of the array @a. The filter can be an executable function
1081 * accepting one argument, in which case the return value of the function
1082 * will be used as the output element; @filt can also be a hash, in which
1083 * case the original element will be used as a key to the hash and the
1084 * associated value used as the output element.
1086 * [Arrays]
1088 /** array = map(filter, a); */
1089 static mpdm_t F_map(mpdm_t a)
1091 mpdm_t key = mpdm_aget(a, 0);
1092 mpdm_t set = mpdm_aget(a, 1);
1093 mpdm_t out;
1095 /* map NULL to NULL */
1096 if (set == NULL)
1097 return NULL;
1099 out = mpdm_ref(MPDM_A(mpdm_size(set)));
1101 if (MPDM_IS_EXEC(key)) {
1102 int n;
1104 /* executes the code using the element as argument
1105 and stores the result in the output array */
1106 for (n = 0; n < mpdm_size(set); n++)
1107 mpdm_aset(out, mpdm_exec_1(key, mpdm_aget(set, n)), n);
1109 else
1110 if(MPDM_IS_HASH(key)) {
1111 int n;
1113 /* maps each value using the element as key */
1114 for (n = 0; n < mpdm_size(set); n++)
1115 mpdm_aset(out, mpdm_hget(key, mpdm_aget(set, n)), n);
1118 return mpdm_unref(out);
1123 * grep - Greps inside an array.
1124 * @filter: the filter
1125 * @a: the array
1127 * Greps inside an array and returns another one containing only the
1128 * elements that passed the filter. If @filter is a string, it's accepted
1129 * as a regular expression, which will be applied to each element.
1130 * If @filter is executable, it will be called with the element as its
1131 * only argument and its return value used as validation.
1133 * The new array will contain all elements that passed the filter.
1134 * [Arrays]
1135 * [Regular Expressions]
1137 /** array = grep(filter, a); */
1138 static mpdm_t F_grep(mpdm_t a)
1140 mpdm_t key = mpdm_aget(a, 0);
1141 mpdm_t set = mpdm_aget(a, 1);
1142 mpdm_t out = mpdm_ref(MPDM_A(0));
1144 if (MPDM_IS_EXEC(key)) {
1145 int n;
1147 /* it's executable */
1148 for (n = 0; n < mpdm_size(set); n++) {
1149 mpdm_t v = mpdm_aget(set, n);
1151 if (mpsl_is_true(mpdm_exec_1(key, v)))
1152 mpdm_push(out, v);
1155 else
1156 if(key->flags & MPDM_STRING) {
1157 int n;
1159 /* it's a string; use it as a regular expression */
1160 for (n = 0; n < mpdm_size(set); n++) {
1161 mpdm_t v = mpdm_aget(set, n);
1163 if (mpdm_regex(key, v, 0))
1164 mpdm_push(out, v);
1168 return mpdm_size(mpdm_unref(out)) == 0 ? NULL : out;
1171 static mpdm_t F_getenv(mpdm_t a)
1173 mpdm_t e = mpdm_hget_s(mpdm_root(), L"ENV");
1175 return mpdm_hget(e, mpdm_aget(a, 0));
1178 static mpdm_t F_bincall(mpdm_t a) {
1179 return MPDM_X(mpdm_ival(mpdm_aget(a, 0)));
1183 * random - Returns a random value.
1185 * Returns a random number from 0 to value - 1.
1186 * [Miscellaneous]
1188 /** integer = random(value); */
1189 static mpdm_t F_random(mpdm_t a) {
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);
1205 static struct {
1206 wchar_t * name;
1207 mpdm_t (* func)(mpdm_t);
1208 } mpsl_funcs[] = {
1209 { L"size", F_size },
1210 { L"clone", F_clone },
1211 { L"dump", F_dump },
1212 { L"dumper", F_dumper },
1213 { L"cmp", F_cmp },
1214 { L"is_array", F_is_array },
1215 { L"is_hash", F_is_hash },
1216 { L"is_exec", F_is_exec },
1217 { L"splice", F_splice },
1218 { L"expand", F_expand },
1219 { L"collapse", F_collapse },
1220 { L"ins", F_ins },
1221 { L"adel", F_adel },
1222 { L"shift", F_shift },
1223 { L"push", F_push },
1224 { L"pop", F_pop },
1225 { L"queue", F_queue },
1226 { L"seek", F_seek },
1227 { L"sort", F_sort },
1228 { L"split", F_split },
1229 { L"join", F_join },
1230 { L"hsize", F_hsize },
1231 { L"exists", F_exists },
1232 { L"hdel", F_hdel },
1233 { L"keys", F_keys },
1234 { L"open", F_open },
1235 { L"close", F_close },
1236 { L"read", F_read },
1237 { L"write", F_write },
1238 { L"getchar", F_getchar },
1239 { L"putchar", F_putchar },
1240 { L"fseek", F_fseek },
1241 { L"ftell", F_ftell },
1242 { L"unlink", F_unlink },
1243 { L"stat", F_stat },
1244 { L"chmod", F_chmod },
1245 { L"chown", F_chown },
1246 { L"glob", F_glob },
1247 { L"encoding", F_encoding },
1248 { L"popen", F_popen },
1249 { L"pclose", F_pclose },
1250 { L"regex", F_regex },
1251 { L"sregex", F_sregex },
1252 { L"load", F_load },
1253 { L"compile", F_compile },
1254 { L"error", F_error },
1255 { L"eval", F_eval },
1256 { L"print", F_print },
1257 { L"gettext", F_gettext },
1258 { L"gettext_domain", F_gettext_domain },
1259 { L"sprintf", F_sprintf },
1260 { L"sweep", F_sweep },
1261 { L"chr", F_chr },
1262 { L"ord", F_ord },
1263 { L"map", F_map },
1264 { L"grep", F_grep },
1265 { L"getenv", F_getenv },
1266 { L"uc", F_uc },
1267 { L"lc", F_lc },
1268 { L"time", F_time },
1269 { L"chdir", F_chdir },
1270 { L"sscanf", F_sscanf },
1271 { L"bincall", F_bincall },
1272 { L"random", F_random },
1273 { NULL, NULL }
1277 mpdm_t mpsl_build_funcs(void)
1278 /* build all functions */
1280 mpdm_t c;
1281 int n;
1283 /* creates all the symbols in the CORE library */
1284 c = MPDM_H(0);
1285 for (n = 0; mpsl_funcs[n].name != NULL; n++) {
1286 mpdm_t f = MPDM_S(mpsl_funcs[n].name);
1287 mpdm_t x = MPDM_X(mpsl_funcs[n].func);
1289 mpdm_hset(mpdm_root(), f, x);
1290 mpdm_hset(c, f, x);
1293 return c;