<commit_before>#include "UnrealEnginePythonPrivatePCH.h"

#if WITH_EDITOR

static PyObject *py_ue_fraw_mesh_set_vertex_positions(ue_PyFRawMesh *self, PyObject * args) {
	PyObject *data;
	if (!PyArg_ParseTuple(args, "O:set_vertex_positions", &data)) {
		return nullptr;
	}

	PyObject *iter = PyObject_GetIter(data);
	if (!iter)
		return PyErr_Format(PyExc_TypeError, "argument is not an iterable");

	TArray<FVector> vertex;

	for (;;) {
		PyObject *item_x = PyIter_Next(iter);
		if (!item_x)
			break;
		if (!PyNumber_Check(item_x))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_x = PyNumber_Float(item_x);
		float x = PyFloat_AsDouble(py_x);
		Py_DECREF(py_x);

		PyObject *item_y = PyIter_Next(iter);
		if (!item_y)
			break;
		if (!PyNumber_Check(item_y))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_y = PyNumber_Float(item_y);
		float y = PyFloat_AsDouble(py_y);
		Py_DECREF(py_y);

		PyObject *item_z = PyIter_Next(iter);
		if (!item_z)
			break;
		if (!PyNumber_Check(item_z))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_z = PyNumber_Float(item_z);
		float z = PyFloat_AsDouble(py_z);
		Py_DECREF(py_z);

		vertex.Add(FVector(x, y, z));
	}

	self->raw_mesh->VertexPositions = vertex;

	Py_DECREF(iter);

	Py_RETURN_NONE;
}

static PyObject *py_ue_fraw_mesh_set_wedge_tex_coords(ue_PyFRawMesh *self, PyObject * args) {
	PyObject *data;
	int index = 0;
	if (!PyArg_ParseTuple(args, "O|i:set_wedge_tex_coords", &data, &index)) {
		return nullptr;
	}

	PyObject *iter = PyObject_GetIter(data);
	if (!iter)
		return PyErr_Format(PyExc_TypeError, "argument is not an iterable");

	TArray<FVector2D> uv;

	for (;;) {
		PyObject *item_x = PyIter_Next(iter);
		if (!item_x)
			break;
		if (!PyNumber_Check(item_x))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_x = PyNumber_Float(item_x);
		float x = PyFloat_AsDouble(py_x);
		Py_DECREF(py_x);

		PyObject *item_y = PyIter_Next(iter);
		if (!item_y)
			break;
		if (!PyNumber_Check(item_y))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_y = PyNumber_Float(item_y);
		float y = PyFloat_AsDouble(py_y);
		Py_DECREF(py_y);

		uv.Add(FVector2D(x, y));
	}

	self->raw_mesh->WedgeTexCoords[index] = uv;

	Py_DECREF(iter);

	Py_RETURN_NONE;
}

static PyObject *py_ue_fraw_mesh_set_wedge_indices(ue_PyFRawMesh *self, PyObject * args) {
	PyObject *data;
	if (!PyArg_ParseTuple(args, "O:set_wedge_indices", &data)) {
		return nullptr;
	}

	PyObject *iter = PyObject_GetIter(data);
	if (!iter)
		return PyErr_Format(PyExc_TypeError, "argument is not an iterable");

	TArray<uint32> indices;

	for (;;) {
		PyObject *item = PyIter_Next(iter);
		if (!item)
			break;
		if (!PyNumber_Check(item))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_value = PyNumber_Long(item);
		uint32 i = PyLong_AsUnsignedLong(py_value);
		Py_DECREF(py_value);

		indices.Add(i);
	}

	self->raw_mesh->WedgeIndices = indices;

	Py_DECREF(iter);

	Py_RETURN_NONE;
}

static PyObject *py_ue_fraw_mesh_save_to_static_mesh_source_model(ue_PyFRawMesh *self, PyObject * args) {
	PyObject *model;
	if (!PyArg_ParseTuple(args, "O:save_to_static_mesh_source_model", &model)) {
		return nullptr;
	}

	FStaticMeshSourceModel *source_model = ue_py_check_struct<FStaticMeshSourceModel>(model);
	if (!source_model)
		return PyErr_Format(PyExc_Exception, "argument is not a FStaticMeshSourceModel");

	if (self->raw_mesh->WedgeIndices.Num() >= 3) {
		// set default sane values (read: 0) to face materials and smoothing groups
		if (self->raw_mesh->FaceSmoothingMasks.Num() == 0)
			self->raw_mesh->FaceSmoothingMasks.AddDefaulted(self->raw_mesh->WedgeIndices.Num() / 3);
		if (self->raw_mesh->FaceMaterialIndices.Num() == 0)
			self->raw_mesh->FaceMaterialIndices.AddDefaulted(self->raw_mesh->WedgeIndices.Num() / 3);
	}

	if (!self->raw_mesh->IsValidOrFixable())
		return PyErr_Format(PyExc_Exception, "FRawMesh is not valid or fixable");

	source_model->RawMeshBulkData->SaveRawMesh(*self->raw_mesh);

	Py_RETURN_NONE;
}

static PyObject *py_ue_fraw_mesh_get_wedge_position(ue_PyFRawMesh *self, PyObject * args) {
	int index;
	if (!PyArg_ParseTuple(args, "i:get_wedge_position", &index)) {
		return nullptr;
	}

	if (index > self->raw_mesh->WedgeIndices.Num() - 1 || index < 0)
		return PyErr_Format(PyExc_IndexError, "wedge index error");

	FVector vec = self->raw_mesh->GetWedgePosition(index);

	return py_ue_new_fvector(vec);
}

static PyMethodDef ue_PyFRawMesh_methods[] = {
	{ "set_vertex_positions", (PyCFunction)py_ue_fraw_mesh_set_vertex_positions, METH_VARARGS, "" },
	{ "set_wedge_indices", (PyCFunction)py_ue_fraw_mesh_set_wedge_indices, METH_VARARGS, "" },
	{ "set_wedge_tex_coords", (PyCFunction)py_ue_fraw_mesh_set_wedge_tex_coords, METH_VARARGS, "" },
	{ "get_wedge_position", (PyCFunction)py_ue_fraw_mesh_get_wedge_position, METH_VARARGS, "" },
	{ "save_to_static_mesh_source_model", (PyCFunction)py_ue_fraw_mesh_save_to_static_mesh_source_model, METH_VARARGS, "" },
	{ NULL }  /* Sentinel */
};

static int ue_py_fraw_mesh_init(ue_PyFRawMesh *self, PyObject *args, PyObject *kwargs) {
	self->raw_mesh = new FRawMesh();
	return 0;
}

static void ue_py_fraw_mesh_dealloc(ue_PyFRawMesh *self) {
	if (self->raw_mesh)
		delete(self->raw_mesh);
#if PY_MAJOR_VERSION < 3
	self->ob_type->tp_free((PyObject*)self);
#else
	Py_TYPE(self)->tp_free((PyObject*)self);
#endif
}

static PyTypeObject ue_PyFRawMeshType = {
	PyVarObject_HEAD_INIT(NULL, 0)
	"unreal_engine.FRawMesh", /* tp_name */
	sizeof(ue_PyFRawMesh),    /* tp_basicsize */
	0,                         /* tp_itemsize */
	(destructor)ue_py_fraw_mesh_dealloc,   /* tp_dealloc */
	0,                         /* tp_print */
	0,                         /* tp_getattr */
	0,                         /* tp_setattr */
	0,                         /* tp_reserved */
	0,                         /* tp_repr */
	0,                         /* tp_as_number */
	0,                         /* tp_as_sequence */
	0,                         /* tp_as_mapping */
	0,                         /* tp_hash  */
	0,                         /* tp_call */
	0,                         /* tp_str */
	0,                         /* tp_getattro */
	0,                         /* tp_setattro */
	0,                         /* tp_as_buffer */
	Py_TPFLAGS_DEFAULT,        /* tp_flags */
	"Unreal Engine FRawMesh", /* tp_doc */
	0,                         /* tp_traverse */
	0,                         /* tp_clear */
	0,                         /* tp_richcompare */
	0,                         /* tp_weaklistoffset */
	0,                         /* tp_iter */
	0,                         /* tp_iternext */
	ue_PyFRawMesh_methods,    /* tp_methods */
	0,   /* tp_members */
	0,                         /* tp_getset */
};

void ue_python_init_fraw_mesh(PyObject *ue_module) {
	ue_PyFRawMeshType.tp_new = PyType_GenericNew;;
	ue_PyFRawMeshType.tp_init = (initproc)ue_py_fraw_mesh_init;
	if (PyType_Ready(&ue_PyFRawMeshType) < 0)
		return;

	Py_INCREF(&ue_PyFRawMeshType);
	PyModule_AddObject(ue_module, "FRawMesh", (PyObject *)&ue_PyFRawMeshType);
}

#endif
<commit_msg>exposed more wedge configurations for FRawMesh<commit_after>#include "UnrealEnginePythonPrivatePCH.h"

#if WITH_EDITOR

static PyObject *py_ue_fraw_mesh_set_vertex_positions(ue_PyFRawMesh *self, PyObject * args) {
	PyObject *data;
	if (!PyArg_ParseTuple(args, "O:set_vertex_positions", &data)) {
		return nullptr;
	}

	PyObject *iter = PyObject_GetIter(data);
	if (!iter)
		return PyErr_Format(PyExc_TypeError, "argument is not an iterable");

	TArray<FVector> vertex;

	for (;;) {
		PyObject *item_x = PyIter_Next(iter);
		if (!item_x)
			break;
		if (!PyNumber_Check(item_x))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_x = PyNumber_Float(item_x);
		float x = PyFloat_AsDouble(py_x);
		Py_DECREF(py_x);

		PyObject *item_y = PyIter_Next(iter);
		if (!item_y)
			break;
		if (!PyNumber_Check(item_y))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_y = PyNumber_Float(item_y);
		float y = PyFloat_AsDouble(py_y);
		Py_DECREF(py_y);

		PyObject *item_z = PyIter_Next(iter);
		if (!item_z)
			break;
		if (!PyNumber_Check(item_z))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_z = PyNumber_Float(item_z);
		float z = PyFloat_AsDouble(py_z);
		Py_DECREF(py_z);

		vertex.Add(FVector(x, y, z));
	}

	self->raw_mesh->VertexPositions = vertex;

	Py_DECREF(iter);

	Py_RETURN_NONE;
}

static PyObject *py_ue_fraw_mesh_set_wedge_tex_coords(ue_PyFRawMesh *self, PyObject * args) {
	PyObject *data;
	int index = 0;
	if (!PyArg_ParseTuple(args, "O|i:set_wedge_tex_coords", &data, &index)) {
		return nullptr;
	}

	PyObject *iter = PyObject_GetIter(data);
	if (!iter)
		return PyErr_Format(PyExc_TypeError, "argument is not an iterable");

	TArray<FVector2D> uv;

	for (;;) {
		PyObject *item_x = PyIter_Next(iter);
		if (!item_x)
			break;
		if (!PyNumber_Check(item_x))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_x = PyNumber_Float(item_x);
		float x = PyFloat_AsDouble(py_x);
		Py_DECREF(py_x);

		PyObject *item_y = PyIter_Next(iter);
		if (!item_y)
			break;
		if (!PyNumber_Check(item_y))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_y = PyNumber_Float(item_y);
		float y = PyFloat_AsDouble(py_y);
		Py_DECREF(py_y);

		uv.Add(FVector2D(x, y));
	}

	self->raw_mesh->WedgeTexCoords[index] = uv;

	Py_DECREF(iter);

	Py_RETURN_NONE;
}

static PyObject *py_ue_fraw_mesh_set_wedge_indices(ue_PyFRawMesh *self, PyObject * args) {
	PyObject *data;
	if (!PyArg_ParseTuple(args, "O:set_wedge_indices", &data)) {
		return nullptr;
	}

	PyObject *iter = PyObject_GetIter(data);
	if (!iter)
		return PyErr_Format(PyExc_TypeError, "argument is not an iterable");

	TArray<uint32> indices;

	for (;;) {
		PyObject *item = PyIter_Next(iter);
		if (!item)
			break;
		if (!PyNumber_Check(item))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_value = PyNumber_Long(item);
		uint32 i = PyLong_AsUnsignedLong(py_value);
		Py_DECREF(py_value);

		indices.Add(i);
	}

	self->raw_mesh->WedgeIndices = indices;

	Py_DECREF(iter);

	Py_RETURN_NONE;
}

