Phase 4: CHAIN, RUN "file", random-access I/O, MBF conversions
Add CHAIN statement for loading and running chained programs with optional ALL flag to preserve variables. Extend RUN to accept a filename string argument. Implement random-access file I/O with FIELD, LSET, RSET, PUT#, GET# and the MBF conversion functions CVI/CVS/CVD/MKI$/MKS$/MKD$. Add COMMON statement (parse and skip). Five new test programs covering all new features (27 total).
This commit is contained in:
+49
-2
@@ -727,12 +727,59 @@ static gw_value_t eval_atom(void)
|
||||
return eval_function(TOK_PREFIX_FF, func);
|
||||
}
|
||||
|
||||
/* Extended function (0xFD prefix) */
|
||||
/* Extended function (0xFD prefix): CVI, CVS, CVD, MKI$, MKS$, MKD$ */
|
||||
if (tok == TOK_PREFIX_FD) {
|
||||
gw_chrget();
|
||||
uint8_t func = gw_chrgot();
|
||||
gw_chrget();
|
||||
return eval_function(TOK_PREFIX_FD, func);
|
||||
|
||||
switch (func) {
|
||||
case XFUNC_CVI:
|
||||
{
|
||||
gw_expect('(');
|
||||
gw_value_t arg = gw_eval_str();
|
||||
gw_expect_rparen();
|
||||
return gw_fn_cvi(&arg);
|
||||
}
|
||||
case XFUNC_CVS:
|
||||
{
|
||||
gw_expect('(');
|
||||
gw_value_t arg = gw_eval_str();
|
||||
gw_expect_rparen();
|
||||
return gw_fn_cvs(&arg);
|
||||
}
|
||||
case XFUNC_CVD:
|
||||
{
|
||||
gw_expect('(');
|
||||
gw_value_t arg = gw_eval_str();
|
||||
gw_expect_rparen();
|
||||
return gw_fn_cvd(&arg);
|
||||
}
|
||||
case XFUNC_MKI:
|
||||
{
|
||||
gw_expect('(');
|
||||
int16_t n = gw_eval_int();
|
||||
gw_expect_rparen();
|
||||
return gw_fn_mki(n);
|
||||
}
|
||||
case XFUNC_MKS:
|
||||
{
|
||||
gw_expect('(');
|
||||
gw_value_t arg = gw_eval_num();
|
||||
gw_expect_rparen();
|
||||
return gw_fn_mks(gw_to_sng(&arg));
|
||||
}
|
||||
case XFUNC_MKD:
|
||||
{
|
||||
gw_expect('(');
|
||||
gw_value_t arg = gw_eval_num();
|
||||
gw_expect_rparen();
|
||||
return gw_fn_mkd(gw_to_dbl(&arg));
|
||||
}
|
||||
default:
|
||||
gw_error(ERR_SN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* STRING$ function (single-byte token but acts like function) */
|
||||
|
||||
+309
-3
@@ -22,6 +22,10 @@ void gw_file_close_all(void)
|
||||
gw.files[i].mode = 0;
|
||||
gw.files[i].eof_flag = false;
|
||||
}
|
||||
free(gw.files[i].field_buf);
|
||||
gw.files[i].field_buf = NULL;
|
||||
gw.files[i].field_count = 0;
|
||||
gw.files[i].record_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,12 +176,31 @@ void gw_stmt_open(void)
|
||||
gw.files[file_num].mode = mode;
|
||||
gw.files[file_num].file_num = file_num;
|
||||
gw.files[file_num].eof_flag = false;
|
||||
gw.files[file_num].field_buf = NULL;
|
||||
gw.files[file_num].field_count = 0;
|
||||
|
||||
/* Skip optional record length: , reclen */
|
||||
/* Parse optional record length */
|
||||
int reclen = 128;
|
||||
gw_skip_spaces();
|
||||
if (gw_chrgot() == ',') {
|
||||
/* Modern syntax: LEN = n */
|
||||
if (gw_is_letter(gw_chrgot()) && toupper(gw_chrgot()) == 'L') {
|
||||
/* Skip LEN */
|
||||
while (gw_is_letter(gw_chrgot())) gw_chrget();
|
||||
gw_skip_spaces();
|
||||
if (gw_chrgot() == TOK_EQ) {
|
||||
gw_chrget();
|
||||
reclen = gw_eval_int();
|
||||
}
|
||||
} else if (gw_chrgot() == ',') {
|
||||
/* Compact syntax: , reclen */
|
||||
gw_chrget();
|
||||
gw_eval_int(); /* consume and ignore record length */
|
||||
reclen = gw_eval_int();
|
||||
}
|
||||
|
||||
gw.files[file_num].record_len = reclen;
|
||||
if (mode == 'R') {
|
||||
gw.files[file_num].field_buf = calloc(1, reclen);
|
||||
if (!gw.files[file_num].field_buf) gw_error(ERR_OM);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,6 +225,10 @@ void gw_stmt_close(void)
|
||||
gw.files[num].fp = NULL;
|
||||
gw.files[num].mode = 0;
|
||||
gw.files[num].eof_flag = false;
|
||||
free(gw.files[num].field_buf);
|
||||
gw.files[num].field_buf = NULL;
|
||||
gw.files[num].field_count = 0;
|
||||
gw.files[num].record_len = 0;
|
||||
}
|
||||
gw_skip_spaces();
|
||||
if (gw_chrgot() != ',')
|
||||
@@ -472,3 +499,282 @@ void gw_stmt_line_input_file(void)
|
||||
if (feof(f->fp))
|
||||
f->eof_flag = true;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* Random-access file I/O: FIELD, LSET, RSET, PUT, GET
|
||||
* ================================================================ */
|
||||
|
||||
static void field_buf_to_vars(file_entry_t *f);
|
||||
static void vars_to_field_buf(file_entry_t *f);
|
||||
|
||||
/* FIELD #n, width AS var$ [, width AS var$ ...] */
|
||||
void gw_stmt_field(void)
|
||||
{
|
||||
gw_skip_spaces();
|
||||
if (gw_chrgot() == '#')
|
||||
gw_chrget();
|
||||
int num = gw_eval_int();
|
||||
file_entry_t *f = gw_file_get(num);
|
||||
if (f->mode != 'R')
|
||||
gw_error(ERR_BM);
|
||||
|
||||
gw_skip_spaces();
|
||||
if (gw_chrgot() == ',')
|
||||
gw_chrget();
|
||||
|
||||
f->field_count = 0;
|
||||
int offset = 0;
|
||||
|
||||
for (;;) {
|
||||
gw_skip_spaces();
|
||||
if (gw_chrgot() == 0 || gw_chrgot() == ':')
|
||||
break;
|
||||
|
||||
int width = gw_eval_int();
|
||||
if (width < 0) gw_error(ERR_FC);
|
||||
if (offset + width > f->record_len) gw_error(ERR_FO);
|
||||
|
||||
gw_skip_spaces();
|
||||
/* Skip AS keyword */
|
||||
if (gw_is_letter(gw_chrgot()) && toupper(gw_chrgot()) == 'A') {
|
||||
gw_chrget();
|
||||
if (gw_is_letter(gw_chrgot()) && toupper(gw_chrgot()) == 'S')
|
||||
gw_chrget();
|
||||
}
|
||||
|
||||
gw_skip_spaces();
|
||||
char name[2];
|
||||
gw_valtype_t type = gw_parse_varname(name);
|
||||
if (type != VT_STR) gw_error(ERR_TM);
|
||||
|
||||
if (f->field_count >= 32) gw_error(ERR_FO);
|
||||
f->fields[f->field_count].name[0] = name[0];
|
||||
f->fields[f->field_count].name[1] = name[1];
|
||||
f->fields[f->field_count].type = type;
|
||||
f->fields[f->field_count].offset = offset;
|
||||
f->fields[f->field_count].width = width;
|
||||
f->field_count++;
|
||||
|
||||
offset += width;
|
||||
|
||||
gw_skip_spaces();
|
||||
if (gw_chrgot() == ',') {
|
||||
gw_chrget();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Initialize FIELD variables with proper widths (space-filled) */
|
||||
field_buf_to_vars(f);
|
||||
}
|
||||
|
||||
/* Copy field buffer data into the FIELD variables */
|
||||
static void field_buf_to_vars(file_entry_t *f)
|
||||
{
|
||||
for (int i = 0; i < f->field_count; i++) {
|
||||
var_entry_t *var = gw_var_find_or_create(f->fields[i].name,
|
||||
f->fields[i].type);
|
||||
gw_str_free(&var->val.sval);
|
||||
var->val.type = VT_STR;
|
||||
var->val.sval = gw_str_alloc(f->fields[i].width);
|
||||
memcpy(var->val.sval.data,
|
||||
f->field_buf + f->fields[i].offset,
|
||||
f->fields[i].width);
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy FIELD variables into the field buffer */
|
||||
static void vars_to_field_buf(file_entry_t *f)
|
||||
{
|
||||
for (int i = 0; i < f->field_count; i++) {
|
||||
var_entry_t *var = gw_var_find_or_create(f->fields[i].name,
|
||||
f->fields[i].type);
|
||||
int width = f->fields[i].width;
|
||||
int len = (var->val.type == VT_STR) ? var->val.sval.len : 0;
|
||||
int copy = (len < width) ? len : width;
|
||||
if (copy > 0)
|
||||
memcpy(f->field_buf + f->fields[i].offset,
|
||||
var->val.sval.data, copy);
|
||||
if (copy < width)
|
||||
memset(f->field_buf + f->fields[i].offset + copy, ' ',
|
||||
width - copy);
|
||||
}
|
||||
}
|
||||
|
||||
/* LSET var$ = expr$ - left-justify into field variable */
|
||||
void gw_stmt_lset(void)
|
||||
{
|
||||
gw_skip_spaces();
|
||||
char name[2];
|
||||
gw_valtype_t type = gw_parse_varname(name);
|
||||
if (type != VT_STR) gw_error(ERR_TM);
|
||||
var_entry_t *var = gw_var_find_or_create(name, type);
|
||||
|
||||
gw_skip_spaces();
|
||||
gw_expect(TOK_EQ);
|
||||
gw_value_t rhs = gw_eval_str();
|
||||
|
||||
int target_len = var->val.sval.len;
|
||||
if (target_len == 0) {
|
||||
gw_str_free(&rhs.sval);
|
||||
return;
|
||||
}
|
||||
|
||||
int copy = (rhs.sval.len < target_len) ? rhs.sval.len : target_len;
|
||||
memcpy(var->val.sval.data, rhs.sval.data, copy);
|
||||
if (copy < target_len)
|
||||
memset(var->val.sval.data + copy, ' ', target_len - copy);
|
||||
gw_str_free(&rhs.sval);
|
||||
}
|
||||
|
||||
/* RSET var$ = expr$ - right-justify into field variable */
|
||||
void gw_stmt_rset(void)
|
||||
{
|
||||
gw_skip_spaces();
|
||||
char name[2];
|
||||
gw_valtype_t type = gw_parse_varname(name);
|
||||
if (type != VT_STR) gw_error(ERR_TM);
|
||||
var_entry_t *var = gw_var_find_or_create(name, type);
|
||||
|
||||
gw_skip_spaces();
|
||||
gw_expect(TOK_EQ);
|
||||
gw_value_t rhs = gw_eval_str();
|
||||
|
||||
int target_len = var->val.sval.len;
|
||||
if (target_len == 0) {
|
||||
gw_str_free(&rhs.sval);
|
||||
return;
|
||||
}
|
||||
|
||||
int copy = (rhs.sval.len < target_len) ? rhs.sval.len : target_len;
|
||||
int pad = target_len - copy;
|
||||
if (pad > 0)
|
||||
memset(var->val.sval.data, ' ', pad);
|
||||
memcpy(var->val.sval.data + pad, rhs.sval.data, copy);
|
||||
gw_str_free(&rhs.sval);
|
||||
}
|
||||
|
||||
/* PUT #n [, record] - write field buffer to file */
|
||||
void gw_stmt_put(void)
|
||||
{
|
||||
gw_skip_spaces();
|
||||
if (gw_chrgot() == '#')
|
||||
gw_chrget();
|
||||
int num = gw_eval_int();
|
||||
file_entry_t *f = gw_file_get(num);
|
||||
if (f->mode != 'R')
|
||||
gw_error(ERR_BM);
|
||||
|
||||
long record = -1;
|
||||
gw_skip_spaces();
|
||||
if (gw_chrgot() == ',') {
|
||||
gw_chrget();
|
||||
record = gw_eval_int();
|
||||
if (record < 1) gw_error(ERR_RN);
|
||||
}
|
||||
|
||||
vars_to_field_buf(f);
|
||||
|
||||
if (record > 0)
|
||||
fseek(f->fp, (long)(record - 1) * f->record_len, SEEK_SET);
|
||||
|
||||
fwrite(f->field_buf, 1, f->record_len, f->fp);
|
||||
fflush(f->fp);
|
||||
}
|
||||
|
||||
/* GET #n [, record] - read record from file into field buffer */
|
||||
void gw_stmt_get(void)
|
||||
{
|
||||
gw_skip_spaces();
|
||||
if (gw_chrgot() == '#')
|
||||
gw_chrget();
|
||||
int num = gw_eval_int();
|
||||
file_entry_t *f = gw_file_get(num);
|
||||
if (f->mode != 'R')
|
||||
gw_error(ERR_BM);
|
||||
|
||||
long record = -1;
|
||||
gw_skip_spaces();
|
||||
if (gw_chrgot() == ',') {
|
||||
gw_chrget();
|
||||
record = gw_eval_int();
|
||||
if (record < 1) gw_error(ERR_RN);
|
||||
}
|
||||
|
||||
if (record > 0)
|
||||
fseek(f->fp, (long)(record - 1) * f->record_len, SEEK_SET);
|
||||
|
||||
memset(f->field_buf, 0, f->record_len);
|
||||
size_t got = fread(f->field_buf, 1, f->record_len, f->fp);
|
||||
if (got == 0)
|
||||
f->eof_flag = true;
|
||||
|
||||
field_buf_to_vars(f);
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* MBF Conversion Functions: CVI, CVS, CVD, MKI$, MKS$, MKD$
|
||||
* ================================================================ */
|
||||
|
||||
gw_value_t gw_fn_cvi(gw_value_t *s)
|
||||
{
|
||||
if (s->type != VT_STR) gw_error(ERR_TM);
|
||||
if (s->sval.len < 2) gw_error(ERR_FC);
|
||||
gw_value_t v;
|
||||
v.type = VT_INT;
|
||||
v.ival = (int16_t)((uint8_t)s->sval.data[0] |
|
||||
((uint8_t)s->sval.data[1] << 8));
|
||||
gw_str_free(&s->sval);
|
||||
return v;
|
||||
}
|
||||
|
||||
gw_value_t gw_fn_cvs(gw_value_t *s)
|
||||
{
|
||||
if (s->type != VT_STR) gw_error(ERR_TM);
|
||||
if (s->sval.len < 4) gw_error(ERR_FC);
|
||||
gw_value_t v;
|
||||
v.type = VT_SNG;
|
||||
memcpy(&v.fval, s->sval.data, 4);
|
||||
gw_str_free(&s->sval);
|
||||
return v;
|
||||
}
|
||||
|
||||
gw_value_t gw_fn_cvd(gw_value_t *s)
|
||||
{
|
||||
if (s->type != VT_STR) gw_error(ERR_TM);
|
||||
if (s->sval.len < 8) gw_error(ERR_FC);
|
||||
gw_value_t v;
|
||||
v.type = VT_DBL;
|
||||
memcpy(&v.dval, s->sval.data, 8);
|
||||
gw_str_free(&s->sval);
|
||||
return v;
|
||||
}
|
||||
|
||||
gw_value_t gw_fn_mki(int16_t n)
|
||||
{
|
||||
gw_value_t v;
|
||||
v.type = VT_STR;
|
||||
v.sval = gw_str_alloc(2);
|
||||
v.sval.data[0] = (char)(n & 0xFF);
|
||||
v.sval.data[1] = (char)((n >> 8) & 0xFF);
|
||||
return v;
|
||||
}
|
||||
|
||||
gw_value_t gw_fn_mks(float f)
|
||||
{
|
||||
gw_value_t v;
|
||||
v.type = VT_STR;
|
||||
v.sval = gw_str_alloc(4);
|
||||
memcpy(v.sval.data, &f, 4);
|
||||
return v;
|
||||
}
|
||||
|
||||
gw_value_t gw_fn_mkd(double d)
|
||||
{
|
||||
gw_value_t v;
|
||||
v.type = VT_STR;
|
||||
v.sval = gw_str_alloc(8);
|
||||
memcpy(v.sval.data, &d, 8);
|
||||
return v;
|
||||
}
|
||||
|
||||
+145
-1
@@ -542,6 +542,97 @@ void gw_stmt_mid_assign(void)
|
||||
gw_str_free(&rhs.sval);
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* CHAIN "filename" [, linenum] [, ALL]
|
||||
* ================================================================ */
|
||||
|
||||
void gw_stmt_chain(void)
|
||||
{
|
||||
gw_skip_spaces();
|
||||
|
||||
/* Skip optional MERGE keyword */
|
||||
bool merge = false;
|
||||
if (gw_is_letter(gw_chrgot()) && toupper(gw_chrgot()) == 'M') {
|
||||
/* Could be MERGE - skip the word */
|
||||
uint8_t *save = gw.text_ptr;
|
||||
while (gw_is_letter(gw_chrgot()))
|
||||
gw_chrget();
|
||||
gw_skip_spaces();
|
||||
merge = true;
|
||||
/* If no string follows, this wasn't MERGE */
|
||||
if (gw_chrgot() != '"') {
|
||||
gw.text_ptr = save;
|
||||
merge = false;
|
||||
}
|
||||
}
|
||||
|
||||
gw_value_t fname_val = gw_eval_str();
|
||||
char *filename = gw_str_to_cstr(&fname_val.sval);
|
||||
gw_str_free(&fname_val.sval);
|
||||
|
||||
uint16_t start_line = 0;
|
||||
bool has_start = false;
|
||||
bool keep_all = false;
|
||||
|
||||
gw_skip_spaces();
|
||||
if (gw_chrgot() == ',') {
|
||||
gw_chrget();
|
||||
gw_skip_spaces();
|
||||
/* Optional line number */
|
||||
uint8_t ch = gw_chrgot();
|
||||
if ((ch >= 0x11 && ch <= 0x1A) || ch == TOK_INT1 || ch == TOK_INT2
|
||||
|| ch == TOK_CONST_SNG || ch == TOK_CONST_DBL) {
|
||||
start_line = gw_eval_uint16();
|
||||
has_start = true;
|
||||
}
|
||||
gw_skip_spaces();
|
||||
if (gw_chrgot() == ',') {
|
||||
gw_chrget();
|
||||
gw_skip_spaces();
|
||||
/* ALL keyword - keep all variables */
|
||||
if (gw_is_letter(gw_chrgot()) && toupper(gw_chrgot()) == 'A') {
|
||||
keep_all = true;
|
||||
while (gw_is_letter(gw_chrgot()))
|
||||
gw_chrget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Load the new program */
|
||||
gw_stmt_load_internal(filename, !merge);
|
||||
free(filename);
|
||||
|
||||
if (!keep_all && !merge) {
|
||||
/* Clear variables unless ALL specified */
|
||||
gw_vars_clear();
|
||||
gw_arrays_clear();
|
||||
}
|
||||
|
||||
/* Start execution */
|
||||
program_line_t *start = gw.prog_head;
|
||||
if (has_start) {
|
||||
start = gw_find_line(start_line);
|
||||
if (!start) gw_error(ERR_UL);
|
||||
}
|
||||
|
||||
if (start) {
|
||||
gw.for_sp = 0;
|
||||
gw.gosub_sp = 0;
|
||||
gw.while_sp = 0;
|
||||
gw.data_ptr = NULL;
|
||||
gw.data_line_ptr = NULL;
|
||||
gw.cont_text = NULL;
|
||||
gw.cont_line = NULL;
|
||||
gw.on_error_line = 0;
|
||||
gw.in_error_handler = false;
|
||||
gw.cur_line = start;
|
||||
gw.text_ptr = start->tokens;
|
||||
gw.cur_line_num = start->num;
|
||||
gw.running = true;
|
||||
gw_run_loop();
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* Statement Dispatcher
|
||||
* ================================================================ */
|
||||
@@ -604,6 +695,43 @@ void gw_exec_stmt(void)
|
||||
if (gw_hal) gw_hal->shutdown();
|
||||
exit(0);
|
||||
}
|
||||
if (xstmt == XSTMT_CHAIN) {
|
||||
gw_chrget();
|
||||
gw_stmt_chain();
|
||||
return;
|
||||
}
|
||||
if (xstmt == XSTMT_COMMON) {
|
||||
/* COMMON var, var... - just skip, variables already in table */
|
||||
gw_chrget();
|
||||
while (gw_chrgot() && gw_chrgot() != ':' && gw_chrgot() != TOK_ELSE)
|
||||
gw.text_ptr++;
|
||||
return;
|
||||
}
|
||||
if (xstmt == XSTMT_FIELD) {
|
||||
gw_chrget();
|
||||
gw_stmt_field();
|
||||
return;
|
||||
}
|
||||
if (xstmt == XSTMT_LSET) {
|
||||
gw_chrget();
|
||||
gw_stmt_lset();
|
||||
return;
|
||||
}
|
||||
if (xstmt == XSTMT_RSET) {
|
||||
gw_chrget();
|
||||
gw_stmt_rset();
|
||||
return;
|
||||
}
|
||||
if (xstmt == XSTMT_PUT) {
|
||||
gw_chrget();
|
||||
gw_stmt_put();
|
||||
return;
|
||||
}
|
||||
if (xstmt == XSTMT_GET) {
|
||||
gw_chrget();
|
||||
gw_stmt_get();
|
||||
return;
|
||||
}
|
||||
/* Graphics/sound stubs - parse and discard arguments */
|
||||
if (xstmt == XSTMT_CIRCLE || xstmt == XSTMT_DRAW ||
|
||||
xstmt == XSTMT_PAINT || xstmt == XSTMT_PLAY ||
|
||||
@@ -690,10 +818,26 @@ void gw_exec_stmt(void)
|
||||
gw_chrget();
|
||||
gw_skip_spaces();
|
||||
|
||||
/* RUN "filename" - load and run a file */
|
||||
if (gw_chrgot() == '"') {
|
||||
gw_value_t fname_val = gw_eval_str();
|
||||
char *filename = gw_str_to_cstr(&fname_val.sval);
|
||||
gw_str_free(&fname_val.sval);
|
||||
gw_stmt_load_internal(filename, true);
|
||||
free(filename);
|
||||
if (gw.prog_head) {
|
||||
gw.cur_line = gw.prog_head;
|
||||
gw.text_ptr = gw.prog_head->tokens;
|
||||
gw.cur_line_num = gw.prog_head->num;
|
||||
gw.running = true;
|
||||
gw_run_loop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* RUN with line number */
|
||||
program_line_t *start = gw.prog_head;
|
||||
if (gw_chrgot() >= TOK_INT2 && gw_chrgot() <= TOK_CONST_DBL) {
|
||||
/* has a line number arg */
|
||||
uint16_t num = gw_eval_uint16();
|
||||
start = gw_find_line(num);
|
||||
if (!start) gw_error(ERR_UL);
|
||||
|
||||
+5
-3
@@ -39,7 +39,9 @@ void gw_stmt_save(void)
|
||||
}
|
||||
|
||||
/* Helper: load lines from a file into the program, optionally clearing first */
|
||||
static void load_from_file(const char *filename, bool clear)
|
||||
void gw_stmt_load_internal(const char *filename, bool clear);
|
||||
|
||||
void gw_stmt_load_internal(const char *filename, bool clear)
|
||||
{
|
||||
FILE *fp = fopen(filename, "r");
|
||||
if (!fp)
|
||||
@@ -120,7 +122,7 @@ void gw_stmt_load(void)
|
||||
}
|
||||
}
|
||||
|
||||
load_from_file(filename, true);
|
||||
gw_stmt_load_internal(filename, true);
|
||||
free(filename);
|
||||
|
||||
if (run_after && gw.prog_head) {
|
||||
@@ -140,6 +142,6 @@ void gw_stmt_merge(void)
|
||||
char *filename = gw_str_to_cstr(&fname_val.sval);
|
||||
gw_str_free(&fname_val.sval);
|
||||
|
||||
load_from_file(filename, false);
|
||||
gw_stmt_load_internal(filename, false);
|
||||
free(filename);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user