Skip to content

File module

Wang Renxin edited this page May 31, 2022 · 13 revisions

This module implements a file accessing library with MY-BASIC.

Add implementation functions:

static int _file_open(struct mb_interpreter_t* s, void** l) {
	int result = MB_FUNC_OK;
	FILE* fp = 0;
	char* fn = 0;
	char* fm = 0;

	mb_assert(s && l);

	mb_check(mb_attempt_open_bracket(s, l));

	mb_check(mb_pop_string(s, l, &fn));

	mb_check(mb_pop_string(s, l, &fm));

	mb_check(mb_attempt_close_bracket(s, l));

	if(!fn) {
		result = MB_FUNC_ERR;

		goto _exit;
	}

	fp = fopen(fn, fm);
	if(!fp) {
		result = MB_FUNC_ERR;

		goto _exit;
	}

_exit:
	mb_check(mb_push_usertype(s, l, (void*)fp));

	return result;
}

static int _file_close(struct mb_interpreter_t* s, void** l) {
	int result = MB_FUNC_OK;
	FILE* fp = 0;
	void* up = 0;

	mb_assert(s && l);

	mb_check(mb_attempt_open_bracket(s, l));

	mb_check(mb_pop_usertype(s, l, &up));

	mb_check(mb_attempt_close_bracket(s, l));

	if(!up)
		return MB_FUNC_ERR;

	fp = (FILE*)up;
	fclose(fp);

	return result;
}

static int _file_peek(struct mb_interpreter_t* s, void** l) {
	int result = MB_FUNC_OK;
	FILE* fp = 0;
	void* up = 0;
	long ft = -1; /* Push -1 for error */

	mb_assert(s && l);

	mb_check(mb_attempt_open_bracket(s, l));

	mb_check(mb_pop_usertype(s, l, &up));

	mb_check(mb_attempt_close_bracket(s, l));

	if(!up) {
		result = MB_FUNC_ERR;

		goto _exit;
	}

	fp = (FILE*)up;
	ft = ftell(fp);

_exit:
	mb_check(mb_push_int(s, l, ft));

	return result;
}

static int _file_poke(struct mb_interpreter_t* s, void** l) {
	int result = MB_FUNC_OK;
	FILE* fp = 0;
	void* up = 0;
	int fo = 0;

	mb_assert(s && l);

	mb_check(mb_attempt_open_bracket(s, l));

	mb_check(mb_pop_usertype(s, l, &up));

	mb_check(mb_pop_int(s, l, &fo));

	mb_check(mb_attempt_close_bracket(s, l));

	if(!up)
		return MB_FUNC_ERR;

	fp = (FILE*)up;
	fseek(fp, fo, SEEK_SET);

	return result;
}

static int _file_read(struct mb_interpreter_t* s, void** l) {
	int result = MB_FUNC_OK;
	FILE* fp = 0;
	void* up = 0;
	int ln = 0;

	mb_assert(s && l);

	mb_check(mb_attempt_open_bracket(s, l));

	mb_check(mb_pop_usertype(s, l, &up));

	if(mb_has_arg(s, l)) {
		mb_check(mb_pop_int(s, l, &ln));
	}

	mb_check(mb_attempt_close_bracket(s, l));

	if(!up) {
		result = MB_FUNC_ERR;

		goto _exit;
	}

	fp = (FILE*)up;
	if(ln) {
		char* buf = (char*)malloc(ln + 1);
		fgets(buf, ln + 1, fp);
		buf[ln] = '\0';
		mb_check(mb_push_string(s, l, mb_memdup(buf, ln + 1)));
		free(buf);
	} else {
		int ret = fgetc(fp);
		mb_check(mb_push_int(s, l, ret));
	}

_exit:
	return result;
}