static PyObject *py_ue_fraw_mesh_save_to_static_mesh_source_model(ue_PyFRawMesh *self, PyObject * args) {
	PyObject *model;
	if (!PyArg_ParseTuple(args, "O:save_to_static_mesh_source_model", &model)) {
		return nullptr;
	}

	FStaticMeshSourceModel *source_model = ue_py_check_struct<FStaticMeshSourceModel>(model);
	if (!source_model)
		return PyErr_Format(PyExc_Exception, "argument is not a FStaticMeshSourceModel");

	if (self->raw_mesh->WedgeIndices.Num() >= 3) {
		// set default sane values (read: 0) to face materials and smoothing groups
		if (self->raw_mesh->FaceSmoothingMasks.Num() == 0)
			self->raw_mesh->FaceSmoothingMasks.AddDefaulted(self->raw_mesh->WedgeIndices.Num() / 3);
		if (self->raw_mesh->FaceMaterialIndices.Num() == 0)
			self->raw_mesh->FaceMaterialIndices.AddDefaulted(self->raw_mesh->WedgeIndices.Num() / 3);
	}

	if (!self->raw_mesh->IsValidOrFixable())
		return PyErr_Format(PyExc_Exception, "FRawMesh is not valid or fixable");

	source_model->RawMeshBulkData->SaveRawMesh(*self->raw_mesh);

	Py_RETURN_NONE;
}

static PyObject *py_ue_fraw_mesh_get_wedge_position(ue_PyFRawMesh *self, PyObject * args) {
	int index;
	if (!PyArg_ParseTuple(args, "i:get_wedge_position", &index)) {
		return nullptr;
	}

	if (index > self->raw_mesh->WedgeIndices.Num() - 1 || index < 0)
		return PyErr_Format(PyExc_IndexError, "wedge index error");

	FVector vec = self->raw_mesh->GetWedgePosition(index);

	return py_ue_new_fvector(vec);
}

static PyObject *py_ue_fraw_mesh_set_wedge_tangent_x(ue_PyFRawMesh *self, PyObject * args) {
	PyObject *data;
	if (!PyArg_ParseTuple(args, "O:set_wedge_tangent_x", &data)) {
		return nullptr;
	}

	PyObject *iter = PyObject_GetIter(data);
	if (!iter)
		return PyErr_Format(PyExc_TypeError, "argument is not an iterable");

	TArray<FVector> vertex;

	for (;;) {
		PyObject *item_x = PyIter_Next(iter);
		if (!item_x)
			break;
		if (!PyNumber_Check(item_x))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_x = PyNumber_Float(item_x);
		float x = PyFloat_AsDouble(py_x);
		Py_DECREF(py_x);

		PyObject *item_y = PyIter_Next(iter);
		if (!item_y)
			break;
		if (!PyNumber_Check(item_y))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_y = PyNumber_Float(item_y);
		float y = PyFloat_AsDouble(py_y);
		Py_DECREF(py_y);

		PyObject *item_z = PyIter_Next(iter);
		if (!item_z)
			break;
		if (!PyNumber_Check(item_z))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_z = PyNumber_Float(item_z);
		float z = PyFloat_AsDouble(py_z);
		Py_DECREF(py_z);

		vertex.Add(FVector(x, y, z));
	}

	self->raw_mesh->WedgeTangentX = vertex;

	Py_DECREF(iter);

	Py_RETURN_NONE;
}

static PyObject *py_ue_fraw_mesh_set_wedge_tangent_y(ue_PyFRawMesh *self, PyObject * args) {
	PyObject *data;
	if (!PyArg_ParseTuple(args, "O:set_wedge_tangent_y", &data)) {
		return nullptr;
	}

	PyObject *iter = PyObject_GetIter(data);
	if (!iter)
		return PyErr_Format(PyExc_TypeError, "argument is not an iterable");

	TArray<FVector> vertex;

	for (;;) {
		PyObject *item_x = PyIter_Next(iter);
		if (!item_x)
			break;
		if (!PyNumber_Check(item_x))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_x = PyNumber_Float(item_x);
		float x = PyFloat_AsDouble(py_x);
		Py_DECREF(py_x);

		PyObject *item_y = PyIter_Next(iter);
		if (!item_y)
			break;
		if (!PyNumber_Check(item_y))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_y = PyNumber_Float(item_y);
		float y = PyFloat_AsDouble(py_y);
		Py_DECREF(py_y);

		PyObject *item_z = PyIter_Next(iter);
		if (!item_z)
			break;
		if (!PyNumber_Check(item_z))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_z = PyNumber_Float(item_z);
		float z = PyFloat_AsDouble(py_z);
		Py_DECREF(py_z);

		vertex.Add(FVector(x, y, z));
	}

	self->raw_mesh->WedgeTangentY = vertex;

	Py_DECREF(iter);

	Py_RETURN_NONE;
}

static PyObject *py_ue_fraw_mesh_set_wedge_tangent_z(ue_PyFRawMesh *self, PyObject * args) {
	PyObject *data;
	if (!PyArg_ParseTuple(args, "O:set_wedge_tangent_z", &data)) {
		return nullptr;
	}

	PyObject *iter = PyObject_GetIter(data);
	if (!iter)
		return PyErr_Format(PyExc_TypeError, "argument is not an iterable");

	TArray<FVector> vertex;

	for (;;) {
		PyObject *item_x = PyIter_Next(iter);
		if (!item_x)
			break;
		if (!PyNumber_Check(item_x))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_x = PyNumber_Float(item_x);
		float x = PyFloat_AsDouble(py_x);
		Py_DECREF(py_x);

		PyObject *item_y = PyIter_Next(iter);
		if (!item_y)
			break;
		if (!PyNumber_Check(item_y))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_y = PyNumber_Float(item_y);
		float y = PyFloat_AsDouble(py_y);
		Py_DECREF(py_y);

		PyObject *item_z = PyIter_Next(iter);
		if (!item_z)
			break;
		if (!PyNumber_Check(item_z))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_z = PyNumber_Float(item_z);
		float z = PyFloat_AsDouble(py_z);
		Py_DECREF(py_z);

		vertex.Add(FVector(x, y, z));
	}

	self->raw_mesh->WedgeTangentZ = vertex;

	Py_DECREF(iter);

	Py_RETURN_NONE;
}

static PyObject *py_ue_fraw_mesh_set_wedge_colors(ue_PyFRawMesh *self, PyObject * args) {
	PyObject *data;
	if (!PyArg_ParseTuple(args, "O:set_wedge_colors", &data)) {
		return nullptr;
	}

	PyObject *iter = PyObject_GetIter(data);
	if (!iter)
		return PyErr_Format(PyExc_TypeError, "argument is not an iterable");

	TArray<FColor> colors;

	for (;;) {
		PyObject *item_x = PyIter_Next(iter);
		if (!item_x)
			break;
		if (!PyNumber_Check(item_x))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_x = PyNumber_Long(item_x);
		uint8 x = PyLong_AsUnsignedLong(py_x);
		Py_DECREF(py_x);

		PyObject *item_y = PyIter_Next(iter);
		if (!item_y)
			break;
		if (!PyNumber_Check(item_y))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_y = PyNumber_Long(item_y);
		uint8 y = PyLong_AsUnsignedLong(py_y);
		Py_DECREF(py_y);

		PyObject *item_z = PyIter_Next(iter);
		if (!item_z)
			break;
		if (!PyNumber_Check(item_z))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_z = PyNumber_Long(item_z);
		uint8 z = PyLong_AsUnsignedLong(py_z);
		Py_DECREF(py_z);

		PyObject *item_a = PyIter_Next(iter);
		if (!item_a)
			break;
		if (!PyNumber_Check(item_a))
			return PyErr_Format(PyExc_Exception, "argument iterable does not contains only numbers");
		PyObject *py_a = PyNumber_Long(item_a);
		uint8 a = PyLong_AsUnsignedLong(py_a);
		Py_DECREF(py_a);

		colors.Add(FColor(x, y, z, a));
	}

	self->raw_mesh->WedgeColors = colors;

	Py_DECREF(iter);

	Py_RETURN_NONE;
}

static PyMethodDef ue_PyFRawMesh_methods[] = {
	{ "set_vertex_positions", (PyCFunction)py_ue_fraw_mesh_set_vertex_positions, METH_VARARGS, "" },
	{ "set_wedge_indices", (PyCFunction)py_ue_fraw_mesh_set_wedge_indices, METH_VARARGS, "" },
	{ "set_wedge_tex_coords", (PyCFunction)py_ue_fraw_mesh_set_wedge_tex_coords, METH_VARARGS, "" },
	{ "set_wedge_tangent_x", (PyCFunction)py_ue_fraw_mesh_set_wedge_tangent_x, METH_VARARGS, "" },
	{ "set_wedge_tangent_y", (PyCFunction)py_ue_fraw_mesh_set_wedge_tangent_y, METH_VARARGS, "" },
	{ "set_wedge_tangent_z", (PyCFunction)py_ue_fraw_mesh_set_wedge_tangent_z, METH_VARARGS, "" },
	{ "set_wedge_colors", (PyCFunction)py_ue_fraw_mesh_set_wedge_colors, METH_VARARGS, "" },
	{ "get_wedge_position", (PyCFunction)py_ue_fraw_mesh_get_wedge_position, METH_VARARGS, "" },
	{ "save_to_static_mesh_source_model", (PyCFunction)py_ue_fraw_mesh_save_to_static_mesh_source_model, METH_VARARGS, "" },
	{ NULL }  /* Sentinel */
};

static int ue_py_fraw_mesh_init(ue_PyFRawMesh *self, PyObject *args, PyObject *kwargs) {
	self->raw_mesh = new FRawMesh();
	return 0;
}

static void ue_py_fraw_mesh_dealloc(ue_PyFRawMesh *self) {
	if (self->raw_mesh)
		delete(self->raw_mesh);
#if PY_MAJOR_VERSION < 3
	self->ob_type->tp_free((PyObject*)self);
#else
	Py_TYPE(self)->tp_free((PyObject*)self);
#endif
}

static PyTypeObject ue_PyFRawMeshType = {
	PyVarObject_HEAD_INIT(NULL, 0)
	"unreal_engine.FRawMesh", /* tp_name */
	sizeof(ue_PyFRawMesh),    /* tp_basicsize */
	0,                         /* tp_itemsize */
	(destructor)ue_py_fraw_mesh_dealloc,   /* tp_dealloc */
	0,                         /* tp_print */
	0,                         /* tp_getattr */
	0,                         /* tp_setattr */
	0,                         /* tp_reserved */
	0,                         /* tp_repr */
	0,                         /* tp_as_number */
	0,                         /* tp_as_sequence */
	0,                         /* tp_as_mapping */
	0,                         /* tp_hash  */
	0,                         /* tp_call */
	0,                         /* tp_str */
	0,                         /* tp_getattro */
	0,                         /* tp_setattro */
	0,                         /* tp_as_buffer */
	Py_TPFLAGS_DEFAULT,        /* tp_flags */
	"Unreal Engine FRawMesh", /* tp_doc */
	0,                         /* tp_traverse */
	0,                         /* tp_clear */
	0,                         /* tp_richcompare */
	0,                         /* tp_weaklistoffset */
	0,                         /* tp_iter */
	0,                         /* tp_iternext */
	ue_PyFRawMesh_methods,    /* tp_methods */
	0,   /* tp_members */
	0,                         /* tp_getset */
};

void ue_python_init_fraw_mesh(PyObject *ue_module) {
	ue_PyFRawMeshType.tp_new = PyType_GenericNew;;
	ue_PyFRawMeshType.tp_init = (initproc)ue_py_fraw_mesh_init;
	if (PyType_Ready(&ue_PyFRawMeshType) < 0)
		return;

	Py_INCREF(&ue_PyFRawMeshType);
	PyModule_AddObject(ue_module, "FRawMesh", (PyObject *)&ue_PyFRawMeshType);
}

#endif
<|endoftext|>


<commit_before>#pragma once

#include <tuple>
#include <typeinfo>
#include <limits>
#include <utility>

namespace mtl {

namespace internal {
    static constexpr std::size_t Max = std::numeric_limits<std::size_t>::max();

    template<typename Target, class Tuple> struct index_of_type;
    template<typename Target>
        struct index_of_type<Target, std::tuple<>> {
            static constexpr auto value = Max;
        };
    template<typename Target, typename... Rest>
        struct index_of_type<Target, std::tuple<Target, Rest...>> {
            static constexpr auto value = 0;
        };
    template<typename Target, typename First, typename... Rest>
        struct index_of_type<Target, std::tuple<First, Rest...>> {
            static constexpr auto next = index_of_type<Target, std::tuple<Rest...>>::value;
            static constexpr auto value = next == Max ? Max : next + 1;
        };

    template <typename Target, class Tuple, std::size_t From = 0>
        struct has_type {
            static constexpr auto value = internal::index_of_type<Target, Tuple>::value != internal::Max;
        };

    template<typename Result, typename... Tuples> struct ConcatImpl;
    template<typename... Result, typename... Types>
        struct ConcatImpl<std::tuple<Result...>, std::tuple<Types...>> {
            using type = std::tuple<Result..., Types...>;
        };
    template<typename... Result, typename... Types, typename... Tuples>
        struct ConcatImpl<std::tuple<Result...>, std::tuple<Types...>, Tuples...> {
            using type = typename ConcatImpl<std::tuple<Result..., Types...>, Tuples...>::type;
        };

    template<typename Tuple> struct TailImpl;
    template<> struct TailImpl<std::tuple<>> { using type = std::tuple<>; };
    template<typename First, typename... Params>
        struct TailImpl<std::tuple<First, Params...>> {
            using type = std::tuple<Params...>;
        };

    template<typename Tuple, template<typename> class Operation> struct TransformImpl;
    template<template<typename> class Operation, typename... Params>
        struct TransformImpl<std::tuple<Params...>, Operation> {
            using type = std::tuple<typename Operation<Params>::type...>;
        };

    template<template<typename> class Predicate, typename Tuple, typename Result = std::tuple<>, typename Enable = void> struct FilterImpl;
    template<template<typename> class Predicate, typename... Done>
        struct FilterImpl<Predicate, std::tuple<>, std::tuple<Done...>> {
            using type = std::tuple<Done...>;
        };
    template<template<typename> class Predicate, typename Head, typename... Tail, typename... Done>
        struct FilterImpl<Predicate, std::tuple<Head, Tail...>, std::tuple<Done...>,
            typename std::enable_if<!Predicate<Head>::value>::type> {
            using type = typename FilterImpl<Predicate, std::tuple<Tail...>, std::tuple<Done...>>::type;
        };
    template<template<typename> class Predicate, typename Head, typename... Tail, typename... Done>
        struct FilterImpl<Predicate, std::tuple<Head, Tail...>, std::tuple<Done...>,
            typename std::enable_if<Predicate<Head>::value>::type> {
            using type = typename FilterImpl<Predicate, std::tuple<Tail...>, std::tuple<Done..., Head>>::type;
        };

    template<typename Tuple, typename Result = std::tuple<>, typename Enabled = void> struct UniqueImpl;
    template<typename... Result>
        struct UniqueImpl<std::tuple<>, std::tuple<Result...>> {
            using type = std::tuple<Result...>;
        };
    template<typename... Result, typename Head, typename... Rest>
        struct UniqueImpl<std::tuple<Head, Rest...>, std::tuple<Result...>,
            typename std::enable_if<has_type<Head, std::tuple<Result...>>::value>::type> {
            using type = typename UniqueImpl<std::tuple<Rest...>, std::tuple<Result...>>::type;
        };
    template<typename... Result, typename Head, typename... Rest>
        struct UniqueImpl<std::tuple<Head, Rest...>, std::tuple<Result...>,
            typename std::enable_if<!has_type<Head, std::tuple<Result...>>::value>::type> {
            using type = typename UniqueImpl<std::tuple<Rest...>, std::tuple<Result..., Head>>::type;
        };

    template<typename T>
        struct WithoutFilter {
            template<typename G>
                struct Predicate {
                    static constexpr auto value = !std::is_same<T, G>::value;
                };
        };
    template<typename T, typename Tuple> struct WithoutImpl;
    template<typename T, typename... Params>
        struct WithoutImpl<T, std::tuple<Params...>> {
            using type = typename FilterImpl<WithoutFilter<T>::template Predicate, std::tuple<Params...>, std::tuple<>>::type;
        };

    template<typename A, typename B, typename Result = std::tuple<>> struct InterleaveImpl;
    template<typename... Result>
        struct InterleaveImpl<std::tuple<>, std::tuple<>, std::tuple<Result...>> {
            using type = std::tuple<Result...>;
        };
    template<typename... AParams, typename... Result>
        struct InterleaveImpl<std::tuple<AParams...>, std::tuple<>, std::tuple<Result...>> {
            using type = std::tuple<Result..., AParams...>;
        };
    template<typename... BParams, typename... Result>
        struct InterleaveImpl<std::tuple<>, std::tuple<BParams...>, std::tuple<Result...>> {
            using type = std::tuple<Result..., BParams...>;
        };
    template<typename AFirst, typename... AParams, typename BFirst, typename... BParams, typename... Result>
        struct InterleaveImpl<std::tuple<AFirst, AParams...>, std::tuple<BFirst, BParams...>, std::tuple<Result...>> {
            using type = typename InterleaveImpl<std::tuple<AParams...>, std::tuple<BParams...>, std::tuple<Result..., AFirst, BFirst>>::type;
        };

    template<typename T1, typename T2, typename CompT>
        struct LessOrSame {
            static constexpr auto value = index_of_type<T1, CompT>::value <= index_of_type<T2, CompT>::value;
        };

    template<typename A, typename B, typename Comparison, typename Result = std::tuple<>, typename Enabled = void> struct MergeImpl {};
    template<typename... Right, typename... ResultArgs, typename Comp>
        struct MergeImpl<std::tuple<>, std::tuple<Right...>, Comp, std::tuple<ResultArgs...>> {
            using type = std::tuple<ResultArgs..., Right...>;
        };
    template<typename... Left, typename... ResultArgs, typename Comp>
        struct MergeImpl<std::tuple<Left...>, std::tuple<>, Comp, std::tuple<ResultArgs...>> {
            using type = std::tuple<ResultArgs..., Left...>;
        };
    template<typename LeftHead, typename RightHead, typename... Left, typename... Right, typename Comp, typename... ResultArgs>
        struct MergeImpl<std::tuple<LeftHead, Left...>, std::tuple<RightHead, Right...>, Comp, std::tuple<ResultArgs...>,
                typename std::enable_if<!LessOrSame<LeftHead, RightHead, Comp>::value>::type> {
            using type = typename MergeImpl<std::tuple<LeftHead, Left...>, std::tuple<Right...>, Comp, std::tuple<ResultArgs..., RightHead>>::type;
        };
    template<typename LeftHead, typename RightHead, typename... Left, typename... Right, typename Comp, typename... ResultArgs>
        struct MergeImpl<std::tuple<LeftHead, Left...>, std::tuple<RightHead, Right...>, Comp, std::tuple<ResultArgs...>,
                typename std::enable_if<LessOrSame<LeftHead, RightHead, Comp>::value>::type> {
            using type = typename MergeImpl<std::tuple<Left...>, std::tuple<RightHead, Right...>, Comp, std::tuple<ResultArgs..., LeftHead>>::type;
        };

    template<typename Tuple, typename Pivot, typename Comp, typename Left = std::tuple<>, typename Right = std::tuple<>, typename Enabled = void> struct PartitionImpl;
    template<typename Pivot, typename Comp, typename... Left, typename... Right>
        struct PartitionImpl<std::tuple<>, Pivot, Comp, std::tuple<Left...>, std::tuple<Right...>> {
            using left = std::tuple<Left...>;
            using right = std::tuple<Right...>;
        };
    template<typename Head, typename... Rest, typename Pivot, typename Comp, typename... Left, typename... Right>
        struct PartitionImpl<std::tuple<Head, Rest...>, Pivot, Comp, std::tuple<Left...>, std::tuple<Right...>,
                     typename std::enable_if<LessOrSame<Head, Pivot, Comp>::value>::type> {
            using left = typename PartitionImpl<std::tuple<Rest...>, Pivot, Comp, std::tuple<Left..., Head>, std::tuple<Right...>>::left;
            using right = typename PartitionImpl<std::tuple<Rest...>, Pivot, Comp, std::tuple<Left..., Head>, std::tuple<Right...>>::right;
        };
    template<typename Head, typename... Rest, typename Pivot, typename Comp, typename... Left, typename... Right>
        struct PartitionImpl<std::tuple<Head, Rest...>, Pivot, Comp, std::tuple<Left...>, std::tuple<Right...>,
                     typename std::enable_if<!LessOrSame<Head, Pivot, Comp>::value>::type> {
            using left = typename PartitionImpl<std::tuple<Rest...>, Pivot, Comp, std::tuple<Left...>, std::tuple<Right..., Head>>::left;
            using right = typename PartitionImpl<std::tuple<Rest...>, Pivot, Comp, std::tuple<Left...>, std::tuple<Right..., Head>>::right;
        };

    template<typename Tuple, typename Comparison, typename Enabled = void> struct SortImpl;
    template<typename Comparison> struct SortImpl<std::tuple<>, Comparison> { using type = std::tuple<>; };
    template<typename Head, typename Comparison> struct SortImpl<std::tuple<Head>, Comparison> { using type = std::tuple<Head>; };
    template<typename Head, typename... Rest, typename Comparison>
        struct SortImpl<std::tuple<Head, Rest...>, Comparison> {
            using partition = PartitionImpl<std::tuple<Rest...>, Head, Comparison>;
            using sorted_left = typename SortImpl<typename partition::left, Comparison>::type;
            using sorted_right = typename SortImpl<typename partition::right, Comparison>::type;
            using type = typename ConcatImpl<sorted_left, std::tuple<Head>, sorted_right>::type;
        };

} // namespace internal

template<typename Target, class Tuple, std::size_t From = 0> using has_type = typename internal::has_type<Target, Tuple, From>;
template<typename Tuple, std::size_t... Idx> using select = std::tuple<typename std::tuple_element<Idx, Tuple>::type...>;
template<typename Tuple> using head = typename std::tuple_element<0, Tuple>::type;
template<typename Tuple> using tail = typename internal::TailImpl<Tuple>::type;
template<typename... Tuples> using concat = typename internal::ConcatImpl<std::tuple<>, Tuples...>::type;
template<typename Tuple, template<typename> class Operation> using transform = typename internal::TransformImpl<Tuple, Operation>::type;
template<template<typename> class Predicate, typename Tuple> using filter = typename internal::FilterImpl<Predicate, Tuple>::type;
template<typename Tuple> using unique = typename internal::UniqueImpl<Tuple>::type;
template<typename T, typename Tuple> using without = typename internal::WithoutImpl<T, Tuple>::type;
template<typename A, typename B> using interleave = typename internal::InterleaveImpl<A, B>::type;
template<typename A, typename B, typename Comparison> using merge = typename internal::MergeImpl<A, B, unique<Comparison>>::type;
template<typename Tuple, typename Pivot, typename Comparison> using partition = typename internal::PartitionImpl<Tuple, Pivot, Comparison>::type;
template<typename Tuple, typename Comparison> using sort = typename internal::SortImpl<Tuple, Comparison>::type;

} // namespace mtl
<commit_msg>index_of<commit_after>#pragma once

#include <tuple>
#include <typeinfo>
#include <limits>
#include <utility>

namespace mtl {

namespace internal {
    static constexpr std::size_t Max = std::numeric_limits<std::size_t>::max();

    template<typename Target, class Tuple> struct index_of_type;
    template<typename Target>
        struct index_of_type<Target, std::tuple<>> {
            static constexpr auto value = Max;
        };
    template<typename Target, typename... Rest>
        struct index_of_type<Target, std::tuple<Target, Rest...>> {
            static constexpr auto value = 0;
        };
    template<typename Target, typename First, typename... Rest>
        struct index_of_type<Target, std::tuple<First, Rest...>> {
            static constexpr auto next = index_of_type<Target, std::tuple<Rest...>>::value;
            static constexpr auto value = next == Max ? Max : next + 1;
        };

    template <typename Target, class Tuple, std::size_t From = 0>
        struct has_type {
            static constexpr auto value = internal::index_of_type<Target, Tuple>::value != internal::Max;
        };

    template<typename Result, typename... Tuples> struct ConcatImpl;
    template<typename... Result, typename... Types>
        struct ConcatImpl<std::tuple<Result...>, std::tuple<Types...>> {
            using type = std::tuple<Result..., Types...>;
        };
    template<typename... Result, typename... Types, typename... Tuples>
        struct ConcatImpl<std::tuple<Result...>, std::tuple<Types...>, Tuples...> {
            using type = typename ConcatImpl<std::tuple<Result..., Types...>, Tuples...>::type;
        };

    template<typename Tuple> struct TailImpl;
    template<> struct TailImpl<std::tuple<>> { using type = std::tuple<>; };
    template<typename First, typename... Params>
        struct TailImpl<std::tuple<First, Params...>> {
            using type = std::tuple<Params...>;
        };

    template<typename Tuple, template<typename> class Operation> struct TransformImpl;
    template<template<typename> class Operation, typename... Params>
        struct TransformImpl<std::tuple<Params...>, Operation> {
            using type = std::tuple<typename Operation<Params>::type...>;
        };

    template<template<typename> class Predicate, typename Tuple, typename Result = std::tuple<>, typename Enable = void> struct FilterImpl;
    template<template<typename> class Predicate, typename... Done>
        struct FilterImpl<Predicate, std::tuple<>, std::tuple<Done...>> {
            using type = std::tuple<Done...>;
        };
    template<template<typename> class Predicate, typename Head, typename... Tail, typename... Done>
        struct FilterImpl<Predicate, std::tuple<Head, Tail...>, std::tuple<Done...>,
            typename std::enable_if<!Predicate<Head>::value>::type> {
            using type = typename FilterImpl<Predicate, std::tuple<Tail...>, std::tuple<Done...>>::type;
        };
    template<template<typename> class Predicate, typename Head, typename... Tail, typename... Done>
        struct FilterImpl<Predicate, std::tuple<Head, Tail...>, std::tuple<Done...>,
            typename std::enable_if<Predicate<Head>::value>::type> {
            using type = typename FilterImpl<Predicate, std::tuple<Tail...>, std::tuple<Done..., Head>>::type;
        };

    template<typename Tuple, typename Result = std::tuple<>, typename Enabled = void> struct UniqueImpl;
    template<typename... Result>
        struct UniqueImpl<std::tuple<>, std::tuple<Result...>> {
            using type = std::tuple<Result...>;
        };
    template<typename... Result, typename Head, typename... Rest>
        struct UniqueImpl<std::tuple<Head, Rest...>, std::tuple<Result...>,
            typename std::enable_if<has_type<Head, std::tuple<Result...>>::value>::type> {
            using type = typename UniqueImpl<std::tuple<Rest...>, std::tuple<Result...>>::type;
        };
    template<typename... Result, typename Head, typename... Rest>
        struct UniqueImpl<std::tuple<Head, Rest...>, std::tuple<Result...>,
            typename std::enable_if<!has_type<Head, std::tuple<Result...>>::value>::type> {
            using type = typename UniqueImpl<std::tuple<Rest...>, std::tuple<Result..., Head>>::type;
        };

    template<typename T>
        struct WithoutFilter {
            template<typename G>
                struct Predicate {
                    static constexpr auto value = !std::is_same<T, G>::value;
                };
        };
    template<typename T, typename Tuple> struct WithoutImpl;
    template<typename T, typename... Params>
        struct WithoutImpl<T, std::tuple<Params...>> {
            using type = typename FilterImpl<WithoutFilter<T>::template Predicate, std::tuple<Params...>, std::tuple<>>::type;
        };

    template<typename A, typename B, typename Result = std::tuple<>> struct InterleaveImpl;
    template<typename... Result>
        struct InterleaveImpl<std::tuple<>, std::tuple<>, std::tuple<Result...>> {
            using type = std::tuple<Result...>;
        };
    template<typename... AParams, typename... Result>
        struct InterleaveImpl<std::tuple<AParams...>, std::tuple<>, std::tuple<Result...>> {
            using type = std::tuple<Result..., AParams...>;
        };
    template<typename... BParams, typename... Result>
        struct InterleaveImpl<std::tuple<>, std::tuple<BParams...>, std::tuple<Result...>> {
            using type = std::tuple<Result..., BParams...>;
        };
    template<typename AFirst, typename... AParams, typename BFirst, typename... BParams, typename... Result>
        struct InterleaveImpl<std::tuple<AFirst, AParams...>, std::tuple<BFirst, BParams...>, std::tuple<Result...>> {
            using type = typename InterleaveImpl<std::tuple<AParams...>, std::tuple<BParams...>, std::tuple<Result..., AFirst, BFirst>>::type;
        };

    template<typename T1, typename T2, typename CompT>
        struct LessOrSame {
            static constexpr auto value = index_of_type<T1, CompT>::value <= index_of_type<T2, CompT>::value;
        };

    template<typename A, typename B, typename Comparison, typename Result = std::tuple<>, typename Enabled = void> struct MergeImpl {};
    template<typename... Right, typename... ResultArgs, typename Comp>
        struct MergeImpl<std::tuple<>, std::tuple<Right...>, Comp, std::tuple<ResultArgs...>> {
            using type = std::tuple<ResultArgs..., Right...>;
        };
    template<typename... Left, typename... ResultArgs, typename Comp>
        struct MergeImpl<std::tuple<Left...>, std::tuple<>, Comp, std::tuple<ResultArgs...>> {
            using type = std::tuple<ResultArgs..., Left...>;
        };
    template<typename LeftHead, typename RightHead, typename... Left, typename... Right, typename Comp, typename... ResultArgs>
        struct MergeImpl<std::tuple<LeftHead, Left...>, std::tuple<RightHead, Right...>, Comp, std::tuple<ResultArgs...>,
                typename std::enable_if<!LessOrSame<LeftHead, RightHead, Comp>::value>::type> {
            using type = typename MergeImpl<std::tuple<LeftHead, Left...>, std::tuple<Right...>, Comp, std::tuple<ResultArgs..., RightHead>>::type;
        };
    template<typename LeftHead, typename RightHead, typename... Left, typename... Right, typename Comp, typename... ResultArgs>
        struct MergeImpl<std::tuple<LeftHead, Left...>, std::tuple<RightHead, Right...>, Comp, std::tuple<ResultArgs...>,
                typename std::enable_if<LessOrSame<LeftHead, RightHead, Comp>::value>::type> {
            using type = typename MergeImpl<std::tuple<Left...>, std::tuple<RightHead, Right...>, Comp, std::tuple<ResultArgs..., LeftHead>>::type;
        };

    template<typename Tuple, typename Pivot, typename Comp, typename Left = std::tuple<>, typename Right = std::tuple<>, typename Enabled = void> struct PartitionImpl;
    template<typename Pivot, typename Comp, typename... Left, typename... Right>
        struct PartitionImpl<std::tuple<>, Pivot, Comp, std::tuple<Left...>, std::tuple<Right...>> {
            using left = std::tuple<Left...>;
            using right = std::tuple<Right...>;
        };
    template<typename Head, typename... Rest, typename Pivot, typename Comp, typename... Left, typename... Right>
        struct PartitionImpl<std::tuple<Head, Rest...>, Pivot, Comp, std::tuple<Left...>, std::tuple<Right...>,
                     typename std::enable_if<LessOrSame<Head, Pivot, Comp>::value>::type> {
            using left = typename PartitionImpl<std::tuple<Rest...>, Pivot, Comp, std::tuple<Left..., Head>, std::tuple<Right...>>::left;
            using right = typename PartitionImpl<std::tuple<Rest...>, Pivot, Comp, std::tuple<Left..., Head>, std::tuple<Right...>>::right;
        };
    template<typename Head, typename... Rest, typename Pivot, typename Comp, typename... Left, typename... Right>
        struct PartitionImpl<std::tuple<Head, Rest...>, Pivot, Comp, std::tuple<Left...>, std::tuple<Right...>,
                     typename std::enable_if<!LessOrSame<Head, Pivot, Comp>::value>::type> {
            using left = typename PartitionImpl<std::tuple<Rest...>, Pivot, Comp, std::tuple<Left...>, std::tuple<Right..., Head>>::left;
            using right = typename PartitionImpl<std::tuple<Rest...>, Pivot, Comp, std::tuple<Left...>, std::tuple<Right..., Head>>::right;
        };

    template<typename Tuple, typename Comparison, typename Enabled = void> struct SortImpl;
    template<typename Comparison> struct SortImpl<std::tuple<>, Comparison> { using type = std::tuple<>; };
    template<typename Head, typename Comparison> struct SortImpl<std::tuple<Head>, Comparison> { using type = std::tuple<Head>; };
    template<typename Head, typename... Rest, typename Comparison>
        struct SortImpl<std::tuple<Head, Rest...>, Comparison> {
            using partition = PartitionImpl<std::tuple<Rest...>, Head, Comparison>;
            using sorted_left = typename SortImpl<typename partition::left, Comparison>::type;
            using sorted_right = typename SortImpl<typename partition::right, Comparison>::type;
            using type = typename ConcatImpl<sorted_left, std::tuple<Head>, sorted_right>::type;
        };

} // namespace internal

template<typename Target, class Tuple, std::size_t From = 0> using has_type = typename internal::has_type<Target, Tuple, From>;
template<typename Tuple, std::size_t... Idx> using select = std::tuple<typename std::tuple_element<Idx, Tuple>::type...>;
template<typename Tuple> using head = typename std::tuple_element<0, Tuple>::type;
template<typename Tuple> using tail = typename internal::TailImpl<Tuple>::type;
template<typename... Tuples> using concat = typename internal::ConcatImpl<std::tuple<>, Tuples...>::type;
template<typename Tuple, template<typename> class Operation> using transform = typename internal::TransformImpl<Tuple, Operation>::type;
template<template<typename> class Predicate, typename Tuple> using filter = typename internal::FilterImpl<Predicate, Tuple>::type;
template<typename Tuple> using unique = typename internal::UniqueImpl<Tuple>::type;
template<typename T, typename Tuple> using without = typename internal::WithoutImpl<T, Tuple>::type;
template<typename A, typename B> using interleave = typename internal::InterleaveImpl<A, B>::type;
template<typename A, typename B, typename Comparison> using merge = typename internal::MergeImpl<A, B, unique<Comparison>>::type;
template<typename Tuple, typename Pivot, typename Comparison> using partition = typename internal::PartitionImpl<Tuple, Pivot, Comparison>::type;
template<typename Tuple, typename Comparison> using sort = typename internal::SortImpl<Tuple, Comparison>::type;
template<typename T, typename... Types> constexpr auto index_of = internal::index_of_type<std::decay<T>, std::tuple<std::decay<Types>...>>::value;

} // namespace mtl
<|endoftext|>


<commit_before>#include "types.h"
#include "bison.h"
#include "fake.h"
#include "variant.h"
#include "paramstack.h"
#ifdef WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif

void fklog(const char * header, const char * file, const char * func, int pos, const char *fmt, ...)
{
	FILE *pLog = NULL;
	time_t clock1;
	struct tm * tptr;
	va_list ap;

	pLog = fopen("fakescript.log", "a+");
	if (pLog == NULL)
	{
		return;
	}

	clock1 = time(0);
	tptr = localtime(&clock1);

	fprintf(pLog, "===========================[%d.%d.%d, %d.%d.%d]%s:%d,%s:===========================\n%s",
		tptr->tm_year+1990,tptr->tm_mon+1,
		tptr->tm_mday,tptr->tm_hour,tptr->tm_min,
		tptr->tm_sec,file,pos,func,header);

	va_start(ap, fmt);
	vfprintf(pLog, fmt, ap);
	fprintf(pLog, "\n\n");
	va_end(ap);

	fclose(pLog);
}

String fkget_token_name(int token)
{
#define TOKEN_SWITCH(x) case x: return #x;
    switch (token)
    {
        TOKEN_SWITCH(VAR_BEGIN)
        TOKEN_SWITCH(RETURN)
        TOKEN_SWITCH(BREAK)
        TOKEN_SWITCH(FUNC)
        TOKEN_SWITCH(WHILE)
        TOKEN_SWITCH(TRUE)
        TOKEN_SWITCH(FALSE)
        TOKEN_SWITCH(IF)
        TOKEN_SWITCH(THEN)
        TOKEN_SWITCH(ELSE)
        TOKEN_SWITCH(END)
        TOKEN_SWITCH(STRING_DEFINITION)
        TOKEN_SWITCH(IDENTIFIER)
        TOKEN_SWITCH(NUMBER)
        TOKEN_SWITCH(SINGLE_LINE_COMMENT)
        TOKEN_SWITCH(DIVIDE_MOD)
        TOKEN_SWITCH(ARG_SPLITTER)
        TOKEN_SWITCH(PLUS)
        TOKEN_SWITCH(MINUS)
        TOKEN_SWITCH(DIVIDE)
        TOKEN_SWITCH(MULTIPLY)
        TOKEN_SWITCH(ASSIGN)
        TOKEN_SWITCH(MORE)
        TOKEN_SWITCH(LESS)
        TOKEN_SWITCH(MORE_OR_EQUAL)
        TOKEN_SWITCH(LESS_OR_EQUAL)
        TOKEN_SWITCH(EQUAL)
        TOKEN_SWITCH(NOT_EQUAL)
        TOKEN_SWITCH(OPEN_BRACKET)
        TOKEN_SWITCH(CLOSE_BRACKET)
        TOKEN_SWITCH(FKFLOAT)
        TOKEN_SWITCH(PLUS_ASSIGN)
        TOKEN_SWITCH(MINUS_ASSIGN)
        TOKEN_SWITCH(DIVIDE_ASSIGN)
		TOKEN_SWITCH(MULTIPLY_ASSIGN)
		TOKEN_SWITCH(DIVIDE_MOD_ASSIGN)
		TOKEN_SWITCH(FOR)
    }
#undef TOKEN_SWITCH
	return fkitoa(token);
}

void * safe_fkmalloc(fake * fk, size_t size)
{
    if (fk && size)
    {
        return fk->cfg.fkm(size);
    }
    return 0;
}

void safe_fkfree(fake * fk, const void * p)
{
    if (fk && p)
    {
        fk->cfg.fkf((void *)p);
    }
}

void seterror(fake * fk, efkerror err, const char *fmt, ...)
{
    fk->errorno = err;
	va_list ap;
	va_start(ap, fmt);
    vsnprintf(fk->errorstr, sizeof(fk->errorstr) - 1, fmt, ap);
	va_end(ap);
	fk->errorstr[sizeof(fk->errorstr) - 1] = 0;
}

String vartostring(const variant * v)
{
    String s;
    V_TOSTRING(v, s);
    return s;
}

paramstack * getps(fake * fk)
{
    return &fk->ps;
}

char * stringdump(fake * fk, const char * src, size_t sz)
{
	char * s = (char*)safe_fkmalloc(fk, sz + 1);
	memcpy(s, src, sz);
	s[sz] = 0;
	return s;
}

uint32_t fkgetmstick()
{
#ifdef WIN32
	return ::GetTickCount();
#else
	struct timeval tv;
	if(::gettimeofday(&tv, 0) == 0)
	{
		uint64_t t = tv.tv_sec * 1000;
		t += tv.tv_usec / 1000;
		return t & 0xffffffff;
	}
	return 0;
#endif
}
<commit_msg>asdgasdg<commit_after>#include "types.h"
#include "bison.h"
#include "fake.h"
#include "variant.h"
#include "paramstack.h"
#ifdef WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif

void fklog(const char * header, const char * file, const char * func, int pos, const char *fmt, ...)
{
	FILE *pLog = NULL;
	time_t clock1;
	struct tm * tptr;
	va_list ap;

	pLog = fopen("fakescript.log", "a+");
	if (pLog == NULL)
	{
		return;
	}

	clock1 = time(0);
	tptr = localtime(&clock1);

	fprintf(pLog, "===========================[%d.%d.%d, %d.%d.%d]%s:%d,%s:===========================\n%s",
		tptr->tm_year+1990,tptr->tm_mon+1,
		tptr->tm_mday,tptr->tm_hour,tptr->tm_min,
		tptr->tm_sec,file,pos,func,header);

	va_start(ap, fmt);
	vfprintf(pLog, fmt, ap);
	fprintf(pLog, "\n\n");
	va_end(ap);

	fclose(pLog);
}

String fkget_token_name(int token)
{
#define TOKEN_SWITCH(x) case x: return #x;
    switch (token)
    {
        TOKEN_SWITCH(VAR_BEGIN)
        TOKEN_SWITCH(RETURN)
        TOKEN_SWITCH(BREAK)
        TOKEN_SWITCH(FUNC)
        TOKEN_SWITCH(WHILE)
        TOKEN_SWITCH(TRUE)
        TOKEN_SWITCH(FALSE)
        TOKEN_SWITCH(IF)
        TOKEN_SWITCH(THEN)
        TOKEN_SWITCH(ELSE)
        TOKEN_SWITCH(END)
        TOKEN_SWITCH(STRING_DEFINITION)
        TOKEN_SWITCH(IDENTIFIER)
        TOKEN_SWITCH(NUMBER)
        TOKEN_SWITCH(SINGLE_LINE_COMMENT)
        TOKEN_SWITCH(DIVIDE_MOD)
        TOKEN_SWITCH(ARG_SPLITTER)
        TOKEN_SWITCH(PLUS)
        TOKEN_SWITCH(MINUS)
        TOKEN_SWITCH(DIVIDE)
        TOKEN_SWITCH(MULTIPLY)
        TOKEN_SWITCH(ASSIGN)
        TOKEN_SWITCH(MORE)
        TOKEN_SWITCH(LESS)
        TOKEN_SWITCH(MORE_OR_EQUAL)
        TOKEN_SWITCH(LESS_OR_EQUAL)
        TOKEN_SWITCH(EQUAL)
        TOKEN_SWITCH(NOT_EQUAL)
        TOKEN_SWITCH(OPEN_BRACKET)
        TOKEN_SWITCH(CLOSE_BRACKET)
        TOKEN_SWITCH(FKFLOAT)
        TOKEN_SWITCH(PLUS_ASSIGN)
        TOKEN_SWITCH(MINUS_ASSIGN)
        TOKEN_SWITCH(DIVIDE_ASSIGN)
		TOKEN_SWITCH(MULTIPLY_ASSIGN)
		TOKEN_SWITCH(DIVIDE_MOD_ASSIGN)
		TOKEN_SWITCH(FOR)
		TOKEN_SWITCH(INC)
    }
#undef TOKEN_SWITCH
	return fkitoa(token);
}

void * safe_fkmalloc(fake * fk, size_t size)
{
    if (fk && size)
    {
        return fk->cfg.fkm(size);
    }
    return 0;
}

void safe_fkfree(fake * fk, const void * p)
{
    if (fk && p)
    {
        fk->cfg.fkf((void *)p);
    }
}

void seterror(fake * fk, efkerror err, const char *fmt, ...)
{
    fk->errorno = err;
	va_list ap;
	va_start(ap, fmt);
    vsnprintf(fk->errorstr, sizeof(fk->errorstr) - 1, fmt, ap);
	va_end(ap);
	fk->errorstr[sizeof(fk->errorstr) - 1] = 0;
}

String vartostring(const variant * v)
{
    String s;
    V_TOSTRING(v, s);
    return s;
}

paramstack * getps(fake * fk)
{
    return &fk->ps;
}

char * stringdump(fake * fk, const char * src, size_t sz)
{
	char * s = (char*)safe_fkmalloc(fk, sz + 1);
	memcpy(s, src, sz);
	s[sz] = 0;
	return s;
}

uint32_t fkgetmstick()
{
#ifdef WIN32
	return ::GetTickCount();
#else
	struct timeval tv;
	if(::gettimeofday(&tv, 0) == 0)
	{
		uint64_t t = tv.tv_sec * 1000;
		t += tv.tv_usec / 1000;
		return t & 0xffffffff;
	}
	return 0;
#endif
}
<|endoftext|>


<commit_before>#include <iostream>
#include <stdlib.h>

#include "media/types.h"

using namespace std;

const int arraySize = 50;

void addMedia(Medium* medium, Medium* media[], int arraySize) {
  int i;
  for (i = 0; i < arraySize; i++) {
    if (media[i] == NULL) {
      media[i] = medium;
      break;
    }
  }
  if (i == arraySize) {
    cerr << "Error: Exeeded array size of " << arraySize << " elements!" << endl;
  }
}

int main()
{
  char command = 'q';
  Medium* media[arraySize];
  int signature = 0;
  // Initialize array with NULL values
  int i;
  for (i = 0; i < arraySize; i++) {
    media[i] = NULL;
  }

  while (true) {
    cout << "What do you want to do?" << endl
            << "m: new medium" << endl
            << "b: new book" << endl
            << "v: new video" << endl
            << "l: list media" << endl
            << "e SIGNATURE: borrow media" << endl
            << "r SIGNATURE: return media" << endl
            << "q: quit" << endl
            << endl
            << "Command: ";
    cin >> command;
    cout << endl;

    switch (command) {
      case 'm':
        addMedia(new Medium(), media, arraySize);
        break;
      case 'b':
        addMedia(new Book(), media, arraySize);
        break;
      case 'v':
        addMedia(new Video(), media, arraySize);
        break;
      case 'l':
        cout << "Media Library" << endl;
        int i;
        for (i = 0; i < arraySize; i++) {
          if (media[i] == NULL) {
            break;
          }
          media[i]->print();
        }
        break;
      case 'e':
        cin >> signature;
        for (i = 0; (i < arraySize) && (media[i] != NULL); i++) {
          if (media[i]->getSignature() == signature) {
            media[i]->lendOut();
          }
        }
        break;
      case 'r':
        cin >> signature;
        for (i = 0; (i < arraySize) && (media[i] != NULL); i++) {
          if (media[i]->getSignature() == signature) {
            media[i]->handIn();
          }
        }
        break;
      case 'q':
        exit(EXIT_SUCCESS);
    }
    cout << endl;
  }

  // Garbage collection
  for (i = 0; (i < arraySize) && (media[i] != NULL); i++) {
    delete media[i];
  }
}
<commit_msg>Shortened to long line.<commit_after>#include <iostream>
#include <stdlib.h>

#include "media/types.h"

using namespace std;

const int arraySize = 50;

void addMedia(Medium* medium, Medium* media[], int arraySize) {
  int i;
  for (i = 0; i < arraySize; i++) {
    if (media[i] == NULL) {
      media[i] = medium;
      break;
    }
  }
  if (i == arraySize) {
    cerr << "Error: Exeeded array size of " << arraySize
         << " elements!" << endl;
  }
}

int main()
{
  char command = 'q';
  Medium* media[arraySize];
  int signature = 0;
  // Initialize array with NULL values
  int i;
  for (i = 0; i < arraySize; i++) {
    media[i] = NULL;
  }

  while (true) {
    cout << "What do you want to do?" << endl
            << "m: new medium" << endl
            << "b: new book" << endl
            << "v: new video" << endl
            << "l: list media" << endl
            << "e SIGNATURE: borrow media" << endl
            << "r SIGNATURE: return media" << endl
            << "q: quit" << endl
            << endl
            << "Command: ";
    cin >> command;
    cout << endl;

    switch (command) {
      case 'm':
        addMedia(new Medium(), media, arraySize);
        break;
      case 'b':
        addMedia(new Book(), media, arraySize);
        break;
      case 'v':
        addMedia(new Video(), media, arraySize);
        break;
      case 'l':
        cout << "Media Library" << endl;
        int i;
        for (i = 0; i < arraySize; i++) {
          if (media[i] == NULL) {
            break;
          }
          media[i]->print();
        }
        break;
      case 'e':
        cin >> signature;
        for (i = 0; (i < arraySize) && (media[i] != NULL); i++) {
          if (media[i]->getSignature() == signature) {
            media[i]->lendOut();
          }
        }
        break;
      case 'r':
        cin >> signature;
        for (i = 0; (i < arraySize) && (media[i] != NULL); i++) {
          if (media[i]->getSignature() == signature) {
            media[i]->handIn();
          }
        }
        break;
      case 'q':
        exit(EXIT_SUCCESS);
    }
    cout << endl;
  }

  // Garbage collection
  for (i = 0; (i < arraySize) && (media[i] != NULL); i++) {
    delete media[i];
  }
}
<|endoftext|>


<commit_before>/**
 Copyright 2016 Udey Rishi

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

#include <lang/Command.hpp>
#include <regex>
#include <core/BooleanFunctionParser.hpp>
#include <lang/Exceptions.hpp>
#include <core/Utils.hpp>
#include <algorithm>
#include <sstream>
#include <utility>

using namespace std;

namespace Logic {
static const regex CREATE_ARGS_REGEX("\\s*(" + VARIABLE_REGEX + ")\\s*[=]\\s*(.+)\\s*");
static const string ELSE_ALLOWED = "else_allowed";
static const string RUN_ELSE = "run_else";

BooleanFunction parse(const string &expression, const Runtime &runtime) {
    return BooleanFunctionParser().parse(expression, [&](const string &functionName) -> const BooleanFunction& {
        return runtime.get(functionName);
    });
}

bool Command::execute(const string &args, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    UNUSED(args);
    UNUSED(out);
    UNUSED(interpreter);
    runtime.clearFlags();
    return true;
}

bool QuitCommand::execute(const string &args, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    Command::execute(args, runtime, out, interpreter);
    UNUSED(out);
    UNUSED(runtime);
    UNUSED(interpreter);

    if (args.length() != 0) {
        throw BadCommandArgumentsException("Unknown args to command 'quit': " + args);
    }
    return false;
}

bool CreateBooleanFunctionCommand::execute(const string &args, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    Command::execute(args, runtime, out, interpreter);
    UNUSED(out);
    UNUSED(interpreter);

    smatch sm;
    if (regex_match(args, sm, CREATE_ARGS_REGEX, regex_constants::match_continuous)) {
        string variableName = sm[1];
        string expression = sm[2];
        runtime.save(variableName, parse(expression, runtime));
        return true;
    }

    throw BadCommandArgumentsException("Unknown args to command 'let': " + args);
}

bool PrintBooleanFunctionCommand::execute(const string &expression, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    Command::execute(expression, runtime, out, interpreter);
    UNUSED(interpreter);

    out << parse(expression, runtime) << endl;
    return true;
}

bool DeleteBooleanFunctionCommand::execute(const string &functionName, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    Command::execute(functionName, runtime, out, interpreter);
    UNUSED(interpreter);
    UNUSED(out);

    runtime.erase(functionName);
    return true;
}

bool PrintMaxtermsCommand::execute(const string &expression, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    Command::execute(expression, runtime, out, interpreter);
    UNUSED(interpreter);

    out << join(parse(expression, runtime).getTruthTable().getMaxterms(), ", ") << endl;
    return true;
}

bool PrintMintermsCommand::execute(const string &expression, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    Command::execute(expression, runtime, out, interpreter);
    UNUSED(interpreter);

    out << join(parse(expression, runtime).getTruthTable().getMinterms(), ", ") << endl;
    return true;
}

bool PrintVariablesCommand::execute(const string &expression, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    Command::execute(expression, runtime, out, interpreter);
    UNUSED(interpreter);

    vector<string> variables = parse(expression, runtime).getTruthTable().getVariables();
    // This is how the variables are shown in the truth table -- little endian
    reverse(variables.begin(), variables.end());
    out << join(variables, ", ") << endl;
    return true;
}

static const string BLOCK_REGEX = "[\\s]*[\\{]{1}[\\s]*(.*)[\\s]*[\\}]{1}[\\s]*";

static pair<string, string> getConditionalCommandArgs(const string &args, const string &commandName) {
    static const regex conditionRegex("[\\s]*(.+?)[\\s]*" + BLOCK_REGEX);
    smatch sm;

    if (!regex_search(args, sm, conditionRegex, regex_constants::match_continuous)) {
        throw BadCommandArgumentsException("Unknown args to command '" + commandName + "': " + args);
    }

    return make_pair(sm[1], sm[2]);
}

bool IfCommand::execute(const string &args, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    Command::execute(args, runtime, out, interpreter);
    UNUSED(out);

    const auto parsedArgs = getConditionalCommandArgs(args, "if");
    BooleanFunction conditionFunction = parse(parsedArgs.first, runtime);
    if (!conditionFunction.isConstant()) {
        throw BadCommandArgumentsException("The condition to the 'if' command needs to evaluate to a constant value Boolean function.");
    }

    bool _continue = true;
    if (conditionFunction.getConstantValue()) {
        stringstream ss;
        ss << parsedArgs.second;
        _continue = interpreter(ss);
    } else {
        runtime.flag(RUN_ELSE);
    }

    runtime.flag(ELSE_ALLOWED);
    return _continue;
}

bool WhileCommand::execute(const string &args, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    Command::execute(args, runtime, out, interpreter);
    UNUSED(out);

    const auto parsedArgs = getConditionalCommandArgs(args, "while");

    while (true) {
        BooleanFunction conditionFunction = parse(parsedArgs.first, runtime);
        if (!conditionFunction.isConstant()) {
            throw BadCommandArgumentsException("The condition to the 'while' command needs to evaluate to a constant value Boolean function.");
        }

        if (!conditionFunction.getConstantValue()) {
            break;
        }

        stringstream ss;
        ss << parsedArgs.second;
        if (!interpreter(ss)) {
            return false;
        }
    }

    return true;
}

bool ElseCommand::execute(const string &args, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    if (!runtime.getFlag(ELSE_ALLOWED)) {
        throw CommandNotAllowedException("'else' command cannot be used without a preceding 'if' command.");
    }

    bool runElse = runtime.getFlag(RUN_ELSE);
    Command::execute(args, runtime, out, interpreter);
    UNUSED(out);

    static const regex conditionRegex("[\\s]*(.*?)[\\s]*" + BLOCK_REGEX);
    smatch sm;

    if (!regex_search(args, sm, conditionRegex, regex_constants::match_continuous)) {
        throw BadCommandArgumentsException("Unknown args to command 'else': " + args);
    }

    const string condition = sm[1];
    const string code = sm[2];

    if (!runElse) {
        // A previous if condition was true, so don't execute this else
        if (!isWhitespace(condition)) {
            // If this was an else-if, allow more else conditions. Just don't run them (RUN_ELSE is not set)
            runtime.flag(ELSE_ALLOWED);
        }
        return true;
    }

    // Hack: This is just a one off, but if there are more like these, consider coming up with a more elegant solution
    stringstream ss;
    if (isWhitespace(condition)) {
        ss << code;
    } else if (condition.compare(0, strlen("if"), "if") == 0) {
        // repack
        ss << condition << " { " << code << " }";
    } else {
        throw BadCommandArgumentsException("Expected a conditional 'if' or unconditional block after the 'else' command.");
    }

    return interpreter(ss);
}
}
<commit_msg>Bug fix: Nested failing if's were causing outer else's to be called<commit_after>/**
 Copyright 2016 Udey Rishi

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

#include <lang/Command.hpp>
#include <regex>
#include <core/BooleanFunctionParser.hpp>
#include <lang/Exceptions.hpp>
#include <core/Utils.hpp>
#include <algorithm>
#include <sstream>
#include <utility>

using namespace std;

namespace Logic {
static const regex CREATE_ARGS_REGEX("\\s*(" + VARIABLE_REGEX + ")\\s*[=]\\s*(.+)\\s*");
static const string ELSE_ALLOWED = "else_allowed";
static const string RUN_ELSE = "run_else";

BooleanFunction parse(const string &expression, const Runtime &runtime) {
    return BooleanFunctionParser().parse(expression, [&](const string &functionName) -> const BooleanFunction& {
        return runtime.get(functionName);
    });
}

bool Command::execute(const string &args, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    UNUSED(args);
    UNUSED(out);
    UNUSED(interpreter);
    runtime.clearFlags();
    return true;
}

bool QuitCommand::execute(const string &args, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    Command::execute(args, runtime, out, interpreter);
    UNUSED(out);
    UNUSED(runtime);
    UNUSED(interpreter);

    if (args.length() != 0) {
        throw BadCommandArgumentsException("Unknown args to command 'quit': " + args);
    }
    return false;
}

bool CreateBooleanFunctionCommand::execute(const string &args, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    Command::execute(args, runtime, out, interpreter);
    UNUSED(out);
    UNUSED(interpreter);

    smatch sm;
    if (regex_match(args, sm, CREATE_ARGS_REGEX, regex_constants::match_continuous)) {
        string variableName = sm[1];
        string expression = sm[2];
        runtime.save(variableName, parse(expression, runtime));
        return true;
    }

    throw BadCommandArgumentsException("Unknown args to command 'let': " + args);
}

bool PrintBooleanFunctionCommand::execute(const string &expression, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    Command::execute(expression, runtime, out, interpreter);
    UNUSED(interpreter);

    out << parse(expression, runtime) << endl;
    return true;
}

bool DeleteBooleanFunctionCommand::execute(const string &functionName, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    Command::execute(functionName, runtime, out, interpreter);
    UNUSED(interpreter);
    UNUSED(out);

    runtime.erase(functionName);
    return true;
}

bool PrintMaxtermsCommand::execute(const string &expression, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    Command::execute(expression, runtime, out, interpreter);
    UNUSED(interpreter);

    out << join(parse(expression, runtime).getTruthTable().getMaxterms(), ", ") << endl;
    return true;
}

bool PrintMintermsCommand::execute(const string &expression, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    Command::execute(expression, runtime, out, interpreter);
    UNUSED(interpreter);

    out << join(parse(expression, runtime).getTruthTable().getMinterms(), ", ") << endl;
    return true;
}

bool PrintVariablesCommand::execute(const string &expression, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    Command::execute(expression, runtime, out, interpreter);
    UNUSED(interpreter);

    vector<string> variables = parse(expression, runtime).getTruthTable().getVariables();
    // This is how the variables are shown in the truth table -- little endian
    reverse(variables.begin(), variables.end());
    out << join(variables, ", ") << endl;
    return true;
}

static const string BLOCK_REGEX = "[\\s]*[\\{]{1}[\\s]*(.*)[\\s]*[\\}]{1}[\\s]*";

static pair<string, string> getConditionalCommandArgs(const string &args, const string &commandName) {
    static const regex conditionRegex("[\\s]*(.+?)[\\s]*" + BLOCK_REGEX);
    smatch sm;

    if (!regex_search(args, sm, conditionRegex, regex_constants::match_continuous)) {
        throw BadCommandArgumentsException("Unknown args to command '" + commandName + "': " + args);
    }

    return make_pair(sm[1], sm[2]);
}

bool IfCommand::execute(const string &args, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    Command::execute(args, runtime, out, interpreter);
    UNUSED(out);

    const auto parsedArgs = getConditionalCommandArgs(args, "if");
    BooleanFunction conditionFunction = parse(parsedArgs.first, runtime);
    if (!conditionFunction.isConstant()) {
        throw BadCommandArgumentsException("The condition to the 'if' command needs to evaluate to a constant value Boolean function.");
    }

    bool _continue = true;
    if (conditionFunction.getConstantValue()) {
        stringstream ss;
        ss << parsedArgs.second;
        _continue = interpreter(ss);
        // A nested if condition could've failed and set a flag for else. Now it's not needed
        runtime.getFlag(RUN_ELSE);
    } else {
        runtime.flag(RUN_ELSE);
    }

    runtime.flag(ELSE_ALLOWED);
    return _continue;
}

bool WhileCommand::execute(const string &args, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    Command::execute(args, runtime, out, interpreter);
    UNUSED(out);

    const auto parsedArgs = getConditionalCommandArgs(args, "while");

    while (true) {
        BooleanFunction conditionFunction = parse(parsedArgs.first, runtime);
        if (!conditionFunction.isConstant()) {
            throw BadCommandArgumentsException("The condition to the 'while' command needs to evaluate to a constant value Boolean function.");
        }

        if (!conditionFunction.getConstantValue()) {
            break;
        }

        stringstream ss;
        ss << parsedArgs.second;
        if (!interpreter(ss)) {
            return false;
        }
    }

    return true;
}

bool ElseCommand::execute(const string &args, Runtime &runtime, ostream &out, function<bool (istream &)> interpreter) {
    if (!runtime.getFlag(ELSE_ALLOWED)) {
        throw CommandNotAllowedException("'else' command cannot be used without a preceding 'if' command.");
    }

    bool runElse = runtime.getFlag(RUN_ELSE);
    Command::execute(args, runtime, out, interpreter);
    UNUSED(out);

    static const regex conditionRegex("[\\s]*(.*?)[\\s]*" + BLOCK_REGEX);
    smatch sm;

    if (!regex_search(args, sm, conditionRegex, regex_constants::match_continuous)) {
        throw BadCommandArgumentsException("Unknown args to command 'else': " + args);
    }

    const string condition = sm[1];
    const string code = sm[2];

    if (!runElse) {
        // A previous if condition was true, so don't execute this else
        if (!isWhitespace(condition)) {
            // If this was an else-if, allow more else conditions. Just don't run them (RUN_ELSE is not set)
            runtime.flag(ELSE_ALLOWED);
        }
        return true;
    }

    // Hack: This is just a one off, but if there are more like these, consider coming up with a more elegant solution
    stringstream ss;
    if (isWhitespace(condition)) {
        ss << code;
    } else if (condition.compare(0, strlen("if"), "if") == 0) {
        // repack
        ss << condition << " { " << code << " }";
    } else {
        throw BadCommandArgumentsException("Expected a conditional 'if' or unconditional block after the 'else' command.");
    }

    return interpreter(ss);
}
}
<|endoftext|>


<commit_before>#include "vexporter.h"

#include <QtWidgets>
#include <QFileInfo>
#include <QDir>
#include <QWebChannel>
#include <QDebug>
#include <QVBoxLayout>
#include <QShowEvent>

#ifndef QT_NO_PRINTER
#include <QPrinter>
#include <QPageSetupDialog>
#endif

#include "vconfigmanager.h"
#include "utils/vutils.h"
#include "vfile.h"
#include "vwebview.h"
#include "vpreviewpage.h"
#include "vconstants.h"
#include "vnote.h"
#include "vmarkdownconverter.h"
#include "vdocument.h"

extern VConfigManager vconfig;

QString VExporter::s_defaultPathDir = QDir::homePath();

VExporter::VExporter(MarkdownConverterType p_mdType, QWidget *p_parent)
    : QDialog(p_parent), m_webViewer(NULL), m_mdType(p_mdType),
      m_file(NULL), m_type(ExportType::PDF), m_source(ExportSource::Invalid),
      m_noteState(NoteState::NotReady), m_state(ExportState::Idle),
      m_pageLayout(QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0.0, 0.0, 0.0, 0.0))),
      m_exported(false)
{
    initMarkdownTemplate();

    setupUI();
}

void VExporter::initMarkdownTemplate()
{
    m_htmlTemplate = VUtils::generateHtmlTemplate(m_mdType, true);
}

void VExporter::setupUI()
{
    m_infoLabel = new QLabel();
    m_infoLabel->setWordWrap(true);

    // Target file path.
    QLabel *pathLabel = new QLabel(tr("Target &path:"));
    m_pathEdit = new QLineEdit();
    pathLabel->setBuddy(m_pathEdit);
    m_browseBtn = new QPushButton(tr("&Browse"));
    connect(m_browseBtn, &QPushButton::clicked,
            this, &VExporter::handleBrowseBtnClicked);

    // Page layout.
    QLabel *layoutLabel = new QLabel(tr("Page layout:"));
    m_layoutLabel = new QLabel();
    m_layoutBtn = new QPushButton(tr("&Settings"));

#ifndef QT_NO_PRINTER
    connect(m_layoutBtn, &QPushButton::clicked,
            this, &VExporter::handleLayoutBtnClicked);
#else
    m_layoutBtn->hide();
#endif

    // Progress.
    m_proLabel = new QLabel(this);
    m_proBar = new QProgressBar(this);

    // Ok is the default button.
    m_btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
    m_openBtn = m_btnBox->addButton(tr("Open File Location"), QDialogButtonBox::ActionRole);
    connect(m_btnBox, &QDialogButtonBox::accepted, this, &VExporter::startExport);
    connect(m_btnBox, &QDialogButtonBox::rejected, this, &VExporter::cancelExport);
    connect(m_openBtn, &QPushButton::clicked, this, &VExporter::openTargetPath);

    QPushButton *okBtn = m_btnBox->button(QDialogButtonBox::Ok);
    m_pathEdit->setMinimumWidth(okBtn->sizeHint().width() * 3);

    QGridLayout *mainLayout = new QGridLayout();
    mainLayout->addWidget(m_infoLabel, 0, 0, 1, 3);
    mainLayout->addWidget(pathLabel, 1, 0);
    mainLayout->addWidget(m_pathEdit, 1, 1);
    mainLayout->addWidget(m_browseBtn, 1, 2);
    mainLayout->addWidget(layoutLabel, 2, 0);
    mainLayout->addWidget(m_layoutLabel, 2, 1);
    mainLayout->addWidget(m_layoutBtn, 2, 2);
    mainLayout->addWidget(m_proLabel, 3, 1, 1, 2);
    mainLayout->addWidget(m_proBar, 4, 1, 1, 2);
    mainLayout->addWidget(m_btnBox, 5, 1, 1, 2);

    m_proLabel->hide();
    m_proBar->hide();

    setLayout(mainLayout);
    mainLayout->setSizeConstraint(QLayout::SetFixedSize);
    setWindowTitle(tr("Export Note"));

    m_openBtn->hide();

    updatePageLayoutLabel();
}

static QString exportTypeStr(ExportType p_type)
{
    if (p_type == ExportType::PDF) {
        return "PDF";
    } else {
        return "HTML";
    }
}

void VExporter::handleBrowseBtnClicked()
{
    QFileInfo fi(getFilePath());
    QString fileType = m_type == ExportType::PDF ?
                       tr("Portable Document Format (*.pdf)") :
                       tr("WebPage, Complete (*.html)");
    QString path = QFileDialog::getSaveFileName(this, tr("Export As"),
                                                fi.absolutePath(),
                                                fileType);
    if (path.isEmpty()) {
        return;
    }

    setFilePath(path);
    s_defaultPathDir = VUtils::basePathFromPath(path);

    m_openBtn->hide();
}

void VExporter::handleLayoutBtnClicked()
{
#ifndef QT_NO_PRINTER
    QPrinter printer;
    printer.setPageLayout(m_pageLayout);

    QPageSetupDialog dlg(&printer, this);
    if (dlg.exec() != QDialog::Accepted) {
        return;
    }

    m_pageLayout.setPageSize(printer.pageLayout().pageSize());
    m_pageLayout.setOrientation(printer.pageLayout().orientation());

    updatePageLayoutLabel();
#endif
}

void VExporter::updatePageLayoutLabel()
{
    m_layoutLabel->setText(QString("%1, %2").arg(m_pageLayout.pageSize().name())
                                            .arg(m_pageLayout.orientation() == QPageLayout::Portrait ?
                                                 tr("Portrait") : tr("Landscape")));
}

QString VExporter::getFilePath() const
{
    return QDir::cleanPath(m_pathEdit->text());
}

void VExporter::setFilePath(const QString &p_path)
{
    m_pathEdit->setText(QDir::toNativeSeparators(p_path));
}

void VExporter::exportNote(VFile *p_file, ExportType p_type)
{
    m_file = p_file;
    m_type = p_type;
    m_source = ExportSource::Note;

    if (!m_file || m_file->getDocType() != DocType::Markdown) {
        // Do not support non-Markdown note now.
        m_btnBox->button(QDialogButtonBox::Ok)->setEnabled(false);
        return;
    }

    m_infoLabel->setText(tr("Export note %2 as %3.")
                            .arg(vconfig.c_dataTextStyle)
                            .arg(m_file->getName())
                            .arg(exportTypeStr(p_type)));

    setWindowTitle(tr("Export As %1").arg(exportTypeStr(p_type)));

    setFilePath(QDir(s_defaultPathDir).filePath(QFileInfo(p_file->retrivePath()).baseName() +
                                                "." + exportTypeStr(p_type).toLower()));
}

void VExporter::initWebViewer(VFile *p_file)
{
    V_ASSERT(!m_webViewer);

    m_webViewer = new VWebView(p_file, this);
    m_webViewer->hide();
    VPreviewPage *page = new VPreviewPage(m_webViewer);
    m_webViewer->setPage(page);

    connect(page, &VPreviewPage::loadFinished,
            this, &VExporter::handleLoadFinished);

    VDocument *document = new VDocument(p_file, m_webViewer);
    connect(document, &VDocument::logicsFinished,
            this, &VExporter::handleLogicsFinished);

    QWebChannel *channel = new QWebChannel(m_webViewer);
    channel->registerObject(QStringLiteral("content"), document);
    page->setWebChannel(channel);

    // Need to generate HTML using Hoedown.
    if (m_mdType == MarkdownConverterType::Hoedown) {
        VMarkdownConverter mdConverter;
        QString toc;
        QString html = mdConverter.generateHtml(p_file->getContent(),
                                                vconfig.getMarkdownExtensions(),
                                                toc);
        document->setHtml(html);
    }

    m_webViewer->setHtml(m_htmlTemplate, p_file->getBaseUrl());
}

void VExporter::clearWebViewer()
{
    if (m_webViewer) {
        delete m_webViewer;
        m_webViewer = NULL;
    }
}

void VExporter::handleLogicsFinished()
{
    Q_ASSERT(!(m_noteState & NoteState::WebLogicsReady));
    m_noteState = NoteState(m_noteState | NoteState::WebLogicsReady);
}

void VExporter::handleLoadFinished(bool p_ok)
{
    Q_ASSERT(!(m_noteState & NoteState::WebLoadFinished));
    m_noteState = NoteState(m_noteState | NoteState::WebLoadFinished);

    if (!p_ok) {
        m_noteState = NoteState(m_noteState | NoteState::Failed);
    }
}

void VExporter::clearNoteState()
{
    m_noteState = NoteState::NotReady;
}

bool VExporter::isNoteStateReady() const
{
    return m_noteState == NoteState::Ready;
}

bool VExporter::isNoteStateFailed() const
{
    return m_noteState & NoteState::Failed;
}

void VExporter::startExport()
{
    QPushButton *cancelBtn = m_btnBox->button(QDialogButtonBox::Cancel);

    if (m_exported) {
        cancelBtn->show();
        m_exported = false;
        accept();
    }

    int exportedNum = 0;
    enableUserInput(false);
    V_ASSERT(m_state == ExportState::Idle);
    m_state = ExportState::Busy;

    m_openBtn->hide();

    if (m_source == ExportSource::Note) {
        V_ASSERT(m_file);
        bool isOpened = m_file->isOpened();
        if (!isOpened && !m_file->open()) {
            goto exit;
        }

        clearNoteState();
        initWebViewer(m_file);

        // Update progress info.
        m_proLabel->setText(tr("Exporting %1").arg(m_file->getName()));
        m_proBar->setEnabled(true);
        m_proBar->setMinimum(0);
        m_proBar->setMaximum(100);
        m_proBar->reset();
        m_proLabel->show();
        m_proBar->show();

        while (!isNoteStateReady()) {
            VUtils::sleepWait(100);
            if (m_proBar->value() < 70) {
                m_proBar->setValue(m_proBar->value() + 1);
            }

            if (m_state == ExportState::Cancelled) {
                goto exit;
            }

            if (isNoteStateFailed()) {
                m_state = ExportState::Failed;
                goto exit;
            }
        }

        // Wait to ensure Web side is really ready.
        VUtils::sleepWait(200);

        if (m_state == ExportState::Cancelled) {
            goto exit;
        }

        m_proBar->setValue(80);

        bool exportRet = exportToPDF(m_webViewer, getFilePath(), m_pageLayout);

        clearNoteState();

        if (!isOpened) {
            m_file->close();
        }

        if (exportRet) {
            m_proBar->setValue(100);
            m_state = ExportState::Successful;
            exportedNum++;
        } else {
            m_proBar->setEnabled(false);
            m_state = ExportState::Failed;
        }
    }

exit:
    clearWebViewer();

    m_proLabel->setText("");
    m_proLabel->hide();
    enableUserInput(true);

    if (m_state == ExportState::Cancelled) {
        reject();
    }

    if (exportedNum) {
        m_exported = true;
        m_openBtn->show();
        cancelBtn->hide();
    }

    m_state = ExportState::Idle;
}

void VExporter::cancelExport()
{
    if (m_state == ExportState::Idle) {
        reject();
    } else {
        m_state = ExportState::Cancelled;
    }
}

bool VExporter::exportToPDF(VWebView *p_webViewer, const QString &p_filePath,
                            const QPageLayout &p_layout)
{
    int pdfPrinted = 0;
    p_webViewer->page()->printToPdf([&, this](const QByteArray &p_result) {
        if (p_result.isEmpty() || this->m_state == ExportState::Cancelled) {
            pdfPrinted = -1;
            return;
        }

        V_ASSERT(!p_filePath.isEmpty());

        QFile file(p_filePath);

        if (!file.open(QFile::WriteOnly)) {
            pdfPrinted = -1;
            return;
        }

        file.write(p_result.data(), p_result.size());
        file.close();

        pdfPrinted = 1;
    }, p_layout);

    while (pdfPrinted == 0) {
        VUtils::sleepWait(100);

        if (m_state == ExportState::Cancelled) {
            break;
        }
    }

    return pdfPrinted == 1;
}

void VExporter::enableUserInput(bool p_enabled)
{
    m_btnBox->button(QDialogButtonBox::Ok)->setEnabled(p_enabled);
    m_pathEdit->setEnabled(p_enabled);
    m_browseBtn->setEnabled(p_enabled);
    m_layoutBtn->setEnabled(p_enabled);
}

void VExporter::openTargetPath() const
{
    QUrl url = QUrl::fromLocalFile(VUtils::basePathFromPath(getFilePath()));
    QDesktopServices::openUrl(url);
}
<commit_msg>[fix] show the default filename in 'Export As' dialog (#35)<commit_after>#include "vexporter.h"

#include <QtWidgets>
#include <QFileInfo>
#include <QDir>
#include <QWebChannel>
#include <QDebug>
#include <QVBoxLayout>
#include <QShowEvent>

#ifndef QT_NO_PRINTER
#include <QPrinter>
#include <QPageSetupDialog>
#endif

#include "vconfigmanager.h"
#include "utils/vutils.h"
#include "vfile.h"
#include "vwebview.h"
#include "vpreviewpage.h"
#include "vconstants.h"
#include "vnote.h"
#include "vmarkdownconverter.h"
#include "vdocument.h"

extern VConfigManager vconfig;

QString VExporter::s_defaultPathDir = QDir::homePath();

VExporter::VExporter(MarkdownConverterType p_mdType, QWidget *p_parent)
    : QDialog(p_parent), m_webViewer(NULL), m_mdType(p_mdType),
      m_file(NULL), m_type(ExportType::PDF), m_source(ExportSource::Invalid),
      m_noteState(NoteState::NotReady), m_state(ExportState::Idle),
      m_pageLayout(QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0.0, 0.0, 0.0, 0.0))),
      m_exported(false)
{
    initMarkdownTemplate();

    setupUI();
}

void VExporter::initMarkdownTemplate()
{
    m_htmlTemplate = VUtils::generateHtmlTemplate(m_mdType, true);
}

void VExporter::setupUI()
{
    m_infoLabel = new QLabel();
    m_infoLabel->setWordWrap(true);

    // Target file path.
    QLabel *pathLabel = new QLabel(tr("Target &path:"));
    m_pathEdit = new QLineEdit();
    pathLabel->setBuddy(m_pathEdit);
    m_browseBtn = new QPushButton(tr("&Browse"));
    connect(m_browseBtn, &QPushButton::clicked,
            this, &VExporter::handleBrowseBtnClicked);

    // Page layout.
    QLabel *layoutLabel = new QLabel(tr("Page layout:"));
    m_layoutLabel = new QLabel();
    m_layoutBtn = new QPushButton(tr("&Settings"));

#ifndef QT_NO_PRINTER
    connect(m_layoutBtn, &QPushButton::clicked,
            this, &VExporter::handleLayoutBtnClicked);
#else
    m_layoutBtn->hide();
#endif

    // Progress.
    m_proLabel = new QLabel(this);
    m_proBar = new QProgressBar(this);

    // Ok is the default button.
    m_btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
    m_openBtn = m_btnBox->addButton(tr("Open File Location"), QDialogButtonBox::ActionRole);
    connect(m_btnBox, &QDialogButtonBox::accepted, this, &VExporter::startExport);
    connect(m_btnBox, &QDialogButtonBox::rejected, this, &VExporter::cancelExport);
    connect(m_openBtn, &QPushButton::clicked, this, &VExporter::openTargetPath);

    QPushButton *okBtn = m_btnBox->button(QDialogButtonBox::Ok);
    m_pathEdit->setMinimumWidth(okBtn->sizeHint().width() * 3);

    QGridLayout *mainLayout = new QGridLayout();
    mainLayout->addWidget(m_infoLabel, 0, 0, 1, 3);
    mainLayout->addWidget(pathLabel, 1, 0);
    mainLayout->addWidget(m_pathEdit, 1, 1);
    mainLayout->addWidget(m_browseBtn, 1, 2);
    mainLayout->addWidget(layoutLabel, 2, 0);
    mainLayout->addWidget(m_layoutLabel, 2, 1);
    mainLayout->addWidget(m_layoutBtn, 2, 2);
    mainLayout->addWidget(m_proLabel, 3, 1, 1, 2);
    mainLayout->addWidget(m_proBar, 4, 1, 1, 2);
    mainLayout->addWidget(m_btnBox, 5, 1, 1, 2);

    m_proLabel->hide();
    m_proBar->hide();

    setLayout(mainLayout);
    mainLayout->setSizeConstraint(QLayout::SetFixedSize);
    setWindowTitle(tr("Export Note"));

    m_openBtn->hide();

    updatePageLayoutLabel();
}

static QString exportTypeStr(ExportType p_type)
{
    if (p_type == ExportType::PDF) {
        return "PDF";
    } else {
        return "HTML";
    }
}

void VExporter::handleBrowseBtnClicked()
{
    QFileInfo fi(getFilePath());
    QString fileType = m_type == ExportType::PDF ?
                       tr("Portable Document Format (*.pdf)") :
                       tr("WebPage, Complete (*.html)");
    QString path = QFileDialog::getSaveFileName(this, tr("Export As"),
                                                fi.absoluteFilePath(),
                                                fileType);
    if (path.isEmpty()) {
        return;
    }

    setFilePath(path);
    s_defaultPathDir = VUtils::basePathFromPath(path);

    m_openBtn->hide();
}

void VExporter::handleLayoutBtnClicked()
{
#ifndef QT_NO_PRINTER
    QPrinter printer;
    printer.setPageLayout(m_pageLayout);

    QPageSetupDialog dlg(&printer, this);
    if (dlg.exec() != QDialog::Accepted) {
        return;
    }

    m_pageLayout.setPageSize(printer.pageLayout().pageSize());
    m_pageLayout.setOrientation(printer.pageLayout().orientation());

    updatePageLayoutLabel();
#endif
}

void VExporter::updatePageLayoutLabel()
{
    m_layoutLabel->setText(QString("%1, %2").arg(m_pageLayout.pageSize().name())
                                            .arg(m_pageLayout.orientation() == QPageLayout::Portrait ?
                                                 tr("Portrait") : tr("Landscape")));
}

QString VExporter::getFilePath() const
{
    return QDir::cleanPath(m_pathEdit->text());
}

void VExporter::setFilePath(const QString &p_path)
{
    m_pathEdit->setText(QDir::toNativeSeparators(p_path));
}

void VExporter::exportNote(VFile *p_file, ExportType p_type)
{
    m_file = p_file;
    m_type = p_type;
    m_source = ExportSource::Note;

    if (!m_file || m_file->getDocType() != DocType::Markdown) {
        // Do not support non-Markdown note now.
        m_btnBox->button(QDialogButtonBox::Ok)->setEnabled(false);
        return;
    }

    m_infoLabel->setText(tr("Export note %2 as %3.")
                            .arg(vconfig.c_dataTextStyle)
                            .arg(m_file->getName())
                            .arg(exportTypeStr(p_type)));

    setWindowTitle(tr("Export As %1").arg(exportTypeStr(p_type)));

    setFilePath(QDir(s_defaultPathDir).filePath(QFileInfo(p_file->retrivePath()).baseName() +
                                                "." + exportTypeStr(p_type).toLower()));
}

void VExporter::initWebViewer(VFile *p_file)
{
    V_ASSERT(!m_webViewer);

    m_webViewer = new VWebView(p_file, this);
    m_webViewer->hide();
    VPreviewPage *page = new VPreviewPage(m_webViewer);
    m_webViewer->setPage(page);

    connect(page, &VPreviewPage::loadFinished,
            this, &VExporter::handleLoadFinished);

    VDocument *document = new VDocument(p_file, m_webViewer);
    connect(document, &VDocument::logicsFinished,
            this, &VExporter::handleLogicsFinished);

    QWebChannel *channel = new QWebChannel(m_webViewer);
    channel->registerObject(QStringLiteral("content"), document);
    page->setWebChannel(channel);

    // Need to generate HTML using Hoedown.
    if (m_mdType == MarkdownConverterType::Hoedown) {
        VMarkdownConverter mdConverter;
        QString toc;
        QString html = mdConverter.generateHtml(p_file->getContent(),
                                                vconfig.getMarkdownExtensions(),
                                                toc);
        document->setHtml(html);
    }

    m_webViewer->setHtml(m_htmlTemplate, p_file->getBaseUrl());
}

void VExporter::clearWebViewer()
{
    if (m_webViewer) {
        delete m_webViewer;
        m_webViewer = NULL;
    }
}

void VExporter::handleLogicsFinished()
{
    Q_ASSERT(!(m_noteState & NoteState::WebLogicsReady));
    m_noteState = NoteState(m_noteState | NoteState::WebLogicsReady);
}

void VExporter::handleLoadFinished(bool p_ok)
{
    Q_ASSERT(!(m_noteState & NoteState::WebLoadFinished));
    m_noteState = NoteState(m_noteState | NoteState::WebLoadFinished);

    if (!p_ok) {
        m_noteState = NoteState(m_noteState | NoteState::Failed);
    }
}

void VExporter::clearNoteState()
{
    m_noteState = NoteState::NotReady;
}

bool VExporter::isNoteStateReady() const
{
    return m_noteState == NoteState::Ready;
}

bool VExporter::isNoteStateFailed() const
{
    return m_noteState & NoteState::Failed;
}

void VExporter::startExport()
{
    QPushButton *cancelBtn = m_btnBox->button(QDialogButtonBox::Cancel);

    if (m_exported) {
        cancelBtn->show();
        m_exported = false;
        accept();
    }

    int exportedNum = 0;
    enableUserInput(false);
    V_ASSERT(m_state == ExportState::Idle);
    m_state = ExportState::Busy;

    m_openBtn->hide();

    if (m_source == ExportSource::Note) {
        V_ASSERT(m_file);
        bool isOpened = m_file->isOpened();
        if (!isOpened && !m_file->open()) {
            goto exit;
        }

        clearNoteState();
        initWebViewer(m_file);

        // Update progress info.
        m_proLabel->setText(tr("Exporting %1").arg(m_file->getName()));
        m_proBar->setEnabled(true);
        m_proBar->setMinimum(0);
        m_proBar->setMaximum(100);
        m_proBar->reset();
        m_proLabel->show();
        m_proBar->show();

        while (!isNoteStateReady()) {
            VUtils::sleepWait(100);
            if (m_proBar->value() < 70) {
                m_proBar->setValue(m_proBar->value() + 1);
            }

            if (m_state == ExportState::Cancelled) {
                goto exit;
            }

            if (isNoteStateFailed()) {
                m_state = ExportState::Failed;
                goto exit;
            }
        }

        // Wait to ensure Web side is really ready.
        VUtils::sleepWait(200);

        if (m_state == ExportState::Cancelled) {
            goto exit;
        }

        m_proBar->setValue(80);

        bool exportRet = exportToPDF(m_webViewer, getFilePath(), m_pageLayout);

        clearNoteState();

        if (!isOpened) {
            m_file->close();
        }

        if (exportRet) {
            m_proBar->setValue(100);
            m_state = ExportState::Successful;
            exportedNum++;
        } else {
            m_proBar->setEnabled(false);
            m_state = ExportState::Failed;
        }
    }

exit:
    clearWebViewer();

    m_proLabel->setText("");
    m_proLabel->hide();
    enableUserInput(true);

    if (m_state == ExportState::Cancelled) {
        reject();
    }

    if (exportedNum) {
        m_exported = true;
        m_openBtn->show();
        cancelBtn->hide();
    }

    m_state = ExportState::Idle;
}

void VExporter::cancelExport()
{
    if (m_state == ExportState::Idle) {
        reject();
    } else {
        m_state = ExportState::Cancelled;
    }
}

bool VExporter::exportToPDF(VWebView *p_webViewer, const QString &p_filePath,
                            const QPageLayout &p_layout)
{
    int pdfPrinted = 0;
    p_webViewer->page()->printToPdf([&, this](const QByteArray &p_result) {
        if (p_result.isEmpty() || this->m_state == ExportState::Cancelled) {
            pdfPrinted = -1;
            return;
        }

        V_ASSERT(!p_filePath.isEmpty());

        QFile file(p_filePath);

        if (!file.open(QFile::WriteOnly)) {
            pdfPrinted = -1;
            return;
        }

        file.write(p_result.data(), p_result.size());
        file.close();

        pdfPrinted = 1;
    }, p_layout);

    while (pdfPrinted == 0) {
        VUtils::sleepWait(100);

        if (m_state == ExportState::Cancelled) {
            break;
        }
    }

    return pdfPrinted == 1;
}

void VExporter::enableUserInput(bool p_enabled)
{
    m_btnBox->button(QDialogButtonBox::Ok)->setEnabled(p_enabled);
    m_pathEdit->setEnabled(p_enabled);
    m_browseBtn->setEnabled(p_enabled);
    m_layoutBtn->setEnabled(p_enabled);
}

void VExporter::openTargetPath() const
{
    QUrl url = QUrl::fromLocalFile(VUtils::basePathFromPath(getFilePath()));
    QDesktopServices::openUrl(url);
}
<|endoftext|>