use --WORLD as root of all actions (GC just deletes --WORLD)
[mala.git] / engine / engine.c
blob0803115db31b90a3fb2802468f4dc451b5a58692
1 /*
2 engine.c - MaLa core engine
4 Copyright (C) 2004, Christian Thaeter <chth@gmx.net>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, contact me.
20 #include <stdlib.h>
21 #include <ctype.h>
22 #include <stdio.h>
23 #include "mala_types.h"
24 #include "engine.h"
25 #include "actiondesc.h"
26 #include "action.h"
27 #include "stringlist.h"
28 #include "std/std.h"
31 #define MALA_EXPAND(e,S) S
32 static const char * mala_common_strings [] = MALA_COMMON_STRINGS;
33 #undef MALA_EXPAND
35 #define MALA_STATE(s) #s
36 const char * mala_engine_states [] = {MALA_STATES};
37 #undef MALA_STATE
41 * function definitions
44 MalaEngine
45 mala_engine_new ()
47 MalaEngine self;
48 int i;
50 self = malloc (sizeof(mala_engine));
51 if (!self)
52 return NULL;
54 self->negated = 0;
55 self->engine_trace = MALA_NOTRACE;
56 self->blockcnt = 0;
58 self->state = MALA_CONTINUE;
60 mala_stringbucket_init (&self->words, MALA_STRING_FWD, (void(*)(void*)) mala_actiondesc_free);
62 self->gc_trace = &self->words.gc_trace;
64 mala_engine_add_action_cstr (self, "--WORLD", NULL, NULL, NULL, NULL);
66 for (i = 0; i < MALA_STRING_MAX; ++i)
68 self->common_string[i] = mala_string_new (mala_common_strings[i], &self->words);
69 if (!self->common_string[i])
70 goto ealloc_strings;
73 mala_stringlist_init (&self->program);
74 mala_stringlist_init (&self->arguments);
76 return self;
78 ealloc_strings:
79 while (--i >= 0)
80 mala_string_free (self->common_string[i]);
81 free (self);
82 return NULL;
85 #if 0
86 MalaEngine
87 mala_engine_new_main (int (*initfunc) (MalaEngine),
88 int argc, char **argv,
89 mala_actioninit * actions_init)
91 /*TODO convinience function*/
93 #endif
95 int
96 mala_engine_ppexpand_define (MalaEngine self, const char * name, int argc, char ** argv)
98 int i;
99 MalaStringList list;
100 MalaStringListNode itr;
101 mala_stringlist pre;
103 if (mala_engine_state_get (self) > MALA_EFAULT)
104 return mala_engine_state_get (self);
106 mala_stringlist_init (&pre);
108 for (i = 0; i != argc && *argv; ++i ,++argv)
110 if (!mala_stringlist_tail_new_cstr (&pre, *argv, &self->words))
111 goto ealloc_node;
114 list = mala_stringlist_new ();
115 if (!list)
116 goto ealloc_list;
118 /*TODO preprocess in own function*/
119 while (!mala_stringlist_is_empty (&pre))
121 int putaway;
123 itr = mala_stringlist_head (&pre);
125 putaway = mala_engine_ppexpand (self, &pre, &itr);
127 if (self->state > MALA_EFAULT)
128 return self->state;
130 while (putaway--)
132 mala_stringlist_node_remove (&pre, itr);
133 mala_stringlist_tail_insert (list, itr);
134 if (putaway && mala_stringlist_is_empty (&pre))
135 goto eunderrun;
136 itr = mala_stringlist_head (&pre);
140 if (mala_stringlist_is_empty (list))
142 mala_stringlist_free (list);
143 return mala_engine_add_action_cstr (self, name,
144 mala_string_copy (self->common_string[MALA_STRING_PASS]),
145 mala_substitute_parser,
146 (MalaDataFactory)mala_string_factory,
147 mala_action_get_cstr (&self->words, "--WORLD"));
150 if (mala_stringlist_is_tail (list, mala_stringlist_head (list)))
152 /* substitute */
153 MalaString subst;
155 subst = mala_string_copy (mala_stringlist_head (list) -> string);
156 mala_stringlist_free (list);
158 return mala_engine_add_action_cstr (self, name, subst,
159 mala_substitute_parser,
160 (MalaDataFactory)mala_string_factory,
161 mala_action_get_cstr (&self->words, "--WORLD"));
163 else
165 /* expand */
166 return mala_engine_add_action_cstr (self, name, list,
167 mala_expand_parser,
168 (MalaDataFactory) mala_stringlist_factory,
169 mala_action_get_cstr (&self->words, "--WORLD"));
172 eunderrun:
173 mala_stringlist_free (list);
174 mala_stringlist_erase (&pre);
175 return self->state = MALA_ESYNTAX;
177 ealloc_list:
178 ealloc_node:
179 mala_stringlist_erase (&pre);
180 return self->state = MALA_EALLOC;
184 mala_engine_pushback_word (MalaEngine self, const char * word)
186 if (mala_engine_state_get (self) > MALA_EFAULT)
187 return mala_engine_state_get (self);
189 if (!mala_stringlist_tail_new_cstr (&self->program, word, &self->words))
190 return self->state = MALA_EALLOC;
192 return MALA_SUCCESS;
196 mala_engine_add_action_cstr (MalaEngine self, const char * cname, void * data,
197 MalaParserFunc parser, MalaDataFactory factory,
198 MalaAction parent)
200 MalaString name;
201 MalaAction action;
203 if (mala_engine_state_get (self) > MALA_EFAULT)
204 return mala_engine_state_get (self);
206 name = mala_string_new (cname, &self->words);
207 if (!name)
208 goto ealloc_name;
210 action = mala_action_new (name, data, parser, factory, parent);
211 if (!action)
212 goto ealloc_action;
214 if (mala_action_attach (action) != MALA_SUCCESS)
215 goto ealloc_attach;
217 mala_string_free (name);
218 return MALA_SUCCESS;
220 ealloc_attach:
221 mala_action_free (action);
222 ealloc_action:
223 mala_string_free (name);
224 ealloc_name:
225 return self->state = MALA_EALLOC;
229 mala_engine_add_action (MalaEngine self, MalaString name, void * data,
230 MalaParserFunc parser, MalaDataFactory factory,
231 MalaAction parent)
233 MalaAction action;
235 if (mala_engine_state_get (self) > MALA_EFAULT)
236 return mala_engine_state_get (self);
238 action = mala_action_new (name, data, parser, factory,
239 parent?parent:mala_action_get_cstr (&self->words, "--WORLD"));
240 if (!action)
241 goto ealloc_action;
243 if (mala_action_attach (action) != MALA_SUCCESS)
244 goto ealloc_attach;
246 return MALA_SUCCESS;
248 ealloc_attach:
249 mala_action_free (action);
250 ealloc_action:
251 return self->state = MALA_EALLOC;
255 MalaEngine
256 mala_engine_new_initfunc (int (*initfunc)(MalaEngine))
258 MalaEngine self;
260 self = mala_engine_new ();
261 if (!self)
262 return NULL;
264 self->state = initfunc (self);
265 return self;
268 void
269 mala_engine_free (MalaEngine self)
271 if (!self)
272 return;
274 if (self->words.gc_trace > MALA_NOTRACE)
275 fprintf (stderr ,"GC: engine free, program\n");
277 mala_stringlist_erase (&self->program);
279 if (self->words.gc_trace > MALA_NOTRACE)
280 fprintf (stderr ,"GC: engine free, arguments\n");
282 mala_stringlist_erase (&self->arguments);
284 if (self->words.gc_trace > MALA_NOTRACE)
285 fprintf (stderr ,"GC: engine free world\n");
287 /*TODO direct pointer top of the worlds*/
288 mala_action_free (mala_action_get_cstr (&self->words, "--WORLD"));
290 if (self->words.gc_trace > MALA_NOTRACE)
291 fprintf (stderr ,"GC: engine free, bucket\n");
293 mala_stringbucket_erase (&self->words);
295 free (self);
299 mala_engine_actions_register (MalaEngine self, mala_actioninit * actioninit)
301 MalaAction action;
303 if (mala_engine_state_get (self) > MALA_EFAULT)
304 return mala_engine_state_get (self);
306 while (actioninit->command)
308 action = mala_action_new_actioninit (actioninit, self);
309 if (!action)
310 goto ealloc;
312 if (mala_action_attach (action) != MALA_SUCCESS)
313 goto ealloc;
315 ++actioninit;
318 return MALA_SUCCESS;
320 ealloc:
321 return self->state = MALA_EINIT;
325 /*TODO make some inlines { */
327 MalaStringList
328 mala_engine_getprogram (MalaEngine self)
330 if (mala_engine_state_get (self) > MALA_EFAULT)
331 return NULL;
333 return &self->program;
336 mala_state
337 mala_engine_state_get (MalaEngine self)
339 return self ? self->state : MALA_EINVALID;
342 const char *
343 mala_engine_state_str (MalaEngine self)
345 return mala_engine_states [self ? self->state : MALA_EINVALID];
348 void
349 mala_engine_clearstate (MalaEngine self)
351 if (self)
352 self->state = MALA_SUCCESS;
356 mala_engine_negated (MalaEngine self)
358 return self ? self->negated : -1;
361 void
362 mala_engine_clear_negated (MalaEngine self)
364 if (mala_engine_state_get (self) > MALA_EFAULT)
365 return;
366 self->negated = 0;
368 /* } TODO make some inlines */
371 void
372 mala_engine_dumpprogram (MalaEngine self, FILE* stream, const char * prefix, const char * suffix)
374 MalaStringListNode node;
376 if (!self)
377 return;
379 for (node = mala_stringlist_head (&self->program);
380 node != (void *)&self->program;
381 mala_stringlistnode_fwd (&node))
383 fprintf (stream, "%s%s%s", prefix, mala_string_cstr (node->string), suffix);
387 void
388 mala_engine_dumpargs (MalaEngine self, FILE* stream, const char * prefix, const char * suffix)
390 MalaStringListNode node;
392 if (!self)
393 return;
395 for (node = mala_stringlist_head (&self->arguments);
396 node != (void *)&self->arguments;
397 mala_stringlistnode_fwd (&node))
399 fprintf (stream, "%s%s%s", prefix, mala_string_cstr (node->string), suffix);
404 MalaEngine
405 mala_engine_run (MalaEngine self)
407 MalaStringListNode pptr;
409 if (mala_engine_state_get (self) > MALA_EFAULT)
410 return NULL;
412 if (self->words.gc_trace > MALA_NOTRACE)
413 fprintf (stderr ,"GC: engine run\n");
415 while (self->state < MALA_EFAULT &&
416 (pptr = mala_stringlist_head (&self->program)) != (void *)&self->program)
418 if (self->state == MALA_LITERAL)
420 self->state = mala_engine_string_istrue (self,
421 mala_stringlistnode_string (pptr))
422 ? MALA_SUCCESS
423 : MALA_FAILURE;
424 mala_stringlist_elem_remove (&self->program, pptr);
425 mala_stringlist_tail_insert (&self->arguments, pptr);
427 else
428 mala_engine_eval (self, &pptr);
430 return self;
433 MalaEngine
434 mala_engine_step (MalaEngine self)
436 MalaStringListNode pptr;
438 pptr = mala_stringlist_head (&self->program);
440 mala_engine_eval (self, &pptr);
442 while (pptr->string == self->common_string[MALA_STRING_PASS])
443 mala_engine_eval (self, &pptr);
445 return self;
449 mala_engine_eval (MalaEngine self, MalaStringListNode_ref pptr)
451 MalaAction act;
452 MalaActionDesc desc;
453 int state = MALA_SUCCESS;
455 if (self->engine_trace && (*pptr)->string != self->common_string[MALA_STRING_PASS])
457 fprintf (stderr, "%-8s: ", mala_engine_state_str (self));
458 mala_engine_dumpprogram (self, stderr, "", " ");
459 fprintf (stderr, "\n");
462 desc = (MalaActionDesc) mala_string_user_get ((*pptr)->string);
463 if (!desc)
464 goto def_parser;
466 act = mala_actiondesc_top (desc);
468 if (act)
470 state = mala_action_execute (act, pptr, self);
471 if (self->state != MALA_REMOVE)
472 self->state = state;
474 else
476 def_parser:
477 if (self->state != MALA_REMOVE)
479 #if 0 /*TODO*/
480 if (!(*pptr = mala_stringlist_before_new (&self->program,
481 *pptr,
482 self->common_string[MALA_STRING_DEFAULT_PARSER])))
483 return self->state = state = MALA_EALLOC;
484 #endif
485 self->state = MALA_LITERAL;
487 else
488 mala_stringlistnode_substitute_string (*pptr, self->common_string[MALA_STRING_DEFAULT_PARSER]);
491 if (self->state == MALA_EXCEPTION)
492 self->state = state = MALA_ENOACTION;
494 return state;
498 Evaluate the nth argument until the resulting state is less or equal
499 final_state or greater or equal to MALA_EXCEPTION
501 MalaStringListNode
502 mala_engine_arg_eval (MalaEngine self,
503 MalaStringListNode_ref pptr,
504 unsigned nth,
505 int final_state)
507 MalaStringListNode next;
509 if (mala_engine_state_get (self) > MALA_EFAULT)
510 return NULL;
512 for (next = *pptr;
513 nth && !mala_stringlist_is_tail (&self->program, next);
514 mala_stringlistnode_fwd (&next), --nth);
516 if (nth)
517 goto eend;
519 if (self->state == MALA_REMOVE)
521 mala_engine_eval (self, &next);
523 else
525 self->state = MALA_CONTINUE;
527 while (self->state > final_state && self->state < MALA_EXCEPTION)
529 mala_engine_eval (self, &next);
530 if (mala_stringlist_is_end (&self->program, next))
531 goto eend;
535 return next;
537 eend:
538 mala_engine_exception (self, pptr, mala_stringlist_tail (&self->program),
539 self->common_string[MALA_STRING_ERROR_MISSING_ARGUMENT]);
540 return NULL;
543 #if 0
545 Evaluate the nth argument until one of the following happens
546 - for at most 'times' (-1 for full evaluation)
547 - until we reach a final state MALA_SUCCESS, MALA_FAILURE or MALA_LITERAL
548 - an error/exception is flagged
549 - the type associated with the data of the current word equals to 'type'
551 MalaStringListNode
552 mala_engine_arg_eval (MalaEngine self,
553 MalaStringListNode_ref pptr,
554 unsigned nth,
555 int times,
556 MalaDataFactory type,
557 MalaParserFunc parser)
559 MalaAction act;
560 MalaStringListNode next;
562 if (mala_engine_state_get (self) > MALA_EFAULT)
563 return NULL;
565 for (next = *pptr;
566 nth && !mala_stringlist_is_tail (&self->program, next);
567 mala_stringlistnode_fwd (&next), --nth);
569 if (nth)
570 goto eend;
572 if (self->state == MALA_REMOVE)
574 act = mala_actiondesc_top ((MalaActionDesc) mala_string_user_get (next->string));
575 mala_engine_eval (self, &next);
577 else
579 self->state = MALA_CONTINUE;
581 act = mala_actiondesc_top ((MalaActionDesc) mala_string_user_get (next->string));
582 while (self->state == MALA_CONTINUE
583 && times--
584 && ((act && type) ? (act->factory != type) : 1)
585 && ((act && parser) ? (act->parser != parser) : 1))
587 mala_engine_eval (self, &next);
588 if (mala_stringlist_is_end (&self->program, next))
589 goto eend;
590 act = mala_actiondesc_top ((MalaActionDesc) mala_string_user_get (next->string));
594 return next;
596 eend:
597 mala_engine_exception (self, pptr, mala_stringlist_tail (&self->program),
598 self->common_string[MALA_STRING_ERROR_MISSING_ARGUMENT]);
599 return NULL;
601 #endif
604 mala_engine_arg_eval_fmt (MalaEngine self,
605 MalaStringListNode_ref pptr,
606 unsigned nth,
607 const char* fmt,
608 void * dest,
609 MalaPredicate pred,
610 void * constraint)
612 MalaStringListNode node;
613 int r;
615 node = mala_engine_arg_eval (self, pptr, nth, MALA_LITERAL);
617 if (self->state != MALA_EXCEPTION)
619 r = mala_string_scan (mala_stringlistnode_string (node), fmt, dest);
620 if (r == 1 && pred)
621 r = pred (dest, constraint);
622 if (!r)
623 return mala_engine_exception (self, pptr, node,
624 self->common_string[MALA_STRING_ERROR_WRONG_TYPE]);
627 return self->state;
630 MalaString
631 mala_engine_arg_eval_string (MalaEngine self,
632 MalaStringListNode_ref pptr,
633 unsigned nth,
634 MalaPredicate pred,
635 void * constraint)
637 MalaString string;
639 string = mala_stringlistnode_string (mala_engine_arg_eval (self, pptr, nth, MALA_LITERAL));
641 if (self->state >= MALA_EXCEPTION || ! (pred ? pred (string, constraint) : 1))
642 return NULL;
644 return string;
648 void
649 mala_engine_command_done (MalaEngine eng, MalaStringListNode_ref pptr, int args)
651 mala_stringlistnode_substitute_string (*pptr, eng->common_string[MALA_STRING_PASS]);
652 while (args--)
654 mala_stringlist_elem_delete (&eng->program, mala_stringlistnode_next (*pptr));
660 mala_engine_exception (MalaEngine self,
661 MalaStringListNode_ref pptr,
662 MalaStringListNode here,
663 MalaString except)
665 MalaStringListNode tmp;
667 if (mala_engine_state_get (self) > MALA_EFAULT)
668 return mala_engine_state_get (self);
670 tmp = mala_stringlist_before_new (&self->program, *pptr, except);
671 if (!tmp)
672 return self->state = MALA_EALLOC;
674 if (!mala_stringlist_after_new (&self->program, here,
675 self->common_string[MALA_STRING_HERE]))
676 return self->state = MALA_EALLOC;
678 *pptr = tmp;
680 /*TODO self-state needs to be preserved somehow?*/
681 return self->state = MALA_EXCEPTION;
686 mala_engine_ppexpand (MalaEngine self, MalaStringList list, MalaStringListNode_ref pptr)
688 int ret = 0;
690 if (self->state > MALA_EFAULT)
691 return MALA_EXPANSION_ERROR;
693 #define mala_run_expansion(name) \
694 if (MALA_NO_EXPANSION != (ret = mala_engine_##name (self, list, pptr))) return ret
696 mala_run_expansion (literal_expansion);
697 mala_run_expansion (numsplit_expansion);
698 mala_run_expansion (exclam_expansion);
699 mala_run_expansion (no_expansion);
700 mala_run_expansion (assign_expansion);
701 mala_run_expansion (char_expansion);
702 mala_run_expansion (underscore_expansion);
703 mala_run_expansion (bracket_expansion);
704 mala_run_expansion (assign_contraction);
705 mala_run_expansion (envvar_expansion);
706 mala_run_expansion (setenv_expansion);
707 mala_run_expansion (backquote_expansion);
708 #undef mala_run_expansion
710 return 1;
714 mala_engine_literal_expansion (MalaEngine self,
715 MalaStringList list,
716 MalaStringListNode_ref pptr)
718 if (mala_engine_check_expansionflag (self, MALA_STRING_FLAG_LITERAL_EXPANSION)
719 && mala_string_check_prefix ((*pptr)->string, "`")
720 && !mala_string_check_prefix ((*pptr)->string, "``"))
722 MalaString nstr;
723 MalaStringListNode newnode1;
724 MalaStringListNode newnode2;
726 newnode1 = mala_stringlist_after_new (list,
727 *pptr,
728 self->common_string[MALA_STRING_LITERAL]);
729 if (!newnode1)
730 goto ealloc_newnode1;
732 nstr = mala_string_new_substr ((*pptr)->string, 1, SIZE_MAX);
733 newnode2 = mala_stringlist_after_new (list, newnode1, nstr);
734 if (!newnode2)
735 goto ealloc_newnode2;
737 mala_stringlist_elem_delete (list, *pptr);
738 *pptr = newnode1;
740 return 2;
742 ealloc_newnode2:
743 mala_stringlist_elem_delete (list, newnode1);
744 ealloc_newnode1:
745 self->state = MALA_EALLOC;
746 return MALA_EXPANSION_ERROR;
748 return MALA_NO_EXPANSION;
753 mala_engine_backquote_expansion (MalaEngine self, MalaStringList list, MalaStringListNode_ref pptr)
755 if (mala_engine_check_expansionflag (self, MALA_STRING_FLAG_LITERAL_EXPANSION)
756 && mala_string_check_prefix ((*pptr)->string, "``"))
758 MalaString nstr;
759 MalaStringListNode newnode;
761 nstr = mala_string_new_substr ((*pptr)->string, 1, SIZE_MAX);
762 newnode = mala_stringlist_after_new (list, *pptr, nstr);
763 if (!newnode)
764 goto ealloc_newnode;
766 mala_stringlist_elem_delete (list, *pptr);
767 *pptr = newnode;
769 return 1;
771 ealloc_newnode:
772 self->state = MALA_EALLOC;
773 return MALA_EXPANSION_ERROR;
775 return MALA_NO_EXPANSION;
779 mala_engine_numsplit_expansion (MalaEngine self, MalaStringList list, MalaStringListNode_ref pptr)
781 if (mala_engine_check_expansionflag (self, MALA_STRING_FLAG_NUMSPLIT_EXPANSION)
782 && mala_string_length ((*pptr)->string) > 2
783 && mala_string_at ((*pptr)->string, 0) == '-'
784 && isalpha (mala_string_at ((*pptr)->string, 1))
787 size_t i;
789 for (i = 2; i < mala_string_length ((*pptr)->string); ++i)
791 if (isdigit (mala_string_at ((*pptr)->string, i)))
793 MalaString a;
794 MalaString b;
796 MalaStringListNode na;
797 MalaStringListNode nb;
799 a = mala_string_new_substr ((*pptr)->string, 0, i);
800 b = mala_string_new_substr ((*pptr)->string, i, SIZE_MAX);
801 if (!a || !b)
802 goto ealloc_str;
804 na = mala_stringlist_after_new (list, *pptr, a);
805 if (!na)
806 goto ealloc_nodea;
808 nb = mala_stringlist_after_new (list, na, b);
809 if (!nb)
810 goto ealloc_nodeb;
812 mala_stringlist_elem_delete (list, *pptr);
813 *pptr = na;
815 mala_string_free (a);
816 mala_string_free (b);
818 return 0;
820 ealloc_nodeb:
821 mala_stringlist_elem_delete (list, na);
822 ealloc_nodea:
823 ealloc_str:
824 mala_string_free (a);
825 mala_string_free (b);
826 self->state = MALA_EALLOC;
827 return MALA_EXPANSION_ERROR;
831 return MALA_NO_EXPANSION;
836 mala_engine_exclam_expansion (MalaEngine self, MalaStringList list, MalaStringListNode_ref pptr)
838 if (mala_engine_check_expansionflag (self, MALA_STRING_FLAG_EXCLAM_EXPANSION)
839 && mala_string_length ((*pptr)->string) == 1
840 && mala_string_same ((*pptr)->string, self->common_string[MALA_STRING_EXCLAMATIONMARK]))
842 MalaStringListNode newnode;
844 newnode = mala_stringlist_after_new (list,
845 *pptr,
846 self->common_string[MALA_STRING_NOT]);
847 if (!newnode)
848 return self->state = MALA_EALLOC;
850 mala_stringlist_elem_delete (list, *pptr);
851 *pptr= newnode;
852 return 1;
854 return MALA_NO_EXPANSION;
859 mala_engine_no_expansion (MalaEngine self, MalaStringList list, MalaStringListNode_ref pptr)
861 if (mala_engine_check_expansionflag (self, MALA_STRING_FLAG_NO_EXPANSION)
862 && mala_string_check_prefix_nocase ((*pptr)->string, "--NO-")
863 && mala_string_length ((*pptr)->string) >= sizeof ("--NO-"))
865 MalaString a;
866 MalaString aa;
867 MalaStringListNode n1;
868 MalaStringListNode n2;
870 a = mala_string_new_substr ((*pptr)->string, sizeof ("--NO-")-1, SIZE_MAX);
871 aa = mala_string_new_prefix ("--", a);
872 if (!a || !aa)
873 goto ealloc_a;
875 n1 = mala_stringlist_after_new (list,
876 *pptr, self->common_string[MALA_STRING_NOT]);
877 if (!n1)
878 goto ealloc_n1;
880 n2 = mala_stringlist_after_new (list, n1, aa);
881 if (!n2)
882 goto ealloc_n2;
884 mala_string_free (a);
885 mala_string_free (aa);
886 mala_stringlist_elem_delete (list, *pptr);
887 *pptr = n1;
888 return 1;
890 ealloc_n2:
891 mala_stringlist_elem_delete (list, n1);
892 ealloc_n1:
893 mala_string_free (a);
894 mala_string_free (aa);
895 ealloc_a:
896 self->state = MALA_EALLOC;
897 return MALA_EXPANSION_ERROR;
899 return MALA_NO_EXPANSION;
904 mala_engine_assign_expansion (MalaEngine self, MalaStringList list, MalaStringListNode_ref pptr)
906 size_t eq;
908 if (mala_engine_check_expansionflag (self, MALA_STRING_FLAG_ASSIGN_EXPANSION)
909 && mala_string_check_prefix ((*pptr)->string, "--")
910 && ((eq = mala_string_char_find ((*pptr)->string, '=')) != SIZE_MAX)
911 && mala_string_length ((*pptr)->string) > eq + 1)
913 MalaString a;
914 MalaString b;
916 MalaStringListNode na;
917 MalaStringListNode nb;
919 a = mala_string_new_substr ((*pptr)->string, 0, eq);
920 b = mala_string_new_substr ((*pptr)->string, eq + 1, SIZE_MAX);
921 if (!a || !b)
922 goto ealloc_str;
924 na = mala_stringlist_after_new (list, *pptr, a);
925 if (!na)
926 goto ealloc_nodea;
928 nb = mala_stringlist_after_new (list, na, b);
929 if (!nb)
930 goto ealloc_nodeb;
932 mala_stringlist_elem_delete (list, *pptr);
933 *pptr = na;
935 mala_string_free (a);
936 mala_string_free (b);
939 return 0;
941 ealloc_nodeb:
942 mala_stringlist_elem_delete (list, na);
943 ealloc_nodea:
944 ealloc_str:
945 mala_string_free (a);
946 mala_string_free (b);
947 self->state = MALA_EALLOC;
948 return MALA_EXPANSION_ERROR;
950 return MALA_NO_EXPANSION;
955 mala_engine_envvar_expansion (MalaEngine self, MalaStringList list, MalaStringListNode_ref pptr)
957 if (mala_engine_check_expansionflag (self, MALA_STRING_FLAG_ENVVAR_EXPANSION)
958 && (mala_string_char_find ((*pptr)->string, '$') != SIZE_MAX))
960 MalaStringListNode newnode;
962 newnode = mala_stringlist_before_new (list,
963 *pptr,
964 self->common_string[MALA_STRING_ENVSUBST]);
965 if (!newnode)
966 goto ealloc_node;
968 *pptr= newnode;
969 return 2;
971 ealloc_node:
972 self->state = MALA_EALLOC;
973 return MALA_EXPANSION_ERROR;
976 return MALA_NO_EXPANSION;
981 mala_engine_char_expansion (MalaEngine self, MalaStringList list, MalaStringListNode_ref pptr)
983 if (mala_engine_check_expansionflag (self, MALA_STRING_FLAG_CHAR_EXPANSION)
984 && mala_string_length ((*pptr)->string) > 2
985 && ( mala_string_at ((*pptr)->string, 0) == '-'
986 || mala_string_at ((*pptr)->string, 0) == '+')
987 && isalpha (mala_string_at ((*pptr)->string, 1)))
989 char prefix[2] = "-";
990 char current[2] = " ";
991 const char * i;
992 int cnt = 0;
994 MalaString str;
995 MalaStringListNode node = NULL;
996 MalaStringListNode pred = *pptr;
999 for (i = mala_string_cstr ((*pptr)->string); *i; ++i)
1001 if (*i == '-' || *i == '+')
1002 prefix[0] = *i;
1003 else if (isalpha (*i))
1005 ++cnt;
1006 current[0] = *i;
1007 str = mala_string_new_cat2 (prefix, current,
1008 mala_string_bucket_get ((*pptr)->string));
1009 if (!str)
1010 goto ealloc;
1012 node = mala_stringlist_after_new (list,
1013 pred, str);
1014 if (!node)
1015 goto ealloc;
1017 pred = node;
1018 mala_string_free (str);
1020 else
1021 break;
1024 pred = *pptr;
1025 mala_stringlistnode_fwd (&pred);
1026 mala_stringlist_elem_delete (list, *pptr);
1027 *pptr= pred;
1028 return cnt;
1030 ealloc:
1031 mala_string_free (str);
1032 /* cleanup from pred downto pptr */
1033 while (pred != *pptr)
1035 MalaStringListNode tmp = mala_stringlistnode_prev (pred);
1036 mala_stringlist_elem_delete (list, pred);
1037 pred = tmp;
1039 self->state = MALA_EALLOC;
1040 return MALA_EXPANSION_ERROR;
1042 return MALA_NO_EXPANSION;
1047 mala_engine_underscore_expansion (MalaEngine self, MalaStringList list, MalaStringListNode_ref pptr)
1049 if (mala_engine_check_expansionflag (self, MALA_STRING_FLAG_UNDERSCORE_EXPANSION)
1050 && mala_string_check_prefix ((*pptr)->string, "--")
1051 && strchr (mala_string_cstr ((*pptr)->string), '_'))
1053 MalaString str;
1054 MalaStringListNode node;
1055 char * cstr;
1056 char * i;
1058 cstr = strdup (mala_string_cstr ((*pptr)->string));
1059 if (!cstr)
1060 goto ealloc_cstr;
1062 for (i = cstr + 2; *i; ++i)
1064 if (*i == '_')
1065 *i = '-';
1068 str = mala_string_new (cstr, &self->words);
1069 if (!str)
1070 goto ealloc_str;
1072 node = mala_stringlist_after_new (list,
1073 *pptr,
1074 str);
1075 if (!node)
1076 goto ealloc_node;
1078 free (cstr);
1079 mala_string_free (str);
1081 mala_stringlist_elem_delete (list, *pptr);
1082 *pptr= node;
1083 return 0;
1085 ealloc_node:
1086 mala_string_free (str);
1087 ealloc_str:
1088 free (cstr);
1089 ealloc_cstr:
1090 self->state = MALA_EALLOC;
1091 return MALA_EXPANSION_ERROR;
1093 return MALA_NO_EXPANSION;
1098 mala_engine_setenv_expansion (MalaEngine self, MalaStringList list, MalaStringListNode_ref pptr)
1100 size_t eq;
1102 if (mala_engine_check_expansionflag (self, MALA_STRING_FLAG_SETENV_EXPANSION)
1103 && mala_string_length ((*pptr)->string) > 1
1104 && (eq = mala_string_char_find ((*pptr)->string, '='))
1105 && eq > 0
1106 && eq < SIZE_MAX
1107 && !mala_string_check_prefix ((*pptr)->string, "-"))
1109 MalaString key;
1110 MalaString value;
1111 MalaStringListNode n1;
1112 MalaStringListNode n2;
1113 MalaStringListNode n3;
1115 key = mala_string_new_substr ((*pptr)->string, 0, eq);
1116 if (!key)
1117 goto ealloc_key;
1119 value = mala_string_new_substr ((*pptr)->string, eq + 1, SIZE_MAX);
1120 if (!value)
1121 goto ealloc_value;
1123 n1 = mala_stringlist_after_new (list,
1124 *pptr, self->common_string[MALA_STRING_SETENV]);
1125 if (!n1)
1126 goto ealloc_n1;
1128 n2 = mala_stringlist_after_new (list, n1, key);
1129 if (!n2)
1130 goto ealloc_n2;
1132 n3 = mala_stringlist_after_new (list, n2, value);
1133 if (!n3)
1134 goto ealloc_n3;
1136 mala_string_free (key);
1137 mala_string_free (value);
1138 mala_stringlist_elem_delete (list, *pptr);
1139 *pptr = n1;
1140 return 3;
1142 ealloc_n3:
1143 mala_stringlist_elem_delete (list, n2);
1144 ealloc_n2:
1145 mala_stringlist_elem_delete (list, n1);
1146 ealloc_n1:
1147 mala_string_free (value);
1148 ealloc_value:
1149 mala_string_free (key);
1150 ealloc_key:
1151 self->state = MALA_EALLOC;
1152 return MALA_EXPANSION_ERROR;
1154 return MALA_NO_EXPANSION;
1159 mala_engine_bracket_expansion (MalaEngine self, MalaStringList list, MalaStringListNode_ref pptr)
1161 if (mala_engine_check_expansionflag (self, MALA_STRING_FLAG_BRACKET_EXPANSION)
1162 && mala_string_at ((*pptr)->string, 0) == '[')
1164 MalaStringListNode nitr;
1165 MalaStringListNode node;
1167 MalaString str1 = NULL;
1168 MalaStringListNode node1;
1170 MalaString str2 = NULL;
1171 MalaStringListNode node2;
1173 node = mala_stringlist_after_new (list, *pptr, self->common_string[MALA_STRING_SECTION]);
1174 if (!node)
1175 goto ealloc_node;
1177 if (mala_string_length((*pptr)->string) > 1)
1179 str1 = mala_string_new_substr ((*pptr)->string, 1, SIZE_MAX);
1180 node1 = mala_stringlist_after_new (list, node, str1);
1181 if (!node1)
1182 goto ealloc_node1;
1184 else
1186 node1 = node;
1187 mala_stringlistnode_fwd (&node1);
1190 for (nitr = node1; (void*)nitr != (void*)list; mala_stringlistnode_fwd (&nitr))
1192 if (mala_string_at (nitr->string, mala_string_length(nitr->string) - 1) == ']')
1193 break;
1196 if ((void*)nitr != (void*)list)
1198 if (mala_string_length(nitr->string) > 1)
1200 str2 = mala_string_new_substr (nitr->string, 0,
1201 mala_string_length(nitr->string) - 1);
1202 node2 = mala_stringlist_after_new (list, nitr, str2);
1203 if (!node2)
1204 goto ealloc_node2;
1207 else
1208 goto esyntax;
1211 mala_string_free (str1);
1212 mala_string_free (str2);
1213 mala_stringlist_elem_delete (list, *pptr);
1214 mala_stringlist_elem_delete (list, nitr);
1215 *pptr = node;
1217 return 0;
1219 esyntax:
1220 mala_string_free (str1);
1221 mala_stringlist_elem_delete (list, node1);
1222 mala_stringlist_elem_delete (list, node);
1223 self->state = MALA_ESYNTAX;
1224 return MALA_EXPANSION_ERROR;
1226 ealloc_node2:
1227 mala_string_free (str1);
1228 mala_stringlist_elem_delete (list, node1);
1229 ealloc_node1:
1230 mala_stringlist_elem_delete (list, node);
1231 ealloc_node:
1232 self->state = MALA_EALLOC;
1233 return MALA_EXPANSION_ERROR;
1235 return MALA_NO_EXPANSION;
1240 mala_engine_assign_contraction (MalaEngine self,
1241 MalaStringList list,
1242 MalaStringListNode_ref pptr)
1244 MalaStringListNode assign;
1245 MalaStringListNode value ;
1247 assign = *pptr;
1248 mala_stringlistnode_fwd (&assign);
1249 value = assign;
1251 if (mala_engine_check_expansionflag (self, MALA_STRING_FLAG_ASSIGN_CONTRACTION)
1252 && !mala_stringlist_is_tail (list, *pptr)
1253 && !mala_stringlist_is_tail (list, assign)
1254 && mala_string_same (assign->string, self->common_string[MALA_STRING_ASSIGN]))
1256 MalaString str;
1257 MalaStringListNode node;
1259 mala_stringlistnode_fwd (&value);
1261 str = mala_string_new_print (mala_string_bucket_get ((*pptr)->string),
1262 "%s=%s",
1263 mala_string_cstr ((*pptr)->string),
1264 mala_string_cstr (value->string));
1267 node = mala_stringlist_after_new (list,
1268 value,
1269 str);
1270 if (!node)
1271 goto ealloc_node;
1273 mala_string_free (str);
1274 mala_stringlist_elem_delete (list, *pptr);
1275 mala_stringlist_elem_delete (list, assign);
1276 mala_stringlist_elem_delete (list, value);
1277 *pptr = node;
1278 return 0;
1280 ealloc_node:
1281 mala_string_free (str);
1282 self->state = MALA_EALLOC;
1283 return MALA_EXPANSION_ERROR;
1285 return MALA_NO_EXPANSION;
1292 mala_engine_string_istrue (MalaEngine self, MalaString str)
1294 /*TODO check for other zero representations 0.0 0e0 etc.*/
1295 if (!str
1296 || !mala_string_compare (str, self->common_string[MALA_STRING_EMPTY])
1297 || !mala_string_compare (str, self->common_string[MALA_STRING_FALSE])
1298 || !mala_string_compare (str, self->common_string[MALA_STRING_ZERO]))
1299 return 0;
1301 return 1;
1305 mala_engine_check_expansionflag (MalaEngine self, int flag)
1307 MalaActionDesc desc;
1308 desc = (MalaActionDesc) mala_string_user_get (self->common_string[flag]);
1310 /*only enabled when the topmost action is a subtitution to --TRUE*/
1311 return mala_actiondesc_data_top (desc) == self->common_string[MALA_STRING_TRUE];
1326 #if 0 /*TODO*/
1328 mala_engine_erase_action (MalaEngine self, const t_uchar * key)
1330 MalaAction act;
1332 if (self->state > MALA_EFAULT)
1333 return self->state;
1335 act = mala_actiondict_lookupaction (self->actions, key);
1336 if (!act)
1337 goto enoact;
1339 mala_actiondict_destroy_action (self->actions, act);
1341 return MALA_SUCCESS;
1343 enoact:
1344 self->state = MALA_ENOACTION;
1345 return self->state;
1351 mala_engine_deepeval (MalaEngine self, MalaStringListNode_ref pptr)
1353 MalaStringListNode base = llist_get_prev (pptr);
1354 while (mala_engine_eval (self, llist_get_nextt (base)) < MALA_EVAL)
1355 if (llist_get_next (base) == &self->program)
1356 return MALA_ENOACTION;
1358 return self->state;
1363 void
1364 mala_engine_pusfront_program (MalaEngine self, int argc, char ** argv)
1366 self->state = mala_strlist_pushfront_cstrings (&self->program, argc, argv);
1372 mala_engine_argc (MalaEngine self)
1374 return llist_count (&self->arguments) + 1;
1377 const char*
1378 mala_engine_argv (MalaEngine self, int n)
1380 MalaStringListNode p;
1381 p = llist_get_next (&self->arguments);
1383 if (n==0)
1384 return self->argv_0;
1386 while (--n)
1388 if (p == &self->arguments)
1389 return 0;
1390 p = llist_get_next (p);
1392 return (const char *)(p)->data;
1397 MalaAction
1398 mala_engine_action_new (MalaEngine self, t_uchar** name, void** data,
1399 MalaParserFunc parser, MalaDataDestructor destructor)
1401 MalaAction act;
1403 act = mala_action_new (name, data, parser, destructor);
1404 if (!act)
1405 goto ealloc;
1407 self->state = mala_actiondict_push (self->actions, act);
1408 if (self->state)
1409 goto epush;
1411 return act;
1413 epush:
1414 mala_action_destroy (act);
1415 ealloc:
1416 return 0;
1420 mala_engine_check_expansionflag (MalaEngine self, const t_uchar * name)
1422 MalaAction act;
1424 act = mala_actiondict_lookupaction (self->actions, name);
1425 if (!act)
1426 return MALA_NO_EXPANSION;
1428 if (act->parser != mala_substitute_parser)
1429 return MALA_EPARSER;
1431 return mala_string_check ((t_uchar*) act->data);
1435 MalaAction
1436 mala_engine_getaction (MalaEngine self, const t_uchar * name)
1438 return mala_actiondict_lookupaction (self->actions, name);
1441 MalaAction
1442 mala_engine_getprevaction (MalaEngine self, const t_uchar * name)
1444 return mala_actiondict_lookupprevaction (self->actions, name);
1447 #endif /*TODO*/
1454 // Local Variables:
1455 // mode: C
1456 // c-file-style: "gnu"
1457 // End:
1458 // arch-tag: ece5489f-f703-4033-8cbc-efc1b0562100
1459 // end_of_file