static int _file_read_line(struct mb_interpreter_t* s, void** l) {
	int result = MB_FUNC_OK;
	FILE* fp = 0;
	void* up = 0;

	mb_assert(s && l);

	mb_check(mb_attempt_open_bracket(s, l));

	mb_check(mb_pop_usertype(s, l, &up));

	mb_check(mb_attempt_close_bracket(s, l));

	if(!up) {
		result = MB_FUNC_ERR;

		goto _exit;
	}

	fp = (FILE*)up;
	{
		char* buf = 0;
		size_t size = 0;
		while(!feof(fp)) {
			buf = (char*)realloc(buf, ++size);
			buf[size - 1] = (char)fgetc(fp);
			if(buf[size - 1] == '\n' || buf[size - 1] == '\r') {
				long l = ftell(fp);
				if(fgetc(fp) != '\r')
					fseek(fp, l, SEEK_SET);

				break;
			}
		}
		if(buf) {
			buf[size - 1] = '\0';
			mb_check(mb_push_string(s, l, mb_memdup(buf, size)));
		} else {
			mb_check(mb_push_string(s, l, mb_memdup("", 1)));
		}
		if(buf)
			free(buf);
	}

_exit:
	return result;
}

static int _file_write(struct mb_interpreter_t* s, void** l) {
	int result = MB_FUNC_OK;
	FILE* fp = 0;
	void* up = 0;
	mb_value_t val;

	mb_assert(s && l);

	mb_check(mb_attempt_open_bracket(s, l));

	mb_check(mb_pop_usertype(s, l, &up));

	if(!up) {
		result = MB_FUNC_ERR;

		goto _exit;
	}

	fp = (FILE*)up;

	while(mb_has_arg(s, l)) { /* Support variadic */
		mb_check(mb_pop_value(s, l, &val));
		switch(val.type) {
		case MB_DT_INT:
			fputc(val.value.integer, fp);

			break;
		case MB_DT_REAL:
			fputc((int_t)val.value.float_point, fp);

			break;
		case MB_DT_STRING:
			fputs(val.value.string, fp);

			break;
		default:
			result = MB_FUNC_ERR;

			break;
		}
	}

_exit:
	mb_check(mb_attempt_close_bracket(s, l));

	return result;
}

static int _file_write_line(struct mb_interpreter_t* s, void** l) {
	int result = MB_FUNC_OK;
	FILE* fp = 0;
	void* up = 0;
	mb_value_t val;

	mb_assert(s && l);

	mb_check(mb_attempt_open_bracket(s, l));

	mb_check(mb_pop_usertype(s, l, &up));

	if(!up) {
		result = MB_FUNC_ERR;

		goto _exit;
	}

	fp = (FILE*)up;

	while(mb_has_arg(s, l)) { /* Support variadic */
		mb_check(mb_pop_value(s, l, &val));
		switch(val.type) {
		case MB_DT_INT:
			fputc(val.value.integer, fp);

			break;
		case MB_DT_REAL:
			fputc((int_t)val.value.float_point, fp);

			break;
		case MB_DT_STRING:
			fputs(val.value.string, fp);

			break;
		default:
			result = MB_FUNC_ERR;

			break;
		}
	}

	fputc('\n', fp);
	fputc('\r', fp);

_exit:
	mb_check(mb_attempt_close_bracket(s, l));

	return result;
}

Register them:

mb_register_func(bas, "FOPEN", _file_open);
mb_register_func(bas, "FCLOSE", _file_close);
mb_register_func(bas, "FPEEK", _file_peek);
mb_register_func(bas, "FPOKE", _file_poke);
mb_register_func(bas, "FREAD", _file_read);
mb_register_func(bas, "FREAD_LINE", _file_read_line);
mb_register_func(bas, "FWRITE", _file_write);
mb_register_func(bas, "FWRITE_LINE", _file_write_line);

BASIC usage:

f = fopen("file.txt", "w+")

fwrite(f, "123")               ' Write a string
fwrite(f, 10, 13)              ' Write \n\r
fwrite_line(f, "hello world!") ' Write a line

print fpeek(f);

fpoke(f, 0)

s = fread(f, 3)                ' Read a string length 3
n = fread(f)                   ' Read a byte
r = fread(f)                   ' Read another byte
l = fread_line(f)              ' Read a line

print fpeek(f);

print s, n, r, l;              ' Note bytes are printed as int

fclose(f)
Clone this wiki locally