
static JSValue js_sys_file_opt(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, u32 file_opt)
{
	const char *dirname, *newfile;
	char *ext;
	GF_Err e;
	JSValue res;
	if (!argc || !JS_IsString(argv[0])) return GF_JS_EXCEPTION(ctx);
	dirname = JS_ToCString(ctx, argv[0]);
	if (!dirname) return GF_JS_EXCEPTION(ctx);

	res = JS_UNDEFINED;
	switch (file_opt) {
	case OPT_RMDIR:
		e = gf_rmdir(dirname);
		if (e) res = js_throw_err_msg(ctx, e, "Failed to remove dir %s", dirname);
		break;
	case OPT_MKDIR:
		e = gf_mkdir(dirname);
		if (e) res = js_throw_err_msg(ctx, e, "Failed to create dir %s", dirname);
		break;
	case OPT_DIREXISTS:
		res = JS_NewBool(ctx, gf_dir_exists(dirname) );
		break;
	case OPT_DIRCLEAN:
		e = gf_dir_cleanup(dirname);
		if (e) res = js_throw_err_msg(ctx, e, "Failed to clean dir %s", dirname);
		break;
	case OPT_FILEBASENAME:
		res = JS_NewString(ctx, gf_file_basename(dirname) );
		break;
	case OPT_FILEEXT:
		ext = gf_file_ext_start(dirname);
		res = ext ? JS_NewString(ctx, ext) : JS_NULL;
		break;
	case OPT_FILEDEL:
		e = gf_file_delete(dirname);
		if (e) res = js_throw_err_msg(ctx, e, "Failed to delete file %s", dirname);
		break;
	case OPT_FILEMODTIME:
		res = JS_NewInt64(ctx, gf_file_modification_time(dirname) );
		break;
	case OPT_FILEEXISTS:
		res = JS_NewBool(ctx, gf_file_exists(dirname) );
		break;
	case OPT_FILEMOVE:
		newfile = (argc<2) ? NULL : JS_ToCString(ctx, argv[1]);
		if (!newfile) res = js_throw_err_msg(ctx, GF_BAD_PARAM, "Missing new file name");
		else {
			e = gf_file_move(dirname, newfile);
			if (e) res = js_throw_err_msg(ctx, e, "Failed to move file %s to %s", dirname, newfile);
			JS_FreeCString(ctx, newfile);
		}
		break;
	}

	JS_FreeCString(ctx, dirname);
	return res;

static JSValue js_sys_file_opt(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, u32 file_opt)
{
	const char *dirname, *newfile;
	char *ext;
	GF_Err e;
	JSValue res;
	if (!argc || !JS_IsString(argv[0])) return GF_JS_EXCEPTION(ctx);
	dirname = JS_ToCString(ctx, argv[0]);
	if (!dirname) return GF_JS_EXCEPTION(ctx);

	res = JS_UNDEFINED;
	switch (file_opt) {
	case OPT_RMDIR:
		e = gf_rmdir(dirname);
		if (e) res = js_throw_err_msg(ctx, e, "Failed to remove dir %s", dirname);
		break;
	case OPT_MKDIR:
		e = gf_mkdir(dirname);
		if (e) res = js_throw_err_msg(ctx, e, "Failed to create dir %s", dirname);
		break;
	case OPT_DIREXISTS:
		res = JS_NewBool(ctx, gf_dir_exists(dirname) );
		break;
	case OPT_DIRCLEAN:
		e = gf_dir_cleanup(dirname);
		if (e) res = js_throw_err_msg(ctx, e, "Failed to clean dir %s", dirname);
		break;
	case OPT_FILEBASENAME:
		res = JS_NewString(ctx, gf_file_basename(dirname) );
		break;
	case OPT_FILEEXT:
		ext = gf_file_ext_start(dirname);
		res = ext ? JS_NewString(ctx, ext) : JS_NULL;
		break;
	case OPT_FILEDEL:
		e = gf_file_delete(dirname);
		if (e) res = js_throw_err_msg(ctx, e, "Failed to delete file %s", dirname);
		break;
	case OPT_FILEMODTIME:
		res = JS_NewInt64(ctx, gf_file_modification_time(dirname) );
		break;
	case OPT_FILEEXISTS:
		res = JS_NewBool(ctx, gf_file_exists(dirname) );
		break;
	case OPT_FILEMOVE:
		newfile = (argc<2) ? NULL : JS_ToCString(ctx, argv[1]);
		if (!newfile) res = js_throw_err_msg(ctx, GF_BAD_PARAM, "Missing new file name");
		else {
			e = gf_file_move(dirname, newfile);
			if (e) res = js_throw_err_msg(ctx, e, "Failed to move file %s to %s", dirname, newfile);
			JS_FreeCString(ctx, newfile);
		}
		break;
	}

	JS_FreeCString(ctx, dirname);
	return res;