#pragma once
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <strlcat.c>
#include <bvr.h>
#include <tape.c>
#include <bvrvar.c>
#include <inarray.c>
int bvr_commands_check_for_command(char * input_char, char ** value, int *i, FILE * input, int * value_size) {
if((*input_char) == LINE_COMMAND_CHAR) {
FILE * command_return;
size_t buf_size;
char * command_output;
command_return = open_memstream(&command_output, &buf_size);
if(bvr_command_processor(input, command_return) != SUCCESS) {
fprintf(stderr, "[bvrcommands.c] bvr_commands_check_for_command: command, passed as argument, didn't return success. Going on.\n");
}
fflush(command_return);
while((*value_size) < ((*i)+buf_size)) { // make room in chunks for command_output
(*value) = realloc((*value), (*value_size)+BVR_VALUE_CHUNK_SIZE);
if((*value) == NULL) {
fprintf(stderr, "[bvrcommands.c] bvr_commands_check_for_command: CRITICAL OUT-OF-MEMORY.\n");
}
(*value_size) = (*value_size)+BVR_VALUE_CHUNK_SIZE;
}
for(int j = 0; j < buf_size; j++) {
/// fprintf(stderr, "debug: \"%c\", %ld\n", command_output[j], buf_size);
(*value)[(*i)++] = command_output[j];
}
(*input_char) = CLOSING_COMMAND_TAG_CHAR_1; // da zaključimo loop (drugače ostane notri ?)
//\\ zelo slabo. znak, ki ga najde izveden ukaz, se izgubi. rešitev bi bila dobiti zadnji input char, ki triggera break
// prejšnjega ukaza, kar pa je nemogoče.
fflush(command_return);
fclose(command_return);
free(command_output);
command_output == NULL; // the address/pointer, lost for ever!
return BVR_CONTINUE;
}
return BVR_KEEPGOING;
}
char bvr_commands_skip_separator_chars(FILE * input) {
char input_char = fgetc(input);
while(input_char == ' ' || input_char == CLOSING_COMMAND_TAG_CHAR_1 || input_char == ',' || input_char == ';' || input_char == EOF ||
input_char == '\0' || input_char == '\n') {
input_char = fgetc(input);
}
return input_char;
}
char * bvr_commands_get_value(FILE * input, char * yeetus_chars) {
int value_size = BVR_VALUE_CHUNK_SIZE;
char * value = (char*) malloc(value_size);
char input_char = bvr_commands_skip_separator_chars(input);
int i = 0;
while(1) {
// i == napisali smo že toliko znakov
if(i >= value_size) { // <-- todo: uncomment after done debugging
value = realloc(value, (value_size) * BVR_VALUE_CHUNK_SIZE);
if(value == NULL) {
fprintf(stderr, "[bvrcommands.c] bvr_commands_get_value: CRITICAL OUT-OF-MEMORY, FUCK!\n");
}
value_size = value_size + BVR_VALUE_CHUNK_SIZE;
}
if(char_in_array(input_char, yeetus_chars)) {
value[i++] = '\0';
return value; // or yeet!
}
if(bvr_commands_check_for_command(&(input_char), &(value), &(i), input, &(value_size)) == BVR_CONTINUE) {
continue;
}
(value)[(i)++] = input_char;
input_char = fgetc(input);
}
// we should not get here!
}
char * bvr_commands_get_string(FILE * input) {
int value_size = BVR_VALUE_CHUNK_SIZE;
char * value = (char*) malloc(value_size);
char input_char = fgetc(input);
char previous_char = 'a'; // please don't make a an escape char
int i = 0;
while(1) {
// i == napisali smo že toliko znakov
if(i >= value_size) { // <-- todo: uncomment after done debugging
value = realloc(value, (value_size) * BVR_VALUE_CHUNK_SIZE);
if(value == NULL) {
fprintf(stderr, "[bvrcommands.c] bvr_commands_get_value: CRITICAL OUT-OF-MEMORY, FUCK!\n");
}
value_size = value_size + BVR_VALUE_CHUNK_SIZE;
}
if(input_char == BVR_BREAK_STRING_CHAR) {
if(previous_char != BVR_ESCAPE_CHAR) {
value[i++] = '\0';
return value;
} else {
i--; // da zamenjamo prejšnji ESCAPE_CHAR z BREAK_STRING charom
(value)[(i)++] = BVR_BREAK_STRING_CHAR;
}
} else {
(value)[(i)++] = input_char;
}
previous_char = input_char;
input_char = fgetc(input);
}
// we should not get here!
}
int bvr_handle_substring(FILE * input, FILE * output) { // acts like https://www.php.net/manual/en/function.substr.php
char chars_to_break_value[69] = ",; ";
strlcat(chars_to_break_value, BVR_CHARS_TO_BREAK_VALUE, sizeof(chars_to_break_value));
char * offset = bvr_commands_get_value(input, chars_to_break_value);
char * length = bvr_commands_get_value(input, chars_to_break_value);
char * string = bvr_commands_get_value(input, BVR_CHARS_TO_BREAK_VALUE);
int return_status = SUCCESS;
int real_offset = atoi(offset);
if(real_offset < 0) {
real_offset = strlen(string)-abs(real_offset);
}
if(strlen(string) < real_offset) { // catch errors
fprintf(stderr, "[bvrcommands.c] bvr_handle_substring: string lenght (%ld) is less than offset (%d). fuck you.\n",
strlen(string), real_offset);
fprintf(output, "\nbVerbose substring: string length of %ld is less than offset of %d.\n", strlen(string), real_offset);
return_status = FAILURE;
goto cleanup_and_return;
}
if(real_offset < 0) { // catch errors
fprintf(stderr, "[bvrcommands.c] bvr_handle_substring: supplied negative offset after calculation (%d) is negative. failing...\n",
real_offset);
fprintf(output, "\nbVerbose substring: supplied negative offset after calculation (%d) is negative.\n", real_offset);
return_status = FAILURE;
goto cleanup_and_return;
}
if(atoi(length) < 0) {
string[strlen(string)-abs(atoi(length))] = '\0';
fprintf(output, "%s", string+real_offset);
} else {
fprintf(output, "%.*s", atoi(length), string+real_offset);
}
cleanup_and_return:
fflush(output);
free(offset);
free(length);
free(string);
offset = NULL;
length = NULL;
string = NULL;
return return_status;
}
int bvr_handle_get(FILE * input, FILE * output) {
char chars_to_break_value[69] = ",; ";
strlcat(chars_to_break_value, BVR_CHARS_TO_BREAK_VALUE, sizeof(chars_to_break_value));
char * item = bvr_commands_get_value(input, chars_to_break_value);
fprintf(output, "%s", bvr_var_get(item));
fflush(output);
free(item);
item = NULL;
return SUCCESS;
}
int bvr_handle_set(FILE * input, FILE * output) {
char chars_to_break_value[69] = " ";
strlcat(chars_to_break_value, BVR_CHARS_TO_BREAK_VALUE, sizeof(chars_to_break_value));
char * item = bvr_commands_get_value(input, chars_to_break_value);
char * value = bvr_commands_get_value(input, BVR_CHARS_TO_BREAK_VALUE);
int return_value = bvr_var_set(item, value);
fflush(output);
free(item);
free(value);
item = NULL;
value = NULL;
return return_value;
}
int bvr_handle_include(FILE * input, FILE * output) {
char chars_to_break_value[69] = " ";
strlcat(chars_to_break_value, BVR_CHARS_TO_BREAK_VALUE, sizeof(chars_to_break_value));
char * item = bvr_commands_get_value(input, chars_to_break_value);
FILE * stream;
char * cp;
int return_status = SUCCESS;
// fprintf(stderr, "debug: %s\n", item);
if (strncmp(item, "bvr://", strlen("bvr://")) == 0) {
switch (item[6]) {
case 'v': /* ar */
cp = strchr(item+6, '/');
if (cp == NULL)
goto sike_this_actually_is_a_file;
cp = bvr_var_get(cp+1);
if (cp == NULL || 0 == strncmp(cp, "BVR_UNDEFINED", strlen("BVR_UNDEFINED")))
goto sike_this_actually_is_a_file;
stream = fmemopen(cp, strlen(cp), "r");
if (stream == NULL)
goto sike_this_actually_is_a_file;
break;
default:
goto sike_this_actually_is_a_file;
break; /* unreachable "code" */
}
} else {
sike_this_actually_is_a_file:
stream = fopen(item, "r");
char notgoodatnamingvariables[PATH_MAX];
char * path = bvr_var_get(BVR_INCLUDE_PATH_VAR_NAME);
if(stream == NULL) {
strcpy(notgoodatnamingvariables, item);
strcat(notgoodatnamingvariables, BVR_COMMAND_FILE_EXT);
stream = fopen(notgoodatnamingvariables, "r");
if(strcmp(path, BVR_UNDEFINED) == 0 && stream == NULL) {
fprintf(output, "\nbVerbose include error. File \"%s\" not found. Path is undefined.\n", item);
fprintf(stderr, "[bvrcommands.c] bvr_handle_include: File \"%s\" not found. Path is undefined.\n", item);
return_status = FAILURE;
goto returncleanly;
}
}
char * singlepath;
while(stream == NULL) {
singlepath = strrchr(path, BVR_PATH_SEPARATOR);
if(singlepath == NULL) {
strcpy(notgoodatnamingvariables, path);
strcat(notgoodatnamingvariables, item);
stream = fopen(notgoodatnamingvariables, "r"); // ob1 fuckery
if(stream == NULL) {
strcpy(notgoodatnamingvariables, path);
strcat(notgoodatnamingvariables, item);
strcat(notgoodatnamingvariables, BVR_COMMAND_FILE_EXT);
stream = fopen(notgoodatnamingvariables, "r"); // ob1 fuckery
if(stream == NULL) {
fprintf(output, "\nbVerbose include error. File \"%s\" not found.\n", item);
fprintf(stderr, "[bvrcommands.c] bvr_handle_include: File \"%s\" not found.\n", item);
return_status = FAILURE;
goto returncleanly;
}
break;
}
break;
}
strcpy(notgoodatnamingvariables, singlepath);
strcat(notgoodatnamingvariables, item);
stream = fopen(notgoodatnamingvariables+1, "r"); // ob1 fuckery
if(stream == NULL) {
strcat(notgoodatnamingvariables, BVR_COMMAND_FILE_EXT);
stream = fopen(notgoodatnamingvariables+1, "r"); // ob1 fuckery
if(stream != NULL) {
break;
}
}
*singlepath = '\0';
}
}
return_status = bvr_compose_stream(stream, output);
fclose(stream);
returncleanly:
fflush(output);
free(item);
item = NULL;
return return_status;
fflush(output); // kja?
}
int bvr_handle_move(FILE * input, FILE * output) {
char chars_to_break_value[69] = " ";
strlcat(chars_to_break_value, BVR_CHARS_TO_BREAK_VALUE, sizeof(chars_to_break_value));
char * item = bvr_commands_get_value(input, chars_to_break_value);
char * value = bvr_commands_get_value(input, chars_to_break_value);
int return_value = bvr_var_mv(item, value);
free(item);
free(value);
value = NULL;
item = NULL;
fflush(output);
return return_value;
}
int bvr_handle_string(FILE * input, FILE * output) {
char * item = bvr_commands_get_string(input);
char * uuid = randstring(37);
strcpy(uuid, "BVR_STRING");
uuid[10] = '_';
int return_value = bvr_var_set(uuid, item);
free(item);
item = NULL;
fprintf(output, "%s", uuid);
free(uuid);
uuid = NULL;
fflush(output);
return return_value;
}
int bvr_handle_equals(FILE * input, FILE * output) {
char chars_to_break_value[69] = " ";
strlcat(chars_to_break_value, BVR_CHARS_TO_BREAK_VALUE, sizeof(chars_to_break_value));
char * item = bvr_commands_get_value(input, chars_to_break_value);
char * value = bvr_commands_get_value(input, chars_to_break_value);
int return_value = 0;
char * string1 = bvr_var_get(item);
char * string2 = bvr_var_get(value);
char out;
if(strcmp(string1, string2) == 0) {
out = '1';
} else {
out = '0';
}
fprintf(output, "?\"%c\"", out);
free(item);
free(value);
item = NULL;
value = NULL;
fflush(output);
return return_value;
}
int bvr_handle_if(FILE * input, FILE * output) { // ?f 1 <@this is all executed@>
// first argument must *POINT* to a string which evaluates to 1, the second argument is the value of the endif string, spaces
// are argument delimeters. endif is only used for skipping forward if if should not execute.
char chars_to_break_value[69] = " ";
strlcat(chars_to_break_value, BVR_CHARS_TO_BREAK_VALUE, sizeof(chars_to_break_value));
char * item = bvr_commands_get_value(input, chars_to_break_value);
int return_value = 0;
if(strcmp(bvr_var_get(item), "1") == 0) {
char chars_to_break_value[3] = {OPENING_COMMAND_TAG_CHAR_2, EOF, '\0'};
char * temp = bvr_commands_get_value(input, chars_to_break_value);
free(temp);
temp = NULL;
char copy_buffer[BVR_COPY_BUFFER_SIZE];
init_tape_copy_buffer(copy_buffer, COPY_BUFFER_SIZE);
return_value = bvr_inline_command_processor(input, output, copy_buffer);
} else {
char input_char = fgetc(input);
char previous_char = 'a';
int depth = -1; // to increase to 0 after first <@
int we_re_in_a_comment = 0;
while(1) {
if((input_char == BVR_CLOSING_COMMAND_TAG_CHAR_2 && previous_char == BVR_CLOSING_COMMAND_TAG_CHAR_1 && depth == 0 &&
we_re_in_a_comment == 0)) {
break;
}
if(previous_char == BVR_OPENING_COMMAND_TAG_CHAR_1 && input_char == BVR_OPENING_COMMAND_TAG_CHAR_2) {
depth++;
} // this šubidubi doesn't account for <@ and @> in strings.
if(previous_char == BVR_CLOSING_COMMAND_TAG_CHAR_1 && input_char== BVR_CLOSING_COMMAND_TAG_CHAR_2) {
depth--;
}
if(previous_char == LINE_COMMAND_CHAR && input_char == BVR_BREAK_STRING_CHAR) {
char * temp = bvr_commands_get_string(input);
free(temp);
temp = NULL;
}
if(previous_char == BVR_NEWLINE_CHAR && input_char == LINE_COMMENT_CHAR) {
we_re_in_a_comment = 1;
}
if(we_re_in_a_comment && input_char == BVR_NEWLINE_CHAR) {
we_re_in_a_comment = 0;
}
previous_char = input_char;
input_char = fgetc(input);
}
}
free(item);
item = NULL;
if(return_value != 0) {
fprintf(stderr, "bvrcommands.c: bvr_handle_if: bvr_compose_stream returned an error status!\n");
}
return return_value;
}
int bvr_handle_while(FILE * input, FILE * output) {
char chars_to_break_value[69] = " ";
strlcat(chars_to_break_value, BVR_CHARS_TO_BREAK_VALUE, sizeof(chars_to_break_value));
char * item = bvr_commands_get_value(input, chars_to_break_value);
int return_value = 0;
char input_char = fgetc(input);
char previous_char = 'a';
char * string1 = bvr_var_get(item);
FILE * codestream;
int depth = -1; // to increase to 0 after first <@
int we_re_in_a_comment = 0;
char * code = malloc(sizeof(char)*2);
size_t code_index = 0;
size_t read_index = 0;
int in_string = 0;
while(1) {
if((input_char == BVR_CLOSING_COMMAND_TAG_CHAR_2 && previous_char == BVR_CLOSING_COMMAND_TAG_CHAR_1 && depth == 0 &&
we_re_in_a_comment == 0 && in_string == 0)) {
break;
}
if(previous_char == BVR_OPENING_COMMAND_TAG_CHAR_1 && input_char == BVR_OPENING_COMMAND_TAG_CHAR_2) {
depth++;
} // this šubidubi doesn't account for <@ and @> in strings.
if(previous_char == BVR_CLOSING_COMMAND_TAG_CHAR_1 && input_char== BVR_CLOSING_COMMAND_TAG_CHAR_2) {
depth--;
}
if(previous_char == LINE_COMMAND_CHAR && input_char == BVR_BREAK_STRING_CHAR) {
in_string = 1;
}
if (previous_char != BVR_ESCAPE_CHAR && input_char == BVR_BREAK_STRING_CHAR && in_string == 1) {
in_string = 0;
}
if(previous_char == BVR_NEWLINE_CHAR && input_char == LINE_COMMENT_CHAR) {
we_re_in_a_comment = 1;
}
if(we_re_in_a_comment && input_char == BVR_NEWLINE_CHAR) {
we_re_in_a_comment = 0;
}
previous_char = input_char;
input_char = fgetc(input);
read_index++;
if (read_index >= 2) {
code[code_index++] = input_char;
code[code_index] = '\0';
}
code = realloc(code, sizeof(char)*(2+code_index));
if (code == NULL) {
fprintf(stderr, "segmentation fault caught (?) in bvr_handle_while, expect killing of the process soon. there was also a memory leak of around %lu bytes.\n", code_index+2);
return_value = FAILURE;
goto criticalfuckery;
}
}
code[strlen(code)-2] = '\0';
code_index -= 2;
codestream = fmemopen(code, code_index, "r");
while (atoi(string1) > 0) { /* basically the whole logic */
rewind(codestream);
// fprintf(stderr, "debug: %s\n", code);
return_value = return_value != SUCCESS ? return_value : bvr_compose_stream(codestream, output);
string1 = bvr_var_get(item);
}
fclose(codestream);
criticalfuckery:
free(item);
item = NULL;
fflush(output);
return return_value;
}
int bvr_handle_join(FILE * input, FILE * output) {
char operation = fgetc(input);
int return_value = SUCCESS;
char chars_to_break_value[69] = " ";
strlcat(chars_to_break_value, BVR_CHARS_TO_BREAK_VALUE, sizeof(chars_to_break_value));
char * item = bvr_commands_get_value(input, chars_to_break_value);
char * value = bvr_commands_get_value(input, chars_to_break_value);
char * stvar1 = bvr_var_get(item);
char * stvar2 = bvr_var_get(value);
char * temp = malloc(sizeof(char)*(strlen(stvar1)+strlen(stvar2)+1));
sprintf(temp, "%s%s", stvar1, stvar2);
return_value = bvr_var_set(item, temp);
free(item);
free(value);
free(temp);
temp = NULL;
item = NULL;
value = NULL;
return return_value;
}
int bvr_handle_math(FILE * input, FILE * output) {
char operation = fgetc(input);
int return_value = SUCCESS;
char chars_to_break_value[69] = " ";
strlcat(chars_to_break_value, BVR_CHARS_TO_BREAK_VALUE, sizeof(chars_to_break_value));
char * item = bvr_commands_get_value(input, chars_to_break_value);
char * value = bvr_commands_get_value(input, chars_to_break_value);
long long int stvar1 = strtoll(bvr_var_get(item), NULL, 10);
long long int stvar2 = strtoll(bvr_var_get(value), NULL, 10);
char numberplaceholder[69];
switch (operation) {
case '+':
stvar1 += stvar2;
break;
case '-':
stvar1 -= stvar2;
break;
case '*':
stvar1 *= stvar2;
break;
case '/':
if (stvar2 == 0) {
return_value = FAILURE;
fprintf(stderr, "division with zero is illegal, prevented, but raised an error. setting to highest value possible.\n");
stvar1 = LLONG_MAX;
} else {
stvar1 /= stvar2;
}
break;
default:
return_value = FAILURE;
break;
}
snprintf(numberplaceholder, 69-1, "%lld", stvar1);
return_value = bvr_var_set(item, numberplaceholder);
free(item);
free(value);
item = NULL;
value = NULL;
return return_value;
}
int bvr_handle_explode(FILE * input, FILE * output) {
char chars_to_break_value[69] = " ";
strlcat(chars_to_break_value, BVR_CHARS_TO_BREAK_VALUE, sizeof(chars_to_break_value));
char * item = bvr_commands_get_value(input, chars_to_break_value);
char * value = bvr_commands_get_value(input, chars_to_break_value);
int return_value = SUCCESS;
char * string1 = bvr_var_get(item);
char * string2 = bvr_var_get(value);
char * token;
char * rest = malloc(sizeof(char)*(strlen(string1)+1));
strcpy(rest, string1);
char * charpointer;
int index = strlen(item);
size_t len = 0;
char lenst[69];
item[index++] = '[';
item[index] = '\0';
index = 0;
while ((token = strsep(&rest, string2))) { // strsep handles empty strings as well
charpointer = strrchr(item, BVR_ARRAY_INDEX_CHAR);
sprintf(charpointer+1, "%d" BVR_ARRAY_AFTER_INDEX, index++); /* keys must always have 128 bytes more space allocated */
return_value = return_value != SUCCESS ? return_value : bvr_var_set(item, token); // če je bila prej napaka pač ne poskušamo več!
len++;
}
charpointer = strrchr(item, BVR_ARRAY_INDEX_CHAR);
sprintf(charpointer+1, "#" BVR_ARRAY_AFTER_INDEX, index++);
snprintf(lenst, 69-1, "%lu", len);
return_value = return_value != SUCCESS ? return_value : bvr_var_set(item, lenst);
free(item);
free(value);
item = NULL;
value = NULL;
fflush(output);
return return_value;
}
int bvr_handle_info(FILE * input, FILE * output) {
// fprintf(stderr, "[bvrcommands.c] bvr_handle_info: bvr bVerbose HTPCMS %d.%d.%d\n", BVR_VER_MAJOR, BVR_VER_MINOR, BVR_VER_PATCH);
char chars_to_break_value[69] = " ";
strlcat(chars_to_break_value, BVR_CHARS_TO_BREAK_VALUE, sizeof(chars_to_break_value));
char * item = bvr_commands_get_value(input, chars_to_break_value);
switch(item[0]) {
case 'c':
fprintf(output, "%lu", bvr_variables_count);
break;
default:
fprintf(output, "\nbvr bVerbose HTPCMS %d.%d.%d\n", BVR_VER_MAJOR, BVR_VER_MINOR, BVR_VER_PATCH);
break;
}
free(item);
item = NULL;
return SUCCESS;
}