File src/engine/parsing.c changed (mode: 100644) (index 9c8183155..7351e3d94) |
... |
... |
static var_t parse_doubly_quoted_string(parse_context_t *ctx, const char **in); |
178 |
178 |
static int parse_doubly_quoted_char(parse_context_t *ctx, const char **in, |
static int parse_doubly_quoted_char(parse_context_t *ctx, const char **in, |
179 |
179 |
sbuffer *sbuf); |
sbuffer *sbuf); |
180 |
180 |
static var_t eval_envvar(parse_context_t *ctx, const char **in); |
static var_t eval_envvar(parse_context_t *ctx, const char **in); |
181 |
|
static var_t eval_builtinvar(parse_context_t *ctx, const char **in); |
|
|
181 |
|
static var_t eval_var(parse_context_t *ctx, const char **in); |
182 |
182 |
static var_t eval_opt(parse_context_t *ctx, const char **in); |
static var_t eval_opt(parse_context_t *ctx, const char **in); |
183 |
183 |
static expr_t parse_logical_not(parse_context_t *ctx, const char **in); |
static expr_t parse_logical_not(parse_context_t *ctx, const char **in); |
184 |
184 |
static int parse_sequence(parse_context_t *ctx, const char **in, |
static int parse_sequence(parse_context_t *ctx, const char **in, |
|
... |
... |
parse_concat_expr(parse_context_t *ctx, const char **in) |
849 |
849 |
return result; |
return result; |
850 |
850 |
} |
} |
851 |
851 |
|
|
852 |
|
/* term ::= signed_number | number | sqstr | dqstr | envvar | builtinvar | |
|
853 |
|
* funccall | opt | logical_not | '(' or_expr ')' */ |
|
|
852 |
|
/* term ::= signed_number | number | sqstr | dqstr | envvar | var | funccall | |
|
853 |
|
* opt | logical_not | '(' or_expr ')' */ |
854 |
854 |
static expr_t |
static expr_t |
855 |
855 |
parse_term(parse_context_t *ctx, const char **in) |
parse_term(parse_context_t *ctx, const char **in) |
856 |
856 |
{ |
{ |
|
... |
... |
parse_term(parse_context_t *ctx, const char **in) |
909 |
909 |
{ |
{ |
910 |
910 |
if(**in == ':') |
if(**in == ':') |
911 |
911 |
{ |
{ |
912 |
|
result.value = eval_builtinvar(ctx, in); |
|
|
912 |
|
result.value = eval_var(ctx, in); |
913 |
913 |
} |
} |
914 |
914 |
else |
else |
915 |
915 |
{ |
{ |
|
... |
... |
eval_envvar(parse_context_t *ctx, const char **in) |
1132 |
1132 |
return var_from_str(getenv_fu(name)); |
return var_from_str(getenv_fu(name)); |
1133 |
1133 |
} |
} |
1134 |
1134 |
|
|
1135 |
|
/* builtinvar ::= 'v:' varname */ |
|
|
1135 |
|
/* var ::= 'g:' varname | 'v:' varname */ |
1136 |
1136 |
static var_t |
static var_t |
1137 |
|
eval_builtinvar(parse_context_t *ctx, const char **in) |
|
|
1137 |
|
eval_var(parse_context_t *ctx, const char **in) |
1138 |
1138 |
{ |
{ |
1139 |
1139 |
var_t var_value; |
var_t var_value; |
1140 |
|
char name[VAR_NAME_LENGTH_MAX + 1]; |
|
1141 |
|
strcpy(name, "v:"); |
|
1142 |
1140 |
|
|
1143 |
|
if(ctx->last_token.c != 'v' || **in != ':') |
|
|
1141 |
|
if(!ONE_OF(ctx->last_token.c, 'v', 'g') || **in != ':') |
1144 |
1142 |
{ |
{ |
1145 |
1143 |
ctx->last_error = PE_INVALID_EXPRESSION; |
ctx->last_error = PE_INVALID_EXPRESSION; |
1146 |
1144 |
return var_false(); |
return var_false(); |
1147 |
1145 |
} |
} |
1148 |
1146 |
|
|
|
1147 |
|
char name[VAR_NAME_LENGTH_MAX + 1]; |
|
1148 |
|
name[0] = ctx->last_token.c; |
|
1149 |
|
name[1] = ':'; |
|
1150 |
|
name[2] = '\0'; |
|
1151 |
|
|
1149 |
1152 |
get_next(ctx, in); |
get_next(ctx, in); |
1150 |
1153 |
get_next(ctx, in); |
get_next(ctx, in); |
1151 |
1154 |
|
|
File src/engine/variables.c changed (mode: 100644) (index 4d0da68bc..de24b9384) |
43 |
43 |
typedef enum |
typedef enum |
44 |
44 |
{ |
{ |
45 |
45 |
VT_ENVVAR, /* Environment variable. */ |
VT_ENVVAR, /* Environment variable. */ |
|
46 |
|
VT_GVAR, /* Global variable. */ |
46 |
47 |
VT_ANY_OPTION, /* Global and local options (if local exists). */ |
VT_ANY_OPTION, /* Global and local options (if local exists). */ |
47 |
48 |
VT_GLOBAL_OPTION, /* Global option. */ |
VT_GLOBAL_OPTION, /* Global option. */ |
48 |
49 |
VT_LOCAL_OPTION, /* Local option. */ |
VT_LOCAL_OPTION, /* Local option. */ |
|
... |
... |
VariableOperation; |
62 |
63 |
/* Description of a variable. */ |
/* Description of a variable. */ |
63 |
64 |
typedef struct |
typedef struct |
64 |
65 |
{ |
{ |
65 |
|
char *name; /* Name of the variable (including "v:" prefix). */ |
|
|
66 |
|
char *name; /* Name of the variable (including "[gv]:" prefix). */ |
66 |
67 |
var_t val; /* Current value of the variable. */ |
var_t val; /* Current value of the variable. */ |
67 |
68 |
} |
} |
68 |
69 |
var_info_t; |
var_info_t; |
|
... |
... |
static int parse_name(const char **in, const char first[], const char other[], |
91 |
92 |
size_t buf_len, char buf[]); |
size_t buf_len, char buf[]); |
92 |
93 |
static int is_valid_op(const char name[], VariableType vt, |
static int is_valid_op(const char name[], VariableType vt, |
93 |
94 |
VariableOperation vo); |
VariableOperation vo); |
94 |
|
static int perform_op(const char name[], VariableType vt, |
|
95 |
|
VariableOperation vo, const char value[]); |
|
|
95 |
|
static int perform_op(const char name[], VariableType vt, VariableOperation vo, |
|
96 |
|
var_t val, const char value[]); |
96 |
97 |
static void append_envvar(const char *name, const char *val); |
static void append_envvar(const char *name, const char *val); |
97 |
98 |
static void set_envvar(const char *name, const char *val); |
static void set_envvar(const char *name, const char *val); |
|
99 |
|
static int append_internal_var(var_info_t *var, var_t val); |
98 |
100 |
static int perform_opt_op(const char name[], VariableType vt, |
static int perform_opt_op(const char name[], VariableType vt, |
99 |
101 |
VariableOperation vo, const char value[]); |
VariableOperation vo, const char value[]); |
100 |
102 |
static envvar_t * get_record(const char *name); |
static envvar_t * get_record(const char *name); |
|
... |
... |
static void free_record(envvar_t *record); |
104 |
106 |
static void clear_record(envvar_t *record); |
static void clear_record(envvar_t *record); |
105 |
107 |
static void complete_envvars(const char var[], const char **start); |
static void complete_envvars(const char var[], const char **start); |
106 |
108 |
static void complete_internal_vars(const char var[], const char **start); |
static void complete_internal_vars(const char var[], const char **start); |
|
109 |
|
static var_info_t * find_internal_var(const char varname[], int create); |
107 |
110 |
|
|
108 |
111 |
static int initialized; |
static int initialized; |
109 |
112 |
static envvar_t *env_vars; |
static envvar_t *env_vars; |
|
... |
... |
let_variables(const char cmd[]) |
280 |
283 |
|
|
281 |
284 |
str_val = var_to_str(result.value); |
str_val = var_to_str(result.value); |
282 |
285 |
|
|
283 |
|
error = perform_op(name, type, op, str_val); |
|
284 |
|
|
|
|
286 |
|
error = perform_op(name, type, op, result.value, str_val); |
285 |
287 |
free(str_val); |
free(str_val); |
|
288 |
|
|
|
289 |
|
if(error) |
|
290 |
|
{ |
|
291 |
|
vle_tb_append_line(vle_err, "Failed to perform an operation"); |
|
292 |
|
goto fail; |
|
293 |
|
} |
|
294 |
|
|
286 |
295 |
var_free(result.value); |
var_free(result.value); |
287 |
296 |
return error; |
return error; |
288 |
297 |
|
|
|
... |
... |
extract_name(const char **in, VariableType *type, size_t buf_len, char buf[]) |
306 |
315 |
buf_len, buf) != 0); |
buf_len, buf) != 0); |
307 |
316 |
*type = VT_ENVVAR; |
*type = VT_ENVVAR; |
308 |
317 |
} |
} |
|
318 |
|
else if((*in)[0] == 'g' && (*in)[1] == ':') |
|
319 |
|
{ |
|
320 |
|
*in += 2; |
|
321 |
|
copy_str(buf, buf_len, "g:"); |
|
322 |
|
error = (parse_name(in, ENV_VAR_NAME_FIRST_CHAR, ENV_VAR_NAME_CHARS, |
|
323 |
|
buf_len - 2, buf + 2) != 0); |
|
324 |
|
*type = VT_GVAR; |
|
325 |
|
} |
309 |
326 |
else if(**in == '&') |
else if(**in == '&') |
310 |
327 |
{ |
{ |
311 |
328 |
++*in; |
++*in; |
|
... |
... |
is_valid_op(const char name[], VariableType vt, VariableOperation vo) |
416 |
433 |
return (vo == VO_ASSIGN || vo == VO_APPEND); |
return (vo == VO_ASSIGN || vo == VO_APPEND); |
417 |
434 |
} |
} |
418 |
435 |
|
|
|
436 |
|
if(vt == VT_GVAR) |
|
437 |
|
{ |
|
438 |
|
var_info_t *var = find_internal_var(name, /*create=*/0); |
|
439 |
|
if(var == NULL) |
|
440 |
|
{ |
|
441 |
|
/* Let this error be handled somewhere else. */ |
|
442 |
|
return (vo == VO_ASSIGN); |
|
443 |
|
} |
|
444 |
|
|
|
445 |
|
switch(var->val.type) |
|
446 |
|
{ |
|
447 |
|
case VTYPE_ERROR: |
|
448 |
|
/* Unreachable. */ |
|
449 |
|
return 0; |
|
450 |
|
case VTYPE_STRING: |
|
451 |
|
return ONE_OF(vo, VO_ASSIGN, VO_APPEND); |
|
452 |
|
case VTYPE_INT: |
|
453 |
|
return ONE_OF(vo, VO_ASSIGN, VO_ADD, VO_SUB); |
|
454 |
|
} |
|
455 |
|
/* Unreachable. */ |
|
456 |
|
return 0; |
|
457 |
|
} |
|
458 |
|
|
419 |
459 |
opt = vle_opts_find(name, OPT_GLOBAL); |
opt = vle_opts_find(name, OPT_GLOBAL); |
420 |
460 |
if(opt == NULL) |
if(opt == NULL) |
421 |
461 |
{ |
{ |
|
... |
... |
is_valid_op(const char name[], VariableType vt, VariableOperation vo) |
439 |
479 |
/* Performs operation on a value. Returns zero on success, otherwise non-zero |
/* Performs operation on a value. Returns zero on success, otherwise non-zero |
440 |
480 |
* is returned. */ |
* is returned. */ |
441 |
481 |
static int |
static int |
442 |
|
perform_op(const char name[], VariableType vt, VariableOperation vo, |
|
|
482 |
|
perform_op(const char name[], VariableType vt, VariableOperation vo, var_t val, |
443 |
483 |
const char value[]) |
const char value[]) |
444 |
484 |
{ |
{ |
445 |
485 |
if(vt == VT_ENVVAR) |
if(vt == VT_ENVVAR) |
|
... |
... |
perform_op(const char name[], VariableType vt, VariableOperation vo, |
456 |
496 |
return 0; |
return 0; |
457 |
497 |
} |
} |
458 |
498 |
|
|
|
499 |
|
if(vt == VT_GVAR) |
|
500 |
|
{ |
|
501 |
|
var_info_t *var = find_internal_var(name, vo == VO_ASSIGN); |
|
502 |
|
switch(vo) |
|
503 |
|
{ |
|
504 |
|
int a, b; |
|
505 |
|
|
|
506 |
|
case VO_ASSIGN: |
|
507 |
|
var_free(var->val); |
|
508 |
|
var->val = var_clone(val); |
|
509 |
|
return 0; |
|
510 |
|
case VO_ADD: |
|
511 |
|
case VO_SUB: |
|
512 |
|
a = var_to_int(var->val); |
|
513 |
|
b = var_to_int(val); |
|
514 |
|
var_free(var->val); |
|
515 |
|
var->val = var_from_int(vo == VO_ADD ? a + b : a - b); |
|
516 |
|
return 0; |
|
517 |
|
case VO_APPEND: |
|
518 |
|
return append_internal_var(var, val); |
|
519 |
|
} |
|
520 |
|
/* Unreachable. */ |
|
521 |
|
return 1; |
|
522 |
|
} |
|
523 |
|
|
459 |
524 |
/* Update an option. */ |
/* Update an option. */ |
460 |
525 |
|
|
461 |
526 |
if(vt == VT_ANY_OPTION || vt == VT_LOCAL_OPTION) |
if(vt == VT_ANY_OPTION || vt == VT_LOCAL_OPTION) |
|
... |
... |
set_envvar(const char *name, const char *val) |
526 |
591 |
env_set(name, val); |
env_set(name, val); |
527 |
592 |
} |
} |
528 |
593 |
|
|
|
594 |
|
/* Appends two variables as strings, updating LHS in place. Returns zero on |
|
595 |
|
* success. */ |
|
596 |
|
static int |
|
597 |
|
append_internal_var(var_info_t *var, var_t val) |
|
598 |
|
{ |
|
599 |
|
char *current = var_to_str(var->val); |
|
600 |
|
char *suffix = var_to_str(val); |
|
601 |
|
|
|
602 |
|
if(current == NULL || suffix == NULL) |
|
603 |
|
{ |
|
604 |
|
goto oom; |
|
605 |
|
} |
|
606 |
|
|
|
607 |
|
char *final = format_str("%s%s", current, suffix); |
|
608 |
|
if(final == NULL) |
|
609 |
|
{ |
|
610 |
|
goto oom; |
|
611 |
|
} |
|
612 |
|
|
|
613 |
|
var_free(var->val); |
|
614 |
|
var->val = var_out_of_str(final); |
|
615 |
|
|
|
616 |
|
free(current); |
|
617 |
|
free(suffix); |
|
618 |
|
return 0; |
|
619 |
|
|
|
620 |
|
oom: |
|
621 |
|
vle_tb_append_line(vle_err, "Not enough memory"); |
|
622 |
|
free(current); |
|
623 |
|
free(suffix); |
|
624 |
|
return 1; |
|
625 |
|
} |
|
626 |
|
|
529 |
627 |
/* Performs operation on an option. Returns zero on success, otherwise non-zero |
/* Performs operation on an option. Returns zero on success, otherwise non-zero |
530 |
628 |
* is returned. */ |
* is returned. */ |
531 |
629 |
static int |
static int |
|
... |
... |
unlet_variables(const char cmd[]) |
624 |
722 |
|
|
625 |
723 |
while(*cmd != '\0') |
while(*cmd != '\0') |
626 |
724 |
{ |
{ |
627 |
|
envvar_t *record; |
|
|
725 |
|
/* Options can't be removed, use this to mean "no value". */ |
|
726 |
|
VariableType type = VT_ANY_OPTION; |
628 |
727 |
|
|
629 |
728 |
char name[VAR_NAME_MAX + 1]; |
char name[VAR_NAME_MAX + 1]; |
630 |
|
char *p; |
|
631 |
|
int envvar = 1; |
|
|
729 |
|
char *p = name; |
632 |
730 |
|
|
633 |
731 |
/* Check if it's environment variable. */ |
/* Check if it's environment variable. */ |
634 |
|
if(*cmd != '$') |
|
635 |
|
envvar = 0; |
|
636 |
|
else |
|
|
732 |
|
if(*cmd == '$') |
|
733 |
|
{ |
|
734 |
|
type = VT_ENVVAR; |
637 |
735 |
cmd++; |
cmd++; |
|
736 |
|
} |
|
737 |
|
else if(starts_with_lit(cmd, "g:")) |
|
738 |
|
{ |
|
739 |
|
type = VT_GVAR; |
|
740 |
|
*p++ = *cmd++; |
|
741 |
|
*p++ = *cmd++; |
|
742 |
|
} |
638 |
743 |
|
|
639 |
744 |
/* Copy variable name. */ |
/* Copy variable name. */ |
640 |
|
p = name; |
|
641 |
745 |
while(*cmd != '\0' && char_is_one_of(ENV_VAR_NAME_CHARS, *cmd) && |
while(*cmd != '\0' && char_is_one_of(ENV_VAR_NAME_CHARS, *cmd) && |
642 |
746 |
(size_t)(p - name) < sizeof(name) - 1) |
(size_t)(p - name) < sizeof(name) - 1) |
643 |
747 |
{ |
{ |
|
... |
... |
unlet_variables(const char cmd[]) |
654 |
758 |
|
|
655 |
759 |
cmd = skip_whitespace(cmd); |
cmd = skip_whitespace(cmd); |
656 |
760 |
|
|
657 |
|
/* Currently we support only environment variables. */ |
|
658 |
|
if(!envvar) |
|
|
761 |
|
if(type == VT_ANY_OPTION) |
659 |
762 |
{ |
{ |
660 |
763 |
vle_tb_append_linef(vle_err, "%s: %s", "Unsupported variable type", name); |
vle_tb_append_linef(vle_err, "%s: %s", "Unsupported variable type", name); |
661 |
764 |
|
|
|
... |
... |
unlet_variables(const char cmd[]) |
673 |
776 |
continue; |
continue; |
674 |
777 |
} |
} |
675 |
778 |
|
|
676 |
|
record = find_record(name); |
|
677 |
|
if(record == NULL || record->removed) |
|
|
779 |
|
if(type == VT_ENVVAR) |
678 |
780 |
{ |
{ |
679 |
|
vle_tb_append_linef(vle_err, "%s: %s", "No such variable", name); |
|
680 |
|
error++; |
|
681 |
|
continue; |
|
|
781 |
|
envvar_t *record = find_record(name); |
|
782 |
|
if(record == NULL || record->removed) |
|
783 |
|
{ |
|
784 |
|
vle_tb_append_linef(vle_err, "%s: %s", "No such variable", name); |
|
785 |
|
error++; |
|
786 |
|
continue; |
|
787 |
|
} |
|
788 |
|
|
|
789 |
|
if(record->from_parent) |
|
790 |
|
record->removed = 1; |
|
791 |
|
else |
|
792 |
|
free_record(record); |
|
793 |
|
env_remove(name); |
682 |
794 |
} |
} |
|
795 |
|
else if(type == VT_GVAR) |
|
796 |
|
{ |
|
797 |
|
var_info_t *var = find_internal_var(name, /*create=*/0); |
|
798 |
|
if(var == NULL) |
|
799 |
|
{ |
|
800 |
|
vle_tb_append_linef(vle_err, "%s: %s", "No such variable", name); |
|
801 |
|
error++; |
|
802 |
|
continue; |
|
803 |
|
} |
683 |
804 |
|
|
684 |
|
if(record->from_parent) |
|
685 |
|
record->removed = 1; |
|
686 |
|
else |
|
687 |
|
free_record(record); |
|
688 |
|
env_remove(name); |
|
|
805 |
|
free(var->name); |
|
806 |
|
var_free(var->val); |
|
807 |
|
*var = internal_vars[internal_var_count - 1]; |
|
808 |
|
--internal_var_count; |
|
809 |
|
} |
689 |
810 |
} |
} |
690 |
811 |
|
|
691 |
812 |
return error; |
return error; |
|
... |
... |
complete_variables(const char var[], const char **start) |
743 |
864 |
{ |
{ |
744 |
865 |
complete_envvars(var, start); |
complete_envvars(var, start); |
745 |
866 |
} |
} |
746 |
|
else if(var[0] == 'v' && var[1] == ':') |
|
|
867 |
|
else if(ONE_OF(var[0], 'v', 'g') && var[1] == ':') |
747 |
868 |
{ |
{ |
748 |
869 |
complete_internal_vars(var, start); |
complete_internal_vars(var, start); |
749 |
870 |
} |
} |
|
... |
... |
complete_envvars(const char var[], const char **start) |
780 |
901 |
vle_compl_add_last_match(var); |
vle_compl_add_last_match(var); |
781 |
902 |
} |
} |
782 |
903 |
|
|
783 |
|
/* Completes a variable name. var should point to "v:...". *start is set to |
|
|
904 |
|
/* Completes a variable name. var should point to "[gv]:...". *start is set to |
784 |
905 |
* completion insertion position in var. */ |
* completion insertion position in var. */ |
785 |
906 |
static void |
static void |
786 |
907 |
complete_internal_vars(const char var[], const char **start) |
complete_internal_vars(const char var[], const char **start) |
|
... |
... |
complete_internal_vars(const char var[], const char **start) |
808 |
929 |
var_t |
var_t |
809 |
930 |
getvar(const char varname[]) |
getvar(const char varname[]) |
810 |
931 |
{ |
{ |
811 |
|
size_t i; |
|
812 |
|
for(i = 0U; i < internal_var_count; ++i) |
|
|
932 |
|
var_info_t *var = find_internal_var(varname, /*create=*/0); |
|
933 |
|
if(var == NULL) |
813 |
934 |
{ |
{ |
814 |
|
if(strcmp(internal_vars[i].name, varname) == 0) |
|
815 |
|
{ |
|
816 |
|
return internal_vars[i].val; |
|
817 |
|
} |
|
|
935 |
|
return var_error(); |
818 |
936 |
} |
} |
819 |
937 |
|
|
820 |
|
return var_error(); |
|
|
938 |
|
return var->val; |
821 |
939 |
} |
} |
822 |
940 |
|
|
823 |
941 |
int |
int |
824 |
942 |
setvar(const char varname[], var_t val) |
setvar(const char varname[], var_t val) |
825 |
943 |
{ |
{ |
826 |
944 |
var_info_t new_var; |
var_info_t new_var; |
827 |
|
size_t i; |
|
828 |
945 |
void *p; |
void *p; |
829 |
946 |
|
|
830 |
947 |
if(!starts_with_lit(varname, "v:")) |
if(!starts_with_lit(varname, "v:")) |
|
... |
... |
setvar(const char varname[], var_t val) |
842 |
959 |
return 1; |
return 1; |
843 |
960 |
} |
} |
844 |
961 |
|
|
845 |
|
/* Search for existing variable. */ |
|
846 |
|
for(i = 0U; i < internal_var_count; ++i) |
|
|
962 |
|
/* Try updating an existing variable. */ |
|
963 |
|
var_info_t *var = find_internal_var(varname, /*create=*/0); |
|
964 |
|
if(var != NULL) |
847 |
965 |
{ |
{ |
848 |
|
if(strcmp(internal_vars[i].name, varname) == 0) |
|
849 |
|
{ |
|
850 |
|
free(internal_vars[i].name); |
|
851 |
|
var_free(internal_vars[i].val); |
|
852 |
|
internal_vars[i] = new_var; |
|
853 |
|
return 0; |
|
854 |
|
} |
|
|
966 |
|
free(var->name); |
|
967 |
|
var_free(var->val); |
|
968 |
|
*var = new_var; |
|
969 |
|
return 0; |
855 |
970 |
} |
} |
856 |
971 |
|
|
857 |
972 |
/* Try to reallocate list of variables. */ |
/* Try to reallocate list of variables. */ |
|
... |
... |
setvar(const char varname[], var_t val) |
869 |
984 |
return 0; |
return 0; |
870 |
985 |
} |
} |
871 |
986 |
|
|
|
987 |
|
/* Search for an existing variable by its name and optionally create it if |
|
988 |
|
* missing. Returns NULL on unsuccessful search. */ |
|
989 |
|
static var_info_t * |
|
990 |
|
find_internal_var(const char varname[], int create) |
|
991 |
|
{ |
|
992 |
|
size_t i; |
|
993 |
|
for(i = 0U; i < internal_var_count; ++i) |
|
994 |
|
{ |
|
995 |
|
if(strcmp(internal_vars[i].name, varname) == 0) |
|
996 |
|
{ |
|
997 |
|
return &internal_vars[i]; |
|
998 |
|
} |
|
999 |
|
} |
|
1000 |
|
|
|
1001 |
|
if(!create) |
|
1002 |
|
{ |
|
1003 |
|
return NULL; |
|
1004 |
|
} |
|
1005 |
|
|
|
1006 |
|
void *p = |
|
1007 |
|
realloc(internal_vars, sizeof(*internal_vars)*(internal_var_count + 1U)); |
|
1008 |
|
if(p == NULL) |
|
1009 |
|
{ |
|
1010 |
|
return NULL; |
|
1011 |
|
} |
|
1012 |
|
|
|
1013 |
|
internal_vars = p; |
|
1014 |
|
|
|
1015 |
|
internal_vars[internal_var_count].name = strdup(varname); |
|
1016 |
|
if(internal_vars[internal_var_count].name == NULL) |
|
1017 |
|
{ |
|
1018 |
|
return NULL; |
|
1019 |
|
} |
|
1020 |
|
|
|
1021 |
|
internal_vars[internal_var_count].val = var_error(); |
|
1022 |
|
return &internal_vars[internal_var_count++]; |
|
1023 |
|
} |
|
1024 |
|
|
872 |
1025 |
/* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */ |
/* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */ |
873 |
1026 |
/* vim: set cinoptions+=t0 filetype=c : */ |
/* vim: set cinoptions+=t0 filetype=c : */ |
File tests/variables/globals.c added (mode: 100644) (index 000000000..57a2fca63) |
|
1 |
|
#include <stic.h> |
|
2 |
|
|
|
3 |
|
#include "../../src/engine/variables.h" |
|
4 |
|
|
|
5 |
|
TEST(get_var_fails_for_unknown_global) |
|
6 |
|
{ |
|
7 |
|
assert_true(getvar("g:test").type == VTYPE_ERROR); |
|
8 |
|
} |
|
9 |
|
|
|
10 |
|
TEST(get_var_works_for_known_global) |
|
11 |
|
{ |
|
12 |
|
assert_success(let_variables("g:test = 1")); |
|
13 |
|
assert_true(getvar("g:test").type == VTYPE_INT); |
|
14 |
|
} |
|
15 |
|
|
|
16 |
|
TEST(globals_can_be_removed) |
|
17 |
|
{ |
|
18 |
|
assert_success(let_variables("g:test1 = 'a'")); |
|
19 |
|
assert_success(let_variables("g:test2 = 0")); |
|
20 |
|
assert_success(unlet_variables("g:test1 g:test2")); |
|
21 |
|
assert_true(getvar("g:test1").type == VTYPE_ERROR); |
|
22 |
|
assert_true(getvar("g:test2").type == VTYPE_ERROR); |
|
23 |
|
} |
|
24 |
|
|
|
25 |
|
TEST(globals_can_be_strings) |
|
26 |
|
{ |
|
27 |
|
assert_success(let_variables("g:test = 'abc'")); |
|
28 |
|
assert_true(getvar("g:test").type == VTYPE_STRING); |
|
29 |
|
} |
|
30 |
|
|
|
31 |
|
TEST(globals_can_change_value) |
|
32 |
|
{ |
|
33 |
|
assert_success(let_variables("g:test = 0")); |
|
34 |
|
assert_int_equal(0, var_to_int(getvar("g:test"))); |
|
35 |
|
|
|
36 |
|
assert_success(let_variables("g:test = 2")); |
|
37 |
|
assert_int_equal(2, var_to_int(getvar("g:test"))); |
|
38 |
|
} |
|
39 |
|
|
|
40 |
|
TEST(globals_can_change_type) |
|
41 |
|
{ |
|
42 |
|
assert_success(let_variables("g:test = 0")); |
|
43 |
|
assert_true(getvar("g:test").type == VTYPE_INT); |
|
44 |
|
assert_int_equal(0, var_to_int(getvar("g:test"))); |
|
45 |
|
|
|
46 |
|
assert_success(let_variables("g:test = 'abc'")); |
|
47 |
|
assert_true(getvar("g:test").type == VTYPE_STRING); |
|
48 |
|
assert_string_equal("abc", getvar("g:test").value.string); |
|
49 |
|
} |
|
50 |
|
|
|
51 |
|
TEST(int_globals_can_be_incremented_or_decremented) |
|
52 |
|
{ |
|
53 |
|
assert_success(let_variables("g:test = 7")); |
|
54 |
|
assert_int_equal(7, var_to_int(getvar("g:test"))); |
|
55 |
|
|
|
56 |
|
assert_success(let_variables("g:test += 2")); |
|
57 |
|
assert_int_equal(9, var_to_int(getvar("g:test"))); |
|
58 |
|
|
|
59 |
|
assert_success(let_variables("g:test -= 10")); |
|
60 |
|
assert_int_equal(-1, var_to_int(getvar("g:test"))); |
|
61 |
|
} |
|
62 |
|
|
|
63 |
|
TEST(string_globals_cannot_be_incremented_or_decremented) |
|
64 |
|
{ |
|
65 |
|
assert_success(let_variables("g:test = 'a'")); |
|
66 |
|
|
|
67 |
|
assert_failure(let_variables("g:test += 'b'")); |
|
68 |
|
assert_string_equal("a", getvar("g:test").value.string); |
|
69 |
|
|
|
70 |
|
assert_failure(let_variables("g:test -= 'a'")); |
|
71 |
|
assert_string_equal("a", getvar("g:test").value.string); |
|
72 |
|
} |
|
73 |
|
|
|
74 |
|
TEST(int_globals_cannot_be_appended) |
|
75 |
|
{ |
|
76 |
|
assert_success(let_variables("g:test = 0")); |
|
77 |
|
|
|
78 |
|
assert_failure(let_variables("g:test .= 1")); |
|
79 |
|
assert_int_equal(0, var_to_int(getvar("g:test"))); |
|
80 |
|
assert_true(getvar("g:test").type == VTYPE_INT); |
|
81 |
|
|
|
82 |
|
assert_failure(let_variables("g:test .= '1'")); |
|
83 |
|
assert_int_equal(0, var_to_int(getvar("g:test"))); |
|
84 |
|
assert_true(getvar("g:test").type == VTYPE_INT); |
|
85 |
|
} |
|
86 |
|
|
|
87 |
|
TEST(string_globals_can_be_appended) |
|
88 |
|
{ |
|
89 |
|
assert_success(let_variables("g:test = 'a'")); |
|
90 |
|
assert_success(let_variables("g:test .= 'b'")); |
|
91 |
|
assert_string_equal("ab", getvar("g:test").value.string); |
|
92 |
|
} |
|
93 |
|
|
|
94 |
|
/* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */ |
|
95 |
|
/* vim: set cinoptions+=t0 : */ |