Commit cfa755ec authored by Claes's avatar Claes Committed by Esteban Blanc

Regression test fixes

parent 5171e8a4
! Generated by wb_print_wbl 26-MAR-2020 11:53:42.87
! Generated by wb_print_wbl 28-MAY-2020 16:31:59.88
! Volume directory
! Version V5.7.1
Volume directory $DirectoryVolume 254.254.254.253
......@@ -16,7 +16,7 @@ Volume directory $DirectoryVolume 254.254.254.253
Attr BusNumber = 999
EndBody
Object PwrTest01a NodeConfig 10 25-MAR-2020 09:04:16.06
Body RtBody 26-MAR-2020 10:40:52.48
Body RtBody 28-MAY-2020 16:31:59.83
Attr NodeName = "pwrtest01a"
Attr OperatingSystem = 128
Attr Address = "127.0.0.1"
......@@ -42,7 +42,7 @@ Volume directory $DirectoryVolume 254.254.254.253
EndObject
EndObject
Object PwrTest01b NodeConfig 26 25-MAR-2020 09:06:55.29
Body RtBody 26-MAR-2020 10:40:52.48
Body RtBody 28-MAY-2020 16:31:59.83
Attr NodeName = "pwrtest01b"
Attr OperatingSystem = 128
Attr Address = "127.0.0.1"
......@@ -68,7 +68,7 @@ Volume directory $DirectoryVolume 254.254.254.253
EndObject
EndObject
Object PwrTest01c NodeConfig 33 26-MAR-2020 10:23:36.40
Body RtBody 26-MAR-2020 10:40:52.48
Body RtBody 28-MAY-2020 16:31:59.84
Attr NodeName = "pwrtest01c"
Attr OperatingSystem = 128
Attr Address = "127.0.0.1"
......@@ -94,7 +94,7 @@ Volume directory $DirectoryVolume 254.254.254.253
EndObject
EndObject
Object PwrTest01d SevNodeConfig 38 26-MAR-2020 10:24:30.82
Body RtBody 26-MAR-2020 11:53:41.73
Body RtBody 28-MAY-2020 16:31:59.84
Attr NodeName = "pwrtest01d"
Attr OperatingSystem = 128
Attr Address = "127.0.0.1"
......
......@@ -269,3 +269,31 @@
1 26-MAR-2020 10:42:10.97 14971 WbLogin claes pwrp
1 26-MAR-2020 11:53:21.04 8575 WbLogin claes pwrp
1 26-MAR-2020 11:53:42.88 8575 ConfigSave claes directory
2 28-MAY-2020 16:32:03.98 6146 DirectoryBuild claes appl
3 28-MAY-2020 16:32:07.41 6146 PlcBuild claes VolPwrTest01a:Test01a-H1-Plc-W
2 28-MAY-2020 16:32:07.57 6146 VolumeBuild claes VolPwrTest01a
2 28-MAY-2020 16:32:08.20 6146 NodeBuild claes PwrTest01a
2 28-MAY-2020 16:32:08.20 6146 DirectoryBuild claes pop
2 28-MAY-2020 16:32:08.20 6146 DirectoryBuild claes pwr_exe
1 28-MAY-2020 16:32:08.86 6242 CreatePackage claes pwrtest01a "pwrp_pkg_pwrtest01a_0001.tgz"
2 28-MAY-2020 16:32:12.87 6307 DirectoryBuild claes appl
3 28-MAY-2020 16:32:13.49 6307 PlcBuild claes VolPwrTest01b:Test01b-H1-Plc-W
2 28-MAY-2020 16:32:13.61 6307 VolumeBuild claes VolPwrTest01b
2 28-MAY-2020 16:32:13.87 6307 NodeBuild claes PwrTest01b
2 28-MAY-2020 16:32:13.87 6307 DirectoryBuild claes pop
2 28-MAY-2020 16:32:13.87 6307 DirectoryBuild claes pwr_exe
1 28-MAY-2020 16:32:14.43 6403 CreatePackage claes pwrtest01b "pwrp_pkg_pwrtest01b_0001.tgz"
2 28-MAY-2020 16:32:18.87 6468 DirectoryBuild claes appl
3 28-MAY-2020 16:32:21.15 6468 PlcBuild claes VolPwrTest01c:Test01c-H1-Plc-W
2 28-MAY-2020 16:32:21.37 6468 VolumeBuild claes VolPwrTest01c
2 28-MAY-2020 16:32:21.65 6468 NodeBuild claes PwrTest01c
2 28-MAY-2020 16:32:21.65 6468 DirectoryBuild claes pop
2 28-MAY-2020 16:32:21.65 6468 DirectoryBuild claes pwr_exe
1 28-MAY-2020 16:32:22.29 6565 CreatePackage claes pwrtest01c "pwrp_pkg_pwrtest01c_0001.tgz"
2 28-MAY-2020 16:32:26.60 6630 DirectoryBuild claes appl
3 28-MAY-2020 16:32:27.21 6630 PlcBuild claes VolPwrTest01d:Test01d-H1-Plc-W
2 28-MAY-2020 16:32:27.33 6630 VolumeBuild claes VolPwrTest01d
2 28-MAY-2020 16:32:27.59 6630 NodeBuild claes PwrTest01d
2 28-MAY-2020 16:32:27.59 6630 DirectoryBuild claes pop
2 28-MAY-2020 16:32:27.59 6630 DirectoryBuild claes pwr_exe
1 28-MAY-2020 16:32:28.06 6724 CreatePackage claes pwrtest01d "pwrp_pkg_pwrtest01d_0001.tgz"
......@@ -161,7 +161,7 @@ void rt_sysmon::open()
} catch (co_error& e) {
delete o;
objects.pop_back();
errh_Error("DiskSup configuration error: &s", (char*)e.what().c_str());
errh_Error("DiskSup configuration error: %s", (char*)e.what().c_str());
}
}
}
......
......@@ -35,12 +35,12 @@ silent :
.SUFFIXES:
$(exe_dir)/pwrrt.so : pwrrtmodule.c
@ if [ "$(PWRE_CONF_PYDEV)" == "1" ]; then\
@ if [ "$(PWRE_CONF_PYDEV)" = "1" ]; then\
echo "Bulding Python c extension pwrrt";\
python setup_pwrrt.py -q build --build-base $(bld_dir);\
if [ "$(pwre_hw)" == "hw_x86_64" ]; then \
if [ "$(pwre_hw)" = "hw_x86_64" ]; then \
mv $(bld_dir)/lib.linux-x86_64-2.7/pwrrt.so $(pwr_exe); \
elif [ "$(pwre_hw)" == "hw_x86" ]; then \
elif [ "$(pwre_hw)" = "hw_x86" ]; then \
mv $(bld_dir)/lib.linux-i686-2.7/pwrrt.so $(pwr_exe); \
fi;\
python setup_pwrrt.py -q install_egg_info --install-dir $(pwr_exe);\
......
......@@ -805,6 +805,7 @@ user = pwrrt.getUser()\n");
typedef struct {
PyObject_HEAD
pwr_tOid oid;
pwr_tStatus sts;
} OidObject;
static PyObject *Oid_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
......@@ -879,6 +880,7 @@ static PyTypeObject OidType = {
typedef struct {
PyObject_HEAD
pwr_tAttrRef aref;
pwr_tStatus sts;
} ArefObject;
static PyObject *Aref_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
......@@ -1159,6 +1161,7 @@ typedef struct {
unsigned int size;
void *p;
pwr_tRefId refid;
pwr_tStatus sts;
} SubObject;
static PyObject *Sub_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
......@@ -1310,6 +1313,7 @@ Oid_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self = (OidObject *)type->tp_alloc(type, 0);
if (self != NULL) {
self->oid = pwr_cNOid;
self->sts = GDH__SUCCESS;
}
return (PyObject *)self;
......@@ -1324,9 +1328,18 @@ Oid_str(PyObject *self)
oid = ((OidObject *)self)->oid;
sts = gdh_ObjidToName( oid, name, sizeof(name), cdh_mName_path | cdh_mName_object);
if ( EVEN(sts))
strcpy( name, "Unknown");
if (oid.oix != 0) {
sts = gdh_ObjidToName( oid, name, sizeof(name), cdh_mName_path | cdh_mName_object);
if ( EVEN(sts))
return set_error(sts);
}
else {
sts = gdh_ObjidToName( oid, name, sizeof(name), cdh_mName_volume);
if ( EVEN(sts))
return set_error(sts);
else
name[strlen(name)-1] = 0;
}
return PyUnicode_FromFormat("%s", name);
}
......@@ -1337,7 +1350,16 @@ Oid_richcompare(PyObject *self, PyObject *other, int op)
PyObject *result = NULL;
if ( Py_TYPE(other) != &OidType) {
result = Py_NotImplemented;
if (Py_TYPE(other) == &PyBool_Type) {
long oval = PyInt_AsLong(other);
if ((ODD(((OidObject *)self)->sts) && oval) ||
(EVEN(((OidObject *)self)->sts) && !oval))
result = Py_True;
else
result = Py_False;
}
else
result = Py_NotImplemented;
}
else {
switch ( op) {
......@@ -1380,15 +1402,19 @@ Oid_init(OidObject *self, PyObject *args, PyObject *kwds)
if ( name) {
sts = gdh_NameToObjid( name, &oid);
if ( EVEN(sts)) {
self->sts = sts;
set_error(sts);
return -1;
}
}
else {
sts = gdh_GetRootList(&oid);
if ( EVEN(sts))
if ( EVEN(sts)) {
self->sts = sts;
return -1;
}
}
self->sts = sts;
self->oid = oid;
return 0;
......@@ -1397,12 +1423,24 @@ Oid_init(OidObject *self, PyObject *args, PyObject *kwds)
static PyObject *
Oid_name(OidObject *self, PyObject *args)
{
if (EVEN(self->sts))
return set_error(self->sts);
pwr_tOName name;
pwr_tStatus sts;
sts = gdh_ObjidToName( self->oid, name, sizeof(name), cdh_mName_object);
if ( EVEN(sts))
strcpy( name, "");
if (self->oid.oix != 0) {
sts = gdh_ObjidToName( self->oid, name, sizeof(name), cdh_mName_object);
if ( EVEN(sts))
return set_error(sts);
}
else {
sts = gdh_ObjidToName( self->oid, name, sizeof(name), cdh_mName_volume);
if ( EVEN(sts))
return set_error(sts);
else
name[strlen(name)-1] = 0;
}
return Py_BuildValue("s", name);
}
......@@ -1413,9 +1451,12 @@ Oid_fullName(OidObject *self, PyObject *args)
pwr_tOName name;
pwr_tStatus sts;
if (EVEN(self->sts))
return set_error(self->sts);
sts = gdh_ObjidToName( self->oid, name, sizeof(name), cdh_mName_volumeStrict);
if ( EVEN(sts))
strcpy( name, "");
return set_error(sts);
return Py_BuildValue("s", name);
}
......@@ -1423,6 +1464,9 @@ Oid_fullName(OidObject *self, PyObject *args)
static PyObject *
Oid_oidStr(PyObject *s, PyObject *args)
{
if (EVEN(((OidObject *)s)->sts))
return set_error(((OidObject *)s)->sts);
char str[30];
const char *name = 0;
pwr_tOid oid = ((OidObject *)s)->oid;
......@@ -1460,6 +1504,9 @@ Oid_oidStr(PyObject *s, PyObject *args)
static PyObject *
Oid_next(OidObject *self, PyObject *args)
{
if (EVEN(self->sts))
return set_error(self->sts);
pwr_tOid soid;
OidObject *sibling;
pwr_tStatus sts;
......@@ -1487,6 +1534,9 @@ Oid_next(OidObject *self, PyObject *args)
static PyObject *
Oid_parent(OidObject *self, PyObject *args)
{
if (EVEN(self->sts))
return set_error(self->sts);
pwr_tOid poid;
OidObject *parent;
pwr_tStatus sts;
......@@ -1506,6 +1556,9 @@ Oid_parent(OidObject *self, PyObject *args)
static PyObject *
Oid_child(OidObject *self, PyObject *args)
{
if (EVEN(self->sts))
return set_error(self->sts);
pwr_tOid coid;
OidObject *child;
pwr_tStatus sts;
......@@ -1525,6 +1578,9 @@ Oid_child(OidObject *self, PyObject *args)
static PyObject *
Oid_children(PyObject *s)
{
if (EVEN(((OidObject *)s)->sts))
return set_error(((OidObject *)s)->sts);
pwr_tOid coid;
OidObject *child;
pwr_tStatus sts;
......@@ -1555,6 +1611,9 @@ Oid_children(PyObject *s)
static PyObject *
Oid_cid(OidObject *self, PyObject *args)
{
if (EVEN(self->sts))
return set_error(self->sts);
pwr_tCid cid;
CidObject *cid_object;
pwr_tStatus sts;
......@@ -1573,6 +1632,9 @@ Oid_cid(OidObject *self, PyObject *args)
static PyObject *
Oid_attribute(OidObject *self, PyObject *args)
{
if (EVEN(self->sts))
return set_error(self->sts);
pwr_tAttrRef aref, oaref;
ArefObject *aref_object;
pwr_tStatus sts;
......@@ -1602,9 +1664,10 @@ Aref_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
ArefObject *self;
self = (ArefObject *)type->tp_alloc(type, 0);
if (self != NULL)
if (self != NULL) {
self->aref = pwr_cNAttrRef;
self->sts = GDH__SUCCESS;
}
return (PyObject *)self;
}
......@@ -1686,6 +1749,7 @@ Aref_init(ArefObject *self, PyObject *args, PyObject *kwds)
sts = gdh_NameToAttrref( pwr_cNOid, name, &self->aref);
if ( EVEN(sts)) {
set_error(sts);
self->sts = sts;
return -1;
}
}
......@@ -1696,6 +1760,9 @@ Aref_init(ArefObject *self, PyObject *args, PyObject *kwds)
static PyObject *
Aref_name(ArefObject *self, PyObject *args)
{
if (EVEN(self->sts))
return set_error(self->sts);
pwr_tOName name;
pwr_tStatus sts;
......@@ -1709,6 +1776,9 @@ Aref_name(ArefObject *self, PyObject *args)
static PyObject *
Aref_fullName(ArefObject *self, PyObject *args)
{
if (EVEN(self->sts))
return set_error(self->sts);
pwr_tOName name;
pwr_tStatus sts;
......@@ -1722,6 +1792,9 @@ Aref_fullName(ArefObject *self, PyObject *args)
static PyObject *
Aref_arefStr(ArefObject *self, PyObject *args)
{
if (EVEN(self->sts))
return set_error(self->sts);
pwr_tAName name;
cdh_ArefToString( name, sizeof(name), &self->aref, 1);
......@@ -1732,6 +1805,9 @@ Aref_arefStr(ArefObject *self, PyObject *args)
static PyObject *
Aref_tid(ArefObject *self, PyObject *args)
{
if (EVEN(self->sts))
return set_error(self->sts);
pwr_tTid tid;
TidObject *tid_object;
pwr_tStatus sts;
......@@ -1750,6 +1826,9 @@ Aref_tid(ArefObject *self, PyObject *args)
static PyObject *
Aref_value(ArefObject *self, PyObject *args)
{
if (EVEN(self->sts))
return set_error(self->sts);
pwr_tStatus sts;
char *buf;
pwr_eType atype;
......@@ -1827,14 +1906,16 @@ Aref_value(ArefObject *self, PyObject *args)
case pwr_eType_Float32: {
pwr_tFloat32 value = *(pwr_tFloat32 *)buf;
free(buf);
return Py_BuildValue("d", value);
return Py_BuildValue("f", value);
}
case pwr_eType_Float64: {
pwr_tFloat64 value = *(pwr_tFloat64 *)buf;
free(buf);
return Py_BuildValue("D", value);
return Py_BuildValue("d", value);
}
case pwr_eType_String: {
case pwr_eType_String:
case pwr_eType_Text:
case pwr_eType_ProString: {
PyObject *ret = Py_BuildValue("s", buf);
free(buf);
return ret;
......@@ -1881,6 +1962,9 @@ Aref_value(ArefObject *self, PyObject *args)
static PyObject *
Aref_setValue(ArefObject *self, PyObject *args)
{
if (EVEN(self->sts))
return set_error(self->sts);
pwr_tStatus sts;
char *buf;
pwr_eType atype;
......@@ -1967,7 +2051,7 @@ Aref_setValue(ArefObject *self, PyObject *args)
break;
}
case pwr_eType_Float64: {
if ( !PyArg_ParseTuple(args, "D|I", buf, &publicwrite))
if ( !PyArg_ParseTuple(args, "d|I", buf, &publicwrite))
goto error_return;
break;
}
......@@ -2602,11 +2686,15 @@ Sub_init(SubObject *self, PyObject *args, PyObject *kwds)
return -1;
sts = gdh_GetAttributeCharacteristics(name, &atype, &asize, 0, 0);
if (EVEN(sts))
if (EVEN(sts)) {
self->sts = sts;
self->p = 0;
return -1;
}
sts = gdh_RefObjectInfo(name, &self->p, &self->refid, asize);
if ( EVEN(sts)) {
self->sts = sts;
self->p = 0;
return -1;
}
......@@ -2620,7 +2708,7 @@ static PyObject *
Sub_value(SubObject *self, PyObject *args)
{
if ( self->p == 0)
return NULL;
return set_error(self->sts);
switch ( self->type) {
case pwr_eType_Boolean: {
......@@ -2673,11 +2761,11 @@ Sub_value(SubObject *self, PyObject *args)
}
case pwr_eType_Float32: {
pwr_tFloat32 value = *(pwr_tFloat32 *)self->p;
return Py_BuildValue("d", value);
return Py_BuildValue("f", value);
}
case pwr_eType_Float64: {
pwr_tFloat64 value = *(pwr_tFloat64 *)self->p;
return Py_BuildValue("D", value);
return Py_BuildValue("d", value);
}
case pwr_eType_String:
return Py_BuildValue("s", self->p);
......@@ -2712,7 +2800,7 @@ Sub_value(SubObject *self, PyObject *args)
return (PyObject *)arefo;
}
default:
return NULL;
return set_error(GDH__BADOBJTYPE);
}
Py_RETURN_NONE;
}
......@@ -2801,7 +2889,7 @@ Sub_setValue(SubObject *self, PyObject *args)
break;
}
case pwr_eType_Float64: {
if ( !PyArg_ParseTuple(args, "D", buf))
if ( !PyArg_ParseTuple(args, "d", buf))
goto error_return;
break;
}
......@@ -3227,9 +3315,8 @@ static PyObject *pwrrt_volume(PyObject *self, PyObject *args)
}
o = (OidObject *)Oid_new(&OidType, 0, 0);
if (o != NULL) {
if (o != NULL)
o->oid = oid;
}
return (PyObject *)o;
}
......@@ -3267,6 +3354,8 @@ static PyObject *pwrrt_object(PyObject *self, PyObject *args)
{
PyObject *o = Oid_new(&OidType, args, 0);
Oid_init((OidObject *)o, args, 0);
if (EVEN(((OidObject *)o)->sts))
return NULL;
return o;
}
......@@ -3274,6 +3363,8 @@ static PyObject *pwrrt_attribute(PyObject *self, PyObject *args)
{
PyObject *a = Aref_new(&ArefType, args, 0);
Aref_init((ArefObject *)a, args, 0);
if (EVEN(((ArefObject *)a)->sts))
return NULL;
return a;
}
......
......@@ -34,7 +34,9 @@
* General Public License plus this exception.
*/
#include <stdarg.h>
#include "co_nav_crr.h"
#include "co_tst_log.h"
extern "C" {
#include "co_api.h"
......@@ -103,3 +105,37 @@ int crr_object(void* parent_ctx, char* objectname,
delete navcrr;
return sts;
}
void *tst_log_open(pwr_tStatus *sts, char *category, char *file)
{
tst_log *log = new tst_log(sts, category, file);
return (void *)log;
}
void tst_log_close(void *log)
{
delete (tst_log *)log;
}
void tst_log_log(void *log, const char severity, const char *text1,
const char *text2)
{
((tst_log *)log)->log(severity, text1, text2);
}
void tst_log_slog(void *log, const char severity, const char *text1,
const char *text2, pwr_tStatus status)
{
((tst_log *)log)->log(severity, text1, text2, status);
}
void tst_log_vlog(void *log, const char severity, const char *format, ...)
{
va_list ap;
char msg[200];
va_start(ap, format);
vsnprintf(msg, sizeof(msg), format, ap);
va_end(ap);
((tst_log *)log)->log(severity, msg);
}
......@@ -73,6 +73,15 @@ int crr_object(void* parent_ctx, char* objectname,
void (*insert_cb)(void*, void*, navc_eItemType, char*, char*, int),
int (*name_to_objid_cb)(void*, char*, pwr_tObjid*),
int (*get_volume_cb)(void*, pwr_tVid*, pwr_tVid));
void *tst_log_open(pwr_tStatus *sts, char *category, char *file);
void tst_log_close(void *log);
void tst_log_log(void *log, const char severity, const char *text1,
const char *text2);
void tst_log_slog(void *log, const char severity, const char *text1,
const char *text2, pwr_tStatus status);
void tst_log_vlog(void *log, const char severity, const char *format, ...);
#if defined __cplusplus
}
#endif
......
/**
* ProviewR Open Source Process Control.
* Copyright (C) 2005-2020 SSAB EMEA AB.
......@@ -437,7 +438,7 @@ pwr_tStatus cdh_AttrValueToString(
snprintf(String, MaxSize, "%s", (char*)Value);
break;
case pwr_eType_ProString: {
int len = MAX(strlen((char*)Value), MaxSize);
int len = MIN(strlen((char*)Value), MaxSize-1);
int i;
strcpy(String, "");
for (i = 0; i < len; i++)
......@@ -604,7 +605,7 @@ pwr_tStatus cdh_StringToAttrValue(
}
}
ui16val = ui32val;
memcpy(Value, &ui16val, sizeof(ui32val));
memcpy(Value, &ui16val, sizeof(ui16val));
break;
case pwr_eType_UInt32:
......@@ -812,11 +813,11 @@ pwr_tStatus cdh_StringToObjid(const char* s, pwr_tObjid* oid)
s++;
if (sscanf(s, "%d.%d.%d.%d:%u%*s", &vid_3, &vid_2, &vid_1, &vid_0, &oix) != 5)
return CDH__INVCID;
return CDH__INVOID;
if (vid_3 > cdh_cMaxVidGroup || vid_2 > cdh_cMaxVidGroup
|| vid_1 > cdh_cMaxVidGroup || vid_0 > cdh_cMaxVidGroup) {
return CDH__INVCID;
return CDH__INVOID;
}
loid.o.vid_3 = vid_3;
......@@ -832,9 +833,10 @@ pwr_tStatus cdh_StringToObjid(const char* s, pwr_tObjid* oid)
//! Convert AttrRef string to id.
/*!
Convert a string of format "_A1.2.3.4:34(_T44.33:0.5.1)[760,4]" ('_A' is
Convert a string of format "_A1.2.3.4:34(_T44.33:0.5.1)[760.4]" ('_A' is
optional), where
1.2.3.4 is the volume id and 34 is the object index.
1.2.3.4 is the volume id and 34 is the object index,
_T44.33:0.5.1 is the body typeid, 760 the offset and 4 the size.
\param s String.
\param aref Attribute reference.
......@@ -1273,7 +1275,7 @@ char* cdh_AttrRefToString(pwr_sAttrRef* aref, int prefix)
If 's' is non null the resultant string will be catenated
to 's', otherwise the resultant string will be returned.
If 'prefix' is not zero, a '_V' prefix will be included in
If 'prefix' is not zero, a '_N' prefix will be included in
the resultant string.
If 'suffix' is not zero, a ':' suffix will be included in
......@@ -2734,6 +2736,11 @@ void cdh_CutNameSegments(char* outname, char* name, int segments)
char* s[20];
int i, j, last_i = 0;
if (segments == 0) {
strcpy(outname, "");
return;
}
for (i = 0; i < segments; i++) {
s[i] = strrchr(name, '-');
if (s[i] == 0) {
......
......@@ -111,7 +111,7 @@ static pwr_tStatus validateTm(struct tm* tms)
/* Check generic ranges. */
if (69 > tms->tm_year || tms->tm_year > 137) /* EPOCH is 1970 end feb 2038 */
if (69 > tms->tm_year /*|| tms->tm_year > 137*/) /* EPOCH is 1970 end feb 2038 */
return TIME__RANGE;
else if (0 > tms->tm_mon || tms->tm_mon > 11)
return TIME__RANGE;
......@@ -260,10 +260,10 @@ pwr_tTime* time_Aadd_NE(pwr_tTime* result, pwr_tTime* t, pwr_tDeltaTime* a)
}
//! Compare two timespecs.
/*! Returns
1 if t1 > t2
0 if t1 == t2
-1 if t1 < t2
/*! Returns \n
1 if t1 > t2 \n
0 if t1 == t2 \n
-1 if t1 < t2 \n
If argument 't2' is NULL the comparison will
be done as if t2 == 0.
......@@ -291,10 +291,10 @@ int time_Acomp(pwr_tTime* t1, pwr_tTime* t2)
}
//! Compare two timespecs.
/*! Returns
1 if t1 > t2
0 if t1 == t2
-1 if t1 < t2
/*! Returns \n
1 if t1 > t2 \n
0 if t1 == t2 \n
-1 if t1 < t2 \n
If argument 't2' is NULL the comparison will
be done as if t2 == 0.
......@@ -482,7 +482,11 @@ pwr_tDeltaTime* time_Dabs(pwr_tDeltaTime* result, pwr_tDeltaTime* t)
if (r == NULL)
r = t;
else {
r->tv_sec = t->tv_sec;
r->tv_nsec = t->tv_nsec;
}
if (r->tv_sec < 0)
r->tv_sec = -r->tv_sec;
if (r->tv_nsec < 0)
......@@ -508,6 +512,10 @@ pwr_tDeltaTime* time_Dabs_NE(pwr_tDeltaTime* result, pwr_tDeltaTime* t)
if (r == NULL)
r = t;
else {
r->tv_sec = t->tv_sec;
r->tv_nsec = t->tv_nsec;
}
if (notADeltaTime(t)) {
*r = pwr_cNotADeltaTime;
......@@ -599,10 +607,10 @@ pwr_tDeltaTime* time_Dadd_NE(
}
//! Compare two delta times.
/*! Returns
1 if t1 > t2
0 if t1 == t2
-1 if t1 < t2
/*! Returns \n
1 if t1 > t2 \n
0 if t1 == t2 \n
-1 if t1 < t2 \n
If argument 't2' is NULL the comparison will
be done as if t2 == 0.
......@@ -630,10 +638,10 @@ int time_Dcomp(pwr_tDeltaTime* t1, pwr_tDeltaTime* t2)
}
//! Compare two delta times.
/*! Returns
1 if t1 > t2
0 if t1 == t2
-1 if t1 < t2
/*! Returns \n
1 if t1 > t2 \n
0 if t1 == t2 \n
-1 if t1 < t2 \n
If argument 't2' is NULL the comparison will
be done as if t2 == 0.
......@@ -680,6 +688,10 @@ pwr_tDeltaTime* time_Dneg(pwr_tDeltaTime* result, pwr_tDeltaTime* t)
if (r == NULL)
r = t;
else {
r->tv_sec = t->tv_sec;
r->tv_nsec = t->tv_nsec;
}
r->tv_sec = -r->tv_sec;
r->tv_nsec = -r->tv_nsec;
......@@ -705,6 +717,10 @@ pwr_tDeltaTime* time_Dneg_NE(pwr_tDeltaTime* result, pwr_tDeltaTime* t)
if (r == NULL)
r = t;
else {
r->tv_sec = t->tv_sec;
r->tv_nsec = t->tv_nsec;
}
if (notADeltaTime(t)) {
*r = pwr_cNotADeltaTime;
......@@ -796,8 +812,10 @@ pwr_tDeltaTime* time_Dsub_NE(
pwr_tStatus time_DtoAscii(
pwr_tDeltaTime* dt, int hundreds, char* buf, int bufsize)
{
char tmpStr[24];
char tmpStr[32];
div_t day, hour, min;
pwr_tDeltaTime t;
int neg = 0;
if (dt == NULL)
return TIME__IVDTIME;
......@@ -808,6 +826,13 @@ pwr_tStatus time_DtoAscii(
return TIME__NADT;
}
if (dt->tv_sec < 0 || dt->tv_nsec < 0) {
neg = 1;
t.tv_sec = abs(dt->tv_sec);
t.tv_nsec = abs(dt->tv_nsec);
dt = &t;
}
day = div(dt->tv_sec, 24 * 3600);
hour = div(day.rem, 3600);
min = div(hour.rem, 60);
......@@ -815,17 +840,17 @@ pwr_tStatus time_DtoAscii(
if (day.quot) {
if (hundreds) {
long int nsec = dt->tv_nsec / 10000000;
sprintf(tmpStr, "%d %d:%02d:%02d.%02ld", day.quot, hour.quot, min.quot,
sprintf(tmpStr, "%s%d %d:%02d:%02d.%02ld", neg?"-":"", day.quot, hour.quot, min.quot,
min.rem, nsec);
} else
sprintf(
tmpStr, "%d %d:%02d:%02d", day.quot, hour.quot, min.quot, min.rem);
tmpStr, "%s%d %d:%02d:%02d", neg?"-":"", day.quot, hour.quot, min.quot, min.rem);
} else {
if (hundreds) {
long int nsec = dt->tv_nsec / 10000000;
sprintf(tmpStr, "%d:%02d:%02d.%02ld", hour.quot, min.quot, min.rem, nsec);
sprintf(tmpStr, "%s%d:%02d:%02d.%02ld", neg?"-":"", hour.quot, min.quot, min.rem, nsec);
} else
sprintf(tmpStr, "%d:%02d:%02d", hour.quot, min.quot, min.rem);
sprintf(tmpStr, "%s%d:%02d:%02d", neg?"-":"", hour.quot, min.quot, min.rem);
}
strncpy(buf, tmpStr, bufsize);
......@@ -868,6 +893,7 @@ pwr_tStatus time_AtoAscii(
switch (format) {
case time_eFormat_FileDateAndTime:
case time_eFormat_FileDate:
case time_eFormat_TimeAndDate:
break;
default:
sprintf(tmpStr, ".%02d", (int)(tp->tv_nsec / 10000000));
......@@ -893,12 +919,18 @@ pwr_tStatus time_AsciiToD(const char* tstr, pwr_tDeltaTime* ts)
char buf[64];
int day, hour = 0, min, sec, hun = 0;
int useday = 1;
int neg = 0;
if ( streq( tstr, "NotADeltaTime")) {
*ts = pwr_cNotADeltaTime;
return TIME__SUCCESS;
}
strncpy(buf, tstr, sizeof(buf) - 1);
if (*tstr == '-') {
strncpy(buf, &tstr[1], sizeof(buf) - 1);
neg = 1;
}
else
strncpy(buf, tstr, sizeof(buf) - 1);
buf[sizeof(buf) - 1] = '\0';
sp = buf;
......@@ -942,6 +974,10 @@ pwr_tStatus time_AsciiToD(const char* tstr, pwr_tDeltaTime* ts)
ts->tv_sec = day * 24 * 3600 + hour * 3600 + min * 60 + sec;
ts->tv_nsec = hun * 10000000;
if (neg) {
ts->tv_sec = -ts->tv_sec;
ts->tv_nsec = -ts->tv_nsec;
}
return TIME__SUCCESS;
}
......@@ -1309,6 +1345,7 @@ pwr_tFloat64 time_DToFloat64(pwr_tFloat64* f, pwr_tDeltaTime* dt)
return *fp;
}
//! Convert delta time to clock time.
time_tClock time_DtoClock(pwr_tStatus* status, pwr_tDeltaTime* tp)
{
pwr_dStatus(sts, status, TIME__SUCCESS);
......@@ -1316,6 +1353,7 @@ time_tClock time_DtoClock(pwr_tStatus* status, pwr_tDeltaTime* tp)
return tp->tv_sec * 100 + tp->tv_nsec / 10000000;
}
//! Convert clock time to delta time.
pwr_tDeltaTime* time_ClockToD(
pwr_tStatus* status, pwr_tDeltaTime* tp, time_tClock clock)
{
......@@ -1331,6 +1369,7 @@ pwr_tDeltaTime* time_ClockToD(
return tp;
}
//! Zero a delta time.
pwr_tDeltaTime* time_ZeroD(pwr_tDeltaTime* tp)
{
static pwr_tDeltaTime time;
......@@ -1354,6 +1393,7 @@ void time_Sleep(float time)
nanosleep(&ts, NULL);
}
//! Get current time.
int time_GetTime(pwr_tTime* ts)
{
struct timespec t;
......@@ -1366,6 +1406,7 @@ int time_GetTime(pwr_tTime* ts)
return sts;
}
//! Get current monotonic time.
int time_GetTimeMonotonic(pwr_tTime* ts)
{
struct timespec t;
......@@ -1468,7 +1509,7 @@ int time_PeriodMonth(
return 1;
}
//! Calculate start and end time for month.
//! Calculate start and end time for year.
static int time_PeriodYear(
pwr_tTime* time, pwr_tTime* from, pwr_tTime* to, int previous)
{
......@@ -1578,6 +1619,7 @@ int time_PeriodPreviousWeek(pwr_tTime* time, pwr_tTime* from, pwr_tTime* to)
return 1;
}
//! Calculate previous daybreak.
void time_PreviousDayBreak(pwr_tTime* time, pwr_tTime* daybreak)
{
struct tm* tm;
......
......@@ -322,6 +322,65 @@ pwr_tBoolean dvol_DeleteObject(pwr_tStatus* sts, pwr_tObjid oid)
pwr_Return(TRUE, sts, GDH__SUCCESS);
}
/* Delete a local object tree.
Object header and the associated body are removed.
This call is possible only if the object is
in a local volume, i.e a volume owned by the local node.
The volume must be of class $DynamicVolume or $SystemVolume.
The object must not be parent to any other object.
All reachable nodes, who have mounted the volume in question,
are notified about the removal of this object. */
static pwr_tBoolean delete_children(pwr_tStatus *sts, gdb_sObject *op)
{
while (op->g.flags.b.isParent) {
if (!dvol_DeleteObjectTree(sts, op->g.soid))
return FALSE;
}
pwr_Return(TRUE, sts, GDH__SUCCESS);
}
pwr_tBoolean dvol_DeleteObjectTree(pwr_tStatus* sts, pwr_tObjid oid)
{
static cvol_sNotify dm; /* Cannot be on the stack for VAXELN */
gdb_sObject* op;
gdb_sObject* p_op;
gdb_sVolume* vp;
gdb_AssumeLocked;
if (oid.oix == pwr_cNObjectIx)
pwr_Return(FALSE, sts, GDH__VOLDELETE);
op = vol_OidToObject(
sts, oid, gdb_mLo_dynamic, vol_mTrans_none, cvol_eHint_none);
if (op == NULL)
return FALSE;
if (op->g.flags.b.isParent && cdh_ObjidIsNotNull(op->g.soid)) {
if (!delete_children(sts, op))
return FALSE;
}
p_op = pool_Address(NULL, gdbroot->pool, op->l.por);
vp = pool_Address(NULL, gdbroot->pool, op->l.vr);
cvols_InitNotify(op, &dm, net_eMsg_deleteObject);
unadoptObject(sts, op, p_op, &dm);
vol_UnlinkObject(sts, vp, op, vol_mLink_delete);
cvols_Notify(&dm);
pwr_Return(TRUE, sts, GDH__SUCCESS);
}
/* Move a local object.
This call is possible only if the object is
......@@ -385,11 +444,12 @@ gdb_sObject* dvol_MoveObject(pwr_tStatus* sts, pwr_tObjid oid, pwr_tObjid poid)
if (tmp_op != NULL)
pwr_Return(NULL, sts, GDH__DUPLNAME);
cvols_InitNotify(op, &mm, net_eMsg_deleteObject);
cvols_InitNotify(op, &mm, net_eMsg_moveObject);
unadoptObject(NULL, op, old_pop, &mm);
op->g.f.poid = poid;
op->l.por = pool_ItemReference(NULL, gdbroot->pool, new_pop);
adoptObject(NULL, op, new_pop, &mm);
......
......@@ -50,6 +50,8 @@ gdb_sObject* dvol_CreateObject(pwr_tStatus* sts, cdh_sParseName* pn,
pwr_tBoolean dvol_DeleteObject(pwr_tStatus* sts, pwr_tObjid oid);
pwr_tBoolean dvol_DeleteObjectTree(pwr_tStatus* sts, pwr_tObjid oid);
gdb_sObject* dvol_MoveObject(pwr_tStatus* sts, pwr_tObjid oid, pwr_tObjid poid);
gdb_sObject* dvol_RenameObject(
......
......@@ -333,7 +333,7 @@ pwr_tStatus gdh_ClassAttrToAttrref(
if (name != NULL && *name != '\0') {
pn = cdh_ParseName(&sts, &ParseName, pwr_cNObjid, name, 0);
if (pn == NULL) {
if (pn == NULL || pn->nAttribute == 0) {
strcat(buff, name);
pn = cdh_ParseName(&sts, &ParseName, pwr_cNObjid, buff, 0);
}
......@@ -449,7 +449,7 @@ pwr_tStatus gdh_ClassNameToId(const char* name, /**< Class name string. */
*/
pwr_tStatus gdh_CreateObject(
char* name, /**< Object name string. Last segment only.*/
char* name, /**< Object name string with path.*/
pwr_tClassId cid, /**< Class id for object. */
unsigned int size, /**< Size of object body. Only needed for objects
with dynamic size, else 0. */
......@@ -524,6 +524,41 @@ pwr_tStatus gdh_DeleteObject(
return sts;
}
/**
* @brief Remove a local object tree.
*
* Object header and the associated body are removed.
* This call is possible only if the object is
* in a local volume, i.e a volume owned by the local node.
* The volume must be of class $DynamicVolume or $SystemVolume.
* The object must not be parent to any other object.
*
* All reachable nodes, who have mounted the volume in question,
* are notified about the removal of this object.
*
* The objects is not completly removed until all directlink and
* subscriptions to the object are removed.
* @return pwr_tStatus
*/
pwr_tStatus gdh_DeleteObjectTree(
pwr_tObjid oid /**< The identity of the root object of the tree. */
)
{
pwr_tStatus sts = GDH__SUCCESS;
if (cdh_ObjidIsNull(oid))
return GDH__NOSUCHOBJ;
gdh_ScopeLock
{
dvol_DeleteObjectTree(&sts, oid);
}
gdh_ScopeUnlock;
return sts;
}
/**
* @brief Request a direct link to the data denoted by an attribute reference.
*
......@@ -1014,7 +1049,7 @@ pwr_tStatus gdh_GetObjectSize(pwr_tObjid oid, /**< The object identity. */
*/
pwr_tStatus gdh_GetDynamicAttrSize(pwr_tObjid oid, /**< The object identity. */
char* name, /**< Attribute name. */
char* name, /**< Attribute name with leading point, eg ".Length". */
pwr_tUInt32* size /**< Receives the size in bytes of the object. */
)
{
......@@ -2122,7 +2157,7 @@ pwr_tStatus gdh_MDAttribute(
*/
pwr_tStatus gdh_MoveObject(
pwr_tObjid oid, /**< The object that should be moved. */
pwr_tObjid poid /**< The object that should become the newe parent. */
pwr_tObjid poid /**< The object that should become the new parent. */
)
{
pwr_tStatus sts = GDH__SUCCESS;
......@@ -2280,9 +2315,9 @@ pwr_tStatus gdh_NameToAttrref(
const char*
name, /**< The argument is added to the parent to form the
complete item name. If the parent argument is supplied as
pwr_cNobjid, this argument is considered to decsribe the
pwr_cNobjid, this argument is considered to describe the
full name. */
pwr_sAttrRef* arp /**< The resulting attribute reference decsriptor. */
pwr_sAttrRef* arp /**< The resulting attribute reference descriptor. */
)
{
pwr_tStatus sts = GDH__SUCCESS;
......@@ -4335,6 +4370,7 @@ pwr_tStatus gdh_FWriteObjectR(
case pwr_eType_ClassId:
case pwr_eType_TypeId:
case pwr_eType_CastId:
case pwr_eType_Time:
fprintf(fp, "%s \"%s\"\n", &name[1], value_str);
break;
default:
......@@ -4479,6 +4515,7 @@ pwr_tStatus gdh_FReadObject(char* filename, /**< File specification */
case pwr_eType_ClassId:
case pwr_eType_TypeId:
case pwr_eType_CastId:
case pwr_eType_Time:
if (line_elem[1][0] == '"'
&& line_elem[1][strlen(line_elem[1]) - 1] == '"') {
line_elem[1][strlen(line_elem[1]) - 1] = 0;
......
......@@ -195,6 +195,8 @@ pwr_tStatus gdh_CreateObject(char* objectName, pwr_tClassId classid,
pwr_tStatus gdh_DeleteObject(pwr_tObjid objectId);
pwr_tStatus gdh_DeleteObjectTree(pwr_tObjid objectId);
pwr_tStatus gdh_DLRefObjectInfoAttrref(
pwr_sAttrRef* addressOfAttributeReference, void** objectData,
pwr_tDlid* directLinkId);
......@@ -388,6 +390,20 @@ void* gdh_TranslateRtdbPointer(unsigned long rtdbReference);
pwr_tStatus gdh_GetObjectBodyDef(
pwr_tCid cid, gdh_sAttrDef** bodydef, int* rows, pwr_tOid oid);
/* Thread safe functions for times and strings */
void gdh_GetTimeDL(pwr_tTime* atp, pwr_tTime* time);
void gdh_SetTimeDL(pwr_tTime* atp, pwr_tTime* time);
void gdh_GetDeltaTimeDL(pwr_tDeltaTime* dtp, pwr_tDeltaTime* time);
void gdh_SetDeltaTimeDL(pwr_tDeltaTime* dtp, pwr_tDeltaTime* time);
void gdh_GetStrDL(char* sp, char* str, int size);
void gdh_SetStrDL(char* sp, const char* str, int size);
pwr_tStatus gdh_GetObjectInfoTime(const char* name, pwr_tTime* time);
pwr_tStatus gdh_SetObjectInfoTime(const char* name, pwr_tTime* time);
pwr_tStatus gdh_GetObjectInfoDeltaTime(const char* name, pwr_tDeltaTime* time);
pwr_tStatus gdh_SetObjectInfoDeltaTime(const char* name, pwr_tDeltaTime* time);
pwr_tStatus gdh_GetObjectInfoStr(const char* name, char* str, int size);
pwr_tStatus gdh_SetObjectInfoStr(const char* name, const char* str, int size);
/** @} */
void gdh_InitialLoadDone(pwr_tObjid systemobject, pwr_tObjid nodeobject);
......@@ -438,19 +454,6 @@ pwr_tStatus gdh_CheckLocalObject(pwr_tOid oid);
pwr_tStatus gdh_TidToType(pwr_tTid tid, pwr_eType *type);
pwr_tStatus gdh_MountDynClients(void);
/* Thread safe functions for times and strings */
void gdh_GetTimeDL(pwr_tTime* atp, pwr_tTime* time);
void gdh_SetTimeDL(pwr_tTime* atp, pwr_tTime* time);
void gdh_GetDeltaTimeDL(pwr_tDeltaTime* dtp, pwr_tDeltaTime* time);
void gdh_SetDeltaTimeDL(pwr_tDeltaTime* dtp, pwr_tDeltaTime* time);
void gdh_GetStrDL(char* sp, char* str, int size);
void gdh_SetStrDL(char* sp, const char* str, int size);
pwr_tStatus gdh_GetObjectInfoTime(const char* name, pwr_tTime* time);
pwr_tStatus gdh_SetObjectInfoTime(const char* name, pwr_tTime* time);
pwr_tStatus gdh_GetObjectInfoDeltaTime(const char* name, pwr_tDeltaTime* time);
pwr_tStatus gdh_SetObjectInfoDeltaTime(const char* name, pwr_tDeltaTime* time);
pwr_tStatus gdh_GetObjectInfoStr(const char* name, char* str, int size);
pwr_tStatus gdh_SetObjectInfoStr(const char* name, const char* str, int size);
/** @} */
......
......@@ -801,7 +801,8 @@ gdb_sClass* mvol_NameToClass(pwr_tStatus* sts, const char* name)
}
static void insertCattObject(
pwr_tStatus* sts, pwr_tCid cid, gdb_sAttribute* ap, int offset)
pwr_tStatus* sts, pwr_tCid cid, gdb_sAttribute* ap, int offset,
gdb_sAttribute* pap)
{
gdb_sClassAttrKey key;
gdb_sClassAttr* item;
......@@ -827,6 +828,9 @@ static void insertCattObject(
/* Insert in found item */
item->offset[item->numOffset] = offset + ap->offs;
item->flags[item->numOffset++] = ap->flags;
if (ap->flags.b.superclass && pap)
/* Inherit disable flag */
ap->flags.b.disableattr = pap->flags.b.disableattr;
} else {
/* Insert a new item */
pool_tRef itemr;
......@@ -843,7 +847,7 @@ static void insertCattObject(
for (i = 0; i < cp->acount; i++) {
if (cp->attr[i].flags.b.isclass && cdh_tidIsCid(cp->attr[i].tid)
&& !cp->attr[i].flags.b.pointer) {
insertCattObject(sts, cid, &cp->attr[i], offset + ap->offs);
insertCattObject(sts, cid, &cp->attr[i], offset + ap->offs, ap);
if (EVEN(*sts))
return;
}
......@@ -876,7 +880,7 @@ static void insertCattObject(
if (cp->attr[i].flags.b.isclass && cdh_tidIsCid(cp->attr[i].tid)
&& !cp->attr[i].flags.b.pointer) {
insertCattObject(sts, cid, &cp->attr[i],
offset + ap->offs + j * (ap->size / ap->elem));
offset + ap->offs + j * (ap->size / ap->elem), 0);
if (EVEN(*sts))
return;
}
......@@ -904,7 +908,7 @@ void mvol_BuildCatt(pwr_tStatus* sts)
for (i = 0; i < cp->acount; i++) {
if (cp->attr[i].flags.b.isclass && cdh_tidIsCid(cp->attr[i].tid)
&& !cp->attr[i].flags.b.pointer) {
insertCattObject(sts, cid, &cp->attr[i], 0);
insertCattObject(sts, cid, &cp->attr[i], 0, 0);
if (EVEN(*sts))
return;
}
......
......@@ -70,3 +70,4 @@ invtypename <invalid type name> /error
invattrname <invalid attribute name> /error
invbid <invalid body identifier> /error
invattrindex <invalid attribute index> /error
invoid <invalid object identity format> /error
......@@ -907,6 +907,8 @@ sub create_all_modules()
create_module();
_module("opc");
create_module();
_module("test");
create_module();
_module("ssabox");
create_module();
_module("othermanu");
......
ifndef link_rule_mk
link_rule_mk := 1
link = $(ldxx) $(elinkflags) $(domap) -o $(pwr_exe)/test_xtt_gtk \
$(bld_dir)/test_xtt_gtk.o \
$(bld_dir)/xtt_log_gtk.o $(bld_dir)/xtt_lognav_gtk.o $(bld_dir)/xtt_log.o \
$(bld_dir)/xtt_lognav.o $(bld_dir)/xtt_lognav_command.o \
$(rt_msg_eobjs) \
$(pwr_eobj)/rt_io_user.o \
$(pwre_conf_libdir) $(pwre_conf_libpwrxttgtk) $(pwre_conf_libpwrxtt) $(pwre_conf_libgtk) $(pwre_conf_libpwrxttgtk) $(pwre_conf_libpwrxtt) \
$(pwre_conf_libpwrrt) $(pwre_conf_lib)
endif
/*
* ProviewR Open Source Process Control.
* Copyright (C) 2005-2020 SSAB EMEA AB.
*
* This file is part of ProviewR.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProviewR. If not, see <http://www.gnu.org/licenses/>
*
* Linking ProviewR statically or dynamically with other modules is
* making a combined work based on ProviewR. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
*
* In addition, as a special exception, the copyright holders of
* ProviewR give you permission to, from the build function in the
* ProviewR Configurator, combine ProviewR with modules generated by the
* ProviewR PLC Editor to a PLC program, regardless of the license
* terms of these modules. You may copy and distribute the resulting
* combined work under the terms of your choice, provided that every
* copy of the combined work is accompanied by a complete copy of
* the source code of ProviewR (the version used to produce the
* combined work), being distributed under the terms of the GNU
* General Public License plus this exception.
*/
#include <locale.h>
#include <gtk/gtk.h>
#include <fstream>
#include "co_error.h"
#include "co_string.h"
#include "co_dcli.h"
#include "co_time.h"
#include "rt_errh.h"
#include "xtt_log_gtk.h"
void log_close_cb(void* log)
{
XttLogGtk* xttlog = (XttLogGtk*)log;
delete xttlog;
exit(0);
}
void set_severity(LogNav_hier *hier)
{
for (int i = 0; i < hier->child.size(); i++) {
if (hier->child[i].type == lognav_eItemType_Hier)
set_severity(&hier->child[i]);
if (hier->child[i].severity > hier->severity)
hier->severity = hier->child[i].severity;
}
}
LogNav_hier *get_hier(LogNav_hier *parent, char *hier)
{
char *s;
char h1[100], h2[100];
int last = 0;
strncpy(h1, hier, sizeof(h1));
if ((s = strchr(h1, '-'))) {
*s = 0;
strncpy(h2, s+1, sizeof(h2));
}
else
last = 1;
for (int i = 0; i < parent->child.size(); i++) {
if (str_NoCaseStrcmp(h1, parent->child[i].text) == 0) {
if (last)
return &parent->child[i];
else
return get_hier(&parent->child[i], h2);
}
}
// Not found, create
LogNav_hier item;
strcpy(item.text, h1);
item.severity = lognav_eSeverity_No;
item.type = lognav_eItemType_Hier;
parent->child.push_back(item);
if (last)
return &parent->child[parent->child.size()-1];
return get_hier(&parent->child[parent->child.size()-1], h2);
}
void file_read(pwr_tStatus *sts, LogNav_hier *tree, char *filename)
{
FILE *fp;
char line[200];
lognav_eSeverity severity;
char timstr[40];
char hier[150];
std::vector<LogNav_hier> store;
fp = fopen(filename, "r");
if (!fp) {
*sts = 0;
return;
}
while (dcli_read_line(line, sizeof(line), fp)) {
switch (line[0]) {
case 'S':
if (line[1] != ' ')
continue;
severity = lognav_eSeverity_Success;
break;
case 'I':
if (line[1] != ' ')
continue;
severity = lognav_eSeverity_Info;
break;
case 'W':
if (line[1] != ' ')
continue;
severity = lognav_eSeverity_Warning;
break;
case 'E':
if (line[1] != ' ')
continue;
severity = lognav_eSeverity_Error;
break;
case 'F':
if (line[1] != ' ')
continue;
severity = lognav_eSeverity_Fatal;
break;
case 'D':
if (line[1] != ' ')
continue;
severity = lognav_eSeverity_Detail;
break;
case 'X':
if (line[1] != ' ')
continue;
severity = lognav_eSeverity_DetailError;
break;
case 'Z':
if (line[1] != ' ')
continue;
severity = lognav_eSeverity_DetailWarning;
break;
default:
continue;
}
LogNav_hier item;
item.severity = severity;
char *s = strchr(&line[26], ',');
if (!s)
continue;
*s = 0;
strncpy(hier, &line[26], sizeof(hier));
strncpy(item.text, s+2, sizeof(item.text));
item.text[sizeof(item.text)-1] = 0;
item.type = lognav_eItemType_Entry;
strncpy(timstr, &line[2], 23);
timstr[23] = 0;
time_AsciiToA(timstr, &item.time);
if (severity == lognav_eSeverity_Detail ||
severity == lognav_eSeverity_DetailError ||
severity == lognav_eSeverity_DetailWarning) {
// Store and insert as child to next 'real' item
store.push_back(item);
continue;
}
LogNav_hier *h = get_hier(tree, hier);
if (severity > h->severity)
h->severity = severity;
h->child.push_back(item);
if (store.size() != 0) {
for (int i = 0; i < store.size(); i++) {
h->child[h->child.size()-1].child.push_back(store[i]);
}
store.clear();
}
}
set_severity(tree);
}
void log_read(pwr_tStatus *status, LogNav_hier *tree, char *filename)
{
pwr_tFileName found_file;
pwr_tStatus sts;
sts = dcli_search_file(filename, found_file, DCLI_DIR_SEARCH_INIT);
while (ODD(sts)) {
file_read(&sts, tree, found_file);
sts = dcli_search_file(filename, found_file, DCLI_DIR_SEARCH_NEXT);
}
dcli_search_file(filename, found_file, DCLI_DIR_SEARCH_END);
}
int main(int argc, char* argv[])
{
pwr_tStatus sts;
pwr_tFileName filename;
LogNav_hier *tree = 0;
// Get options
for (int i = 1; i < argc; i++) {
if (streq(argv[i], "-f") && i + 1 < argc) {
strncpy(filename, argv[i + 1], sizeof(filename));
i++;
}
}
// Read logfiles
tree = new LogNav_hier();
log_read(&sts, tree, filename);
gtk_init(&argc, &argv);
setlocale(LC_NUMERIC, "POSIX");
setlocale(LC_TIME, "en_US");
XttLogGtk* log = new XttLogGtk(0, 0, tree);
log->close_cb = log_close_cb;
gtk_main();
return 1;
}
/*
* ProviewR Open Source Process Control.
* Copyright (C) 2005-2020 SSAB EMEA AB.
*
* This file is part of ProviewR.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProviewR. If not, see <http://www.gnu.org/licenses/>
*
* Linking ProviewR statically or dynamically with other modules is
* making a combined work based on ProviewR. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
*
* In addition, as a special exception, the copyright holders of
* ProviewR give you permission to, from the build function in the
* ProviewR Configurator, combine ProviewR with modules generated by the
* ProviewR PLC Editor to a PLC program, regardless of the license
* terms of these modules. You may copy and distribute the resulting
* combined work under the terms of your choice, provided that every
* copy of the combined work is accompanied by a complete copy of
* the source code of ProviewR (the version used to produce the
* combined work), being distributed under the terms of the GNU
* General Public License plus this exception.
*/
/* xtt_log_gtk.cpp -- Test log viewer */
#include "co_cdh.h"
#include "co_dcli.h"
#include "co_string.h"
#include "cow_xhelp_gtk.h"
#include "flow_browwidget_gtk.h"
#include "flow_msg.h"
#include "xtt_log_gtk.h"
void XttLogGtk::message(char severity, char* message)
{
gtk_label_set_text(GTK_LABEL(msg_label), message);
}
static gint delete_event(GtkWidget* w, GdkEvent* event, gpointer data)
{
XttLogGtk* xttlog = (XttLogGtk*)data;
if (xttlog->close_cb)
(xttlog->close_cb)(xttlog);
else
delete xttlog;
return FALSE;
}
static void destroy_event(GtkWidget* w, gpointer data)
{
// XttLogGtk *xttlog = (XttLogGtk *)data;
// delete xttlog;
}
static gboolean xttlog_focus_in_event(
GtkWidget* w, GdkEvent* event, gpointer data)
{
XttLogGtk* xttlog = (XttLogGtk*)data;
if (xttlog->lognav)
xttlog->lognav->set_inputfocus();
return FALSE;
}
void XttLogGtk::activate_print(GtkWidget* w, gpointer data)
{
XttLog* xtt = (XttLog*)data;
xtt->activate_print();
}
void XttLogGtk::activate_close(GtkWidget* w, gpointer data)
{
XttLog* xttlog = (XttLog*)data;
if (xttlog->close_cb)
(xttlog->close_cb)(xttlog);
else
delete xttlog;
}
void XttLogGtk::activate_zoom_in(GtkWidget* w, gpointer data)
{
XttLog* xtt = (XttLog*)data;
xtt->activate_zoom_in();
}
void XttLogGtk::activate_zoom_out(GtkWidget* w, gpointer data)
{
XttLog* xtt = (XttLog*)data;
xtt->activate_zoom_out();
}
void XttLogGtk::activate_zoom_reset(GtkWidget* w, gpointer data)
{
XttLog* xtt = (XttLog*)data;
xtt->activate_zoom_reset();
}
void XttLogGtk::activate_help(GtkWidget* w, gpointer data)
{
XttLog* xtt = (XttLog*)data;
if (!xtt->is_authorized())
return;
xtt->activate_help();
}
void XttLogGtk::activate_help_proview(GtkWidget* w, gpointer data)
{
XttLog* xtt = (XttLog*)data;
if (!xtt->is_authorized())
return;
xtt->activate_help_proview();
}
void XttLogGtk::activate_command(GtkWidget* w, gpointer data)
{
XttLog* xtt = (XttLog*)data;
if (!xtt->is_authorized())
return;
if (xtt->command_open) {
g_object_set(((XttLogGtk*)xtt)->cmd_input, "visible", FALSE, NULL);
xtt->set_prompt("");
xtt->command_open = 0;
return;
}
gtk_editable_delete_text(GTK_EDITABLE(((XttLogGtk*)xtt)->cmd_input), 0, -1);
g_object_set(((XttLogGtk*)xtt)->cmd_input, "visible", TRUE, NULL);
xtt->message(' ', "");
gtk_widget_grab_focus(((XttLogGtk*)xtt)->cmd_input);
xtt->set_prompt("xtt >");
xtt->command_open = 1;
}
void XttLogGtk::set_prompt(const char* prompt)
{
if (streq(prompt, "")) {
g_object_set(cmd_prompt, "visible", FALSE, NULL);
g_object_set(msg_label, "visible", TRUE, NULL);
} else {
char* promptutf8
= g_convert(prompt, -1, "UTF-8", "ISO8859-1", NULL, NULL, NULL);
g_object_set(msg_label, "visible", FALSE, NULL);
g_object_set(cmd_prompt, "visible", TRUE, "label", promptutf8, NULL);
g_free(promptutf8);
}
}
void XttLogGtk::valchanged_cmd_input(GtkWidget* w, gpointer data)
{
XttLog* xtt = (XttLog*)data;
int sts;
char *text, *textutf8;
textutf8 = gtk_editable_get_chars(GTK_EDITABLE(w), 0, -1);
text = g_convert(textutf8, -1, "ISO8859-1", "UTF-8", NULL, NULL, NULL);
g_free(textutf8);
sts = xtt->command(text);
g_object_set(w, "visible", FALSE, NULL);
xtt->set_prompt("");
xtt->command_open = 0;
xtt->lognav->set_inputfocus();
}
XttLogGtk::XttLogGtk(GtkWidget* a_parent_wid, void* a_parent_ctx,
LogNav_hier *a_tree)
: XttLog(a_parent_ctx, a_tree), parent_wid(a_parent_wid)
{
int sts;
pwr_tFileName fname;
toplevel = (GtkWidget*)g_object_new(GTK_TYPE_WINDOW, "default-height", 700,
"default-width", 500, "title", "Testlog Viewer", NULL);
g_signal_connect(toplevel, "delete_event", G_CALLBACK(delete_event), this);
g_signal_connect(toplevel, "destroy", G_CALLBACK(destroy_event), this);
g_signal_connect(
toplevel, "focus-in-event", G_CALLBACK(xttlog_focus_in_event), this);
CoWowGtk::SetWindowIcon(toplevel);
GtkWidget* vbox = gtk_vbox_new(FALSE, 0);
// Menu
// Accelerators
GtkAccelGroup* accel_g
= (GtkAccelGroup*)g_object_new(GTK_TYPE_ACCEL_GROUP, NULL);
gtk_window_add_accel_group(GTK_WINDOW(toplevel), accel_g);
GtkMenuBar* menu_bar = (GtkMenuBar*)g_object_new(GTK_TYPE_MENU_BAR, NULL);
// File entry
GtkWidget* file_print = gtk_image_menu_item_new_with_mnemonic(
CoWowGtk::translate_utf8("_Print"));
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(file_print),
gtk_image_new_from_stock("gtk-print", GTK_ICON_SIZE_MENU));
g_signal_connect(file_print, "activate", G_CALLBACK(activate_print), this);
GtkWidget* file_close
= gtk_image_menu_item_new_from_stock(GTK_STOCK_CLOSE, accel_g);
g_signal_connect(file_close, "activate", G_CALLBACK(activate_close), this);
GtkMenu* file_menu = (GtkMenu*)g_object_new(GTK_TYPE_MENU, NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), file_print);
gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), file_close);
GtkWidget* file = gtk_menu_item_new_with_mnemonic("_File");
gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), file);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), GTK_WIDGET(file_menu));
// Functions entry
GtkWidget* functions_command
= gtk_menu_item_new_with_mnemonic(CoWowGtk::translate_utf8("Co_mmand"));
g_signal_connect(
functions_command, "activate", G_CALLBACK(activate_command), this);
gtk_widget_add_accelerator(functions_command, "activate", accel_g, 'b',
GdkModifierType(GDK_CONTROL_MASK), GTK_ACCEL_VISIBLE);
GtkMenu* functions_menu = (GtkMenu*)g_object_new(GTK_TYPE_MENU, NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(functions_menu), functions_command);
GtkWidget* functions
= gtk_menu_item_new_with_mnemonic(CoWowGtk::translate_utf8("_Functions"));
gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), functions);
gtk_menu_item_set_submenu(
GTK_MENU_ITEM(functions), GTK_WIDGET(functions_menu));
// View menu
GtkWidget* view_zoom_in = gtk_image_menu_item_new_with_mnemonic(
CoWowGtk::translate_utf8("Zoom _In"));
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(view_zoom_in),
gtk_image_new_from_stock("gtk-zoom-in", GTK_ICON_SIZE_MENU));
g_signal_connect(
view_zoom_in, "activate", G_CALLBACK(activate_zoom_in), this);
gtk_widget_add_accelerator(view_zoom_in, "activate", accel_g, 'i',
GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
GtkWidget* view_zoom_out = gtk_image_menu_item_new_with_mnemonic(
CoWowGtk::translate_utf8("Zoom _Out"));
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(view_zoom_out),
gtk_image_new_from_stock("gtk-zoom-out", GTK_ICON_SIZE_MENU));
g_signal_connect(
view_zoom_out, "activate", G_CALLBACK(activate_zoom_out), this);
gtk_widget_add_accelerator(view_zoom_out, "activate", accel_g, 'o',
GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
GtkWidget* view_zoom_reset = gtk_image_menu_item_new_with_mnemonic(
CoWowGtk::translate_utf8("Zoom _Reset"));
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(view_zoom_reset),
gtk_image_new_from_stock("gtk-zoom-100", GTK_ICON_SIZE_MENU));
g_signal_connect(
view_zoom_reset, "activate", G_CALLBACK(activate_zoom_reset), this);
GtkMenu* view_menu = (GtkMenu*)g_object_new(GTK_TYPE_MENU, NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), view_zoom_in);
gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), view_zoom_out);
gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), view_zoom_reset);
GtkWidget* view
= gtk_menu_item_new_with_mnemonic(CoWowGtk::translate_utf8("_View"));
gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), view);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(view), GTK_WIDGET(view_menu));
// Help entry
GtkWidget* help_overview = gtk_image_menu_item_new_with_mnemonic(
CoWowGtk::translate_utf8("_Overview"));
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(help_overview),
gtk_image_new_from_stock("gtk-help", GTK_ICON_SIZE_MENU));
g_signal_connect(help_overview, "activate", G_CALLBACK(activate_help), this);
gtk_widget_add_accelerator(help_overview, "activate", accel_g, 'h',
GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
GtkWidget* help_proview = gtk_menu_item_new_with_mnemonic(
CoWowGtk::translate_utf8("_About Proview"));
g_signal_connect(
help_proview, "activate", G_CALLBACK(activate_help_proview), this);
GtkMenu* help_menu = (GtkMenu*)g_object_new(GTK_TYPE_MENU, NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(help_menu), help_overview);
gtk_menu_shell_append(GTK_MENU_SHELL(help_menu), help_proview);
GtkWidget* help
= gtk_menu_item_new_with_mnemonic(CoWowGtk::translate_utf8("_Help"));
gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), help);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(help), GTK_WIDGET(help_menu));
// Toolbar
GtkToolbar* tools = (GtkToolbar*)g_object_new(GTK_TYPE_TOOLBAR, NULL);
GtkWidget* tools_zoom_in = gtk_button_new();
dcli_translate_filename(fname, "$pwr_exe/xtt_zoom_in.png");
gtk_container_add(
GTK_CONTAINER(tools_zoom_in), gtk_image_new_from_file(fname));
g_signal_connect(
tools_zoom_in, "clicked", G_CALLBACK(activate_zoom_in), this);
g_object_set(tools_zoom_in, "can-focus", FALSE, NULL);
gtk_toolbar_append_widget(
tools, tools_zoom_in, CoWowGtk::translate_utf8("Zoom in"), "");
GtkWidget* tools_zoom_out = gtk_button_new();
dcli_translate_filename(fname, "$pwr_exe/xtt_zoom_out.png");
gtk_container_add(
GTK_CONTAINER(tools_zoom_out), gtk_image_new_from_file(fname));
g_signal_connect(
tools_zoom_out, "clicked", G_CALLBACK(activate_zoom_out), this);
g_object_set(tools_zoom_out, "can-focus", FALSE, NULL);
gtk_toolbar_append_widget(
tools, tools_zoom_out, CoWowGtk::translate_utf8("Zoom out"), "");
GtkWidget* tools_zoom_reset = gtk_button_new();
dcli_translate_filename(fname, "$pwr_exe/xtt_zoom_reset.png");
gtk_container_add(
GTK_CONTAINER(tools_zoom_reset), gtk_image_new_from_file(fname));
g_signal_connect(
tools_zoom_reset, "clicked", G_CALLBACK(activate_zoom_reset), this);
g_object_set(tools_zoom_reset, "can-focus", FALSE, NULL);
gtk_toolbar_append_widget(
tools, tools_zoom_reset, CoWowGtk::translate_utf8("Zoom reset"), "");
// Statusbar and cmd input
GtkWidget* statusbar = gtk_hbox_new(FALSE, 0);
msg_label = gtk_label_new("");
gtk_widget_set_size_request(msg_label, -1, 25);
cmd_prompt = gtk_label_new("xtt > ");
gtk_widget_set_size_request(cmd_prompt, -1, 25);
cmd_recall = new CoWowRecall();
cmd_entry = new CoWowEntryGtk(cmd_recall);
cmd_input = cmd_entry->widget();
gtk_widget_set_size_request(cmd_input, -1, 25);
g_signal_connect(
cmd_input, "activate", G_CALLBACK(valchanged_cmd_input), this);
gtk_box_pack_start(GTK_BOX(statusbar), msg_label, FALSE, FALSE, 20);
gtk_box_pack_start(GTK_BOX(statusbar), cmd_prompt, FALSE, FALSE, 20);
gtk_box_pack_start(GTK_BOX(statusbar), cmd_input, TRUE, TRUE, 20);
gtk_widget_show_all(statusbar);
lognav
= new LogNavGtk(this, toplevel, tree, &brow_widget, &sts);
lognav->message_cb = &XttLog::message;
lognav->command_cb = &XttLog::command_cb;
gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(menu_bar), FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(tools), FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(brow_widget), TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(statusbar), FALSE, FALSE, 3);
gtk_container_add(GTK_CONTAINER(toplevel), vbox);
gtk_widget_show_all(toplevel);
g_object_set(cmd_prompt, "visible", FALSE, NULL);
g_object_set(cmd_input, "visible", FALSE, NULL);
// Create help window
CoXHelp* xhelp = new CoXHelpGtk(toplevel, this, xhelp_eUtility_Xtt, &sts);
CoXHelp::set_default(xhelp);
wow = new CoWowGtk(toplevel);
}
XttLogGtk::~XttLogGtk()
{
delete (LogNavGtk*)lognav;
gtk_widget_destroy(toplevel);
}
/*
* ProviewR Open Source Process Control.
* Copyright (C) 2005-2020 SSAB EMEA AB.
*
* This file is part of ProviewR.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProviewR. If not, see <http://www.gnu.org/licenses/>
*
* Linking ProviewR statically or dynamically with other modules is
* making a combined work based on ProviewR. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
*
* In addition, as a special exception, the copyright holders of
* ProviewR give you permission to, from the build function in the
* ProviewR Configurator, combine ProviewR with modules generated by the
* ProviewR PLC Editor to a PLC program, regardless of the license
* terms of these modules. You may copy and distribute the resulting
* combined work under the terms of your choice, provided that every
* copy of the combined work is accompanied by a complete copy of
* the source code of ProviewR (the version used to produce the
* combined work), being distributed under the terms of the GNU
* General Public License plus this exception.
*/
#ifndef xtt_log_gtk_h
#define xtt_log_gtk_h
#include "../src/xtt_log.h"
#include "xtt_lognav_gtk.h"
#include "cow_wow_gtk.h"
/* ge_log.h -- Ge logibute editor */
class CoWowRecall;
class CoWowEntryGtk;
class XttLogGtk : public XttLog {
public:
XttLogGtk(GtkWidget* a_parent_wid, void* a_parent_ctx, LogNav_hier *a_tree);
GtkWidget* parent_wid;
GtkWidget* brow_widget;
GtkWidget* form_widget;
GtkWidget* toplevel;
GtkWidget* msg_label;
GtkWidget* cmd_prompt;
GtkWidget* cmd_input;
GtkWidget* pane;
CoWowRecall* cmd_recall;
CoWowEntryGtk* cmd_entry;
void message(char severity, char* message);
void set_prompt(const char* prompt);
static void activate_command(GtkWidget* w, gpointer data);
static void valchanged_cmd_input(GtkWidget* w, gpointer data);
static void activate_print(GtkWidget* w, gpointer data);
static void activate_close(GtkWidget* w, gpointer data);
static void activate_zoom_in(GtkWidget* w, gpointer data);
static void activate_zoom_out(GtkWidget* w, gpointer data);
static void activate_zoom_reset(GtkWidget* w, gpointer data);
static void activate_help(GtkWidget* w, gpointer data);
static void activate_help_proview(GtkWidget* w, gpointer data);
~XttLogGtk();
};
#endif
/*
* ProviewR Open Source Process Control.
* Copyright (C) 2005-2020 SSAB EMEA AB.
*
* This file is part of ProviewR.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProviewR. If not, see <http://www.gnu.org/licenses/>
*
* Linking ProviewR statically or dynamically with other modules is
* making a combined work based on ProviewR. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
*
* In addition, as a special exception, the copyright holders of
* ProviewR give you permission to, from the build function in the
* ProviewR Configurator, combine ProviewR with modules generated by the
* ProviewR PLC Editor to a PLC program, regardless of the license
* terms of these modules. You may copy and distribute the resulting
* combined work under the terms of your choice, provided that every
* copy of the combined work is accompanied by a complete copy of
* the source code of ProviewR (the version used to produce the
* combined work), being distributed under the terms of the GNU
* General Public License plus this exception.
*/
/* sev_lognav.cpp -- Log file viewer */
#include "co_cdh.h"
#include "co_time.h"
#include "flow_browwidget_gtk.h"
#include "flow_msg.h"
#include "glow_growapi.h"
#include "glow_growwidget_gtk.h"
#include "xtt_log_gtk.h"
//
// Create the navigator widget
//
LogNavGtk::LogNavGtk(void* xn_parent_ctx, GtkWidget* xn_parent_wid,
LogNav_hier *xn_tree, GtkWidget** w,
pwr_tStatus* status)
: LogNav(xn_parent_ctx, xn_tree, status),
parent_wid(xn_parent_wid)
{
form_widget
= scrolledbrowwidgetgtk_new(LogNav::init_brow_cb, this, &brow_widget);
gtk_widget_show_all(brow_widget);
// Create the root item
*w = form_widget;
*status = 1;
}
//
// Delete a nav context
//
LogNavGtk::~LogNavGtk()
{
delete brow;
gtk_widget_destroy(form_widget);
}
void LogNavGtk::set_inputfocus()
{
gtk_widget_grab_focus(brow_widget);
}
/*
* ProviewR Open Source Process Control.
* Copyright (C) 2005-2020 SSAB EMEA AB.
*
* This file is part of ProviewR.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProviewR. If not, see <http://www.gnu.org/licenses/>
*
* Linking ProviewR statically or dynamically with other modules is
* making a combined work based on ProviewR. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
*
* In addition, as a special exception, the copyright holders of
* ProviewR give you permission to, from the build function in the
* ProviewR Configurator, combine ProviewR with modules generated by the
* ProviewR PLC Editor to a PLC program, regardless of the license
* terms of these modules. You may copy and distribute the resulting
* combined work under the terms of your choice, provided that every
* copy of the combined work is accompanied by a complete copy of
* the source code of ProviewR (the version used to produce the
* combined work), being distributed under the terms of the GNU
* General Public License plus this exception.
*/
#ifndef xtt_lognav_gtk_h
#define xtt_lognav_gtk_h
/* xtt_lognav_gtk.h -- Simple navigator */
#include <gtk/gtk.h>
#include "../src/xtt_lognav.h"
//! The navigation area of the attribute editor.
class LogNavGtk : public LogNav {
public:
LogNavGtk(void* xn_parent_ctx, GtkWidget* xn_parent_wid,
LogNav_hier *tree, GtkWidget** w,
pwr_tStatus* status);
~LogNavGtk();
GtkWidget* parent_wid;
GtkWidget* brow_widget;
GtkWidget* form_widget;
GtkWidget* toplevel;
void set_inputfocus();
};
#endif
ifndef link_rule_mk
link_rule_mk := 1
link = $(ldxx) $(elinkflags) $(domap) -o $(export_exe) \
$(export_obj) $(wb_msg_eobjs) $(rt_msg_eobjs) \
$(pwr_eobj)/rt_io_user.o \
$(pwre_conf_libdir) $(pwre_conf_libpwrrt) $(pwre_conf_lib)
endif
/*
* ProviewR Open Source Process Control.
* Copyright (C) 2005-2020 SSAB EMEA AB.
*
* This file is part of ProviewR.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProviewR. If not, see <http://www.gnu.org/licenses/>
*
* Linking ProviewR statically or dynamically with other modules is
* making a combined work based on ProviewR. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
*
* In addition, as a special exception, the copyright holders of
* ProviewR give you permission to, from the build function in the
* ProviewR Configurator, combine ProviewR with modules generated by the
* ProviewR PLC Editor to a PLC program, regardless of the license
* terms of these modules. You may copy and distribute the resulting
* combined work under the terms of your choice, provided that every
* copy of the combined work is accompanied by a complete copy of
* the source code of ProviewR (the version used to produce the
* combined work), being distributed under the terms of the GNU
* General Public License plus this exception.
*/
/* xtt_test.cpp -- Test browser */
#include "co_dcli.h"
#include "co_string.h"
int main(int argc, char* argv[])
{
for (int i = 1; i < argc; i++) {
if (streq(argv[i], "-f")) {
if (i + 1 >= argc) {
printf("\nUsage: test_xtt [-f windowmgr]");
exit(0);
}
dcli_execute_flavour_if_exists(argv, argv[i + 1]);
}
}
dcli_execute_flavour(argv);
}
/*
* ProviewR Open Source Process Control.
* Copyright (C) 2005-2020 SSAB EMEA AB.
*
* This file is part of ProviewR.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProviewR. If not, see <http://www.gnu.org/licenses/>
*
* Linking ProviewR statically or dynamically with other modules is
* making a combined work based on ProviewR. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
*
* In addition, as a special exception, the copyright holders of
* ProviewR give you permission to, from the build function in the
* ProviewR Configurator, combine ProviewR with modules generated by the
* ProviewR PLC Editor to a PLC program, regardless of the license
* terms of these modules. You may copy and distribute the resulting
* combined work under the terms of your choice, provided that every
* copy of the combined work is accompanied by a complete copy of
* the source code of ProviewR (the version used to produce the
* combined work), being distributed under the terms of the GNU
* General Public License plus this exception.
*/
/* xtt_log.cpp -- Display object attributes */
#include <stdlib.h>
#include "co_cnf.h"
#include "co_dcli.h"
#include "co_string.h"
#include "co_time.h"
#include "cow_wow.h"
#include "cow_xhelp.h"
#include "flow_msg.h"
#include "glow_curvectx.h"
#include "xtt_log.h"
#include "xtt_lognav.h"
XttLog::~XttLog()
{
}
XttLog::XttLog(void* xn_parent_ctx, LogNav_hier *xn_tree)
: parent_ctx(xn_parent_ctx), tree(xn_tree), cologin(0), command_open(0),
close_cb(0), base_priv(pwr_mPrv_System), priv(pwr_mPrv_System), verify(0),
ccm_func_registred(0), wow(0), quiet(0)
{
char default_priv[80];
strcpy(base_user, "");
strcpy(user, "");
// Get default privilete from proview.cnf
if (cnf_get_value("sevXttDefaultPriv", default_priv, sizeof(default_priv))) {
if (str_NoCaseStrcmp(default_priv, "READ") == 0)
priv = pwr_mPrv_SevRead;
else if (str_NoCaseStrcmp(default_priv, "ADMIN") == 0)
priv = pwr_mPrv_SevAdmin;
else if (str_NoCaseStrcmp(default_priv, "NONE") == 0)
priv = 0;
else
priv = 0;
} else
priv = 0;
}
void XttLog::message(void* xttlog, char severity, const char* message)
{
((XttLog*)xttlog)->message(severity, message);
}
int XttLog::command_cb(void* ctx, char* cmd)
{
return ((XttLog*)ctx)->command(cmd);
}
int XttLog::is_authorized(void* ctx, unsigned int access, int msg)
{
return ((XttLog*)ctx)->is_authorized(access, msg);
}
int XttLog::is_authorized(unsigned int access, int msg)
{
if (!(priv & access)) {
if (msg)
message('I', "Not authorized for this operation");
return 0;
}
return 1;
}
void XttLog::open_login()
{
pwr_tCmd cmd;
strcpy(cmd, "login");
command(cmd);
}
void XttLog::logout()
{
pwr_tCmd cmd;
strcpy(cmd, "logout");
command(cmd);
}
void XttLog::activate_print()
{
pwr_tFileName filename;
pwr_tCmd cmd;
dcli_translate_filename(filename, "$pwrp_tmp/sevxtt.ps");
lognav->print(filename);
sprintf(cmd, "$pwr_exe/rt_print.sh %s", filename);
system(cmd);
}
void XttLog::activate_zoom_in()
{
double zoom_factor;
lognav->get_zoom(&zoom_factor);
if (zoom_factor > 40)
return;
lognav->zoom(1.18);
}
void XttLog::activate_zoom_out()
{
double zoom_factor;
lognav->get_zoom(&zoom_factor);
if (zoom_factor < 15)
return;
lognav->zoom(1.0 / 1.18);
}
void XttLog::activate_zoom_reset()
{
lognav->unzoom();
}
void XttLog::activate_help()
{
CoXHelp::dhelp("overview", "", navh_eHelpFile_Base, NULL, 0);
}
void XttLog::activate_help_project()
{
CoXHelp::dhelp("index", "", navh_eHelpFile_Project, NULL, 0);
}
void XttLog::activate_help_proview()
{
char cmd[] = "help /version";
command(cmd);
}
void XttLog::sevhist_help_cb(void* ctx, const char* key)
{
CoXHelp::dhelp(key, "", navh_eHelpFile_Base, NULL, 0);
}
int XttLog::sevhist_get_select_cb(
void* ctx, pwr_tOid* oid, char* aname, char* oname)
{
XttLog* xttlog = (XttLog*)ctx;
ItemBase* item;
if (!xttlog->lognav->get_select(&item)) {
xttlog->message('E', "Select an storage item");
return 0;
}
switch (item->type) {
case lognav_eItemType_Hier:
case lognav_eItemType_Entry: {
break;
}
default:
return 0;
}
return 1;
}
/*
* ProviewR Open Source Process Control.
* Copyright (C) 2005-2020 SSAB EMEA AB.
*
* This file is part of ProviewR.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProviewR. If not, see <http://www.gnu.org/licenses/>
*
* Linking ProviewR statically or dynamically with other modules is
* making a combined work based on ProviewR. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
*
* In addition, as a special exception, the copyright holders of
* ProviewR give you permission to, from the build function in the
* ProviewR Configurator, combine ProviewR with modules generated by the
* ProviewR PLC Editor to a PLC program, regardless of the license
* terms of these modules. You may copy and distribute the resulting
* combined work under the terms of your choice, provided that every
* copy of the combined work is accompanied by a complete copy of
* the source code of ProviewR (the version used to produce the
* combined work), being distributed under the terms of the GNU
* General Public License plus this exception.
*/
#ifndef xtt_log_h
#define xtt_log_h
#include "pwr_privilege.h"
#include "rt_sevcli.h"
#include "glow.h"
/* xtt_log.h -- Sev Table Viewer */
class LogNav;
class LogNav_hier;
class XttSevHist;
class CoLogin;
class CoWow;
class XttLog {
public:
XttLog(void* xn_parent_ctx, LogNav_hier *xn_tree);
void* parent_ctx;
char name[80];
LogNav* lognav;
LogNav_hier *tree;
CoLogin* cologin;
int command_open;
void (*close_cb)(void*);
char base_user[80];
char user[80];
unsigned int base_priv;
unsigned int priv;
int verify;
int ccm_func_registred;
CoWow* wow;
int quiet;
virtual void message(char severity, const char* message)
{
}
virtual void set_prompt(const char* prompt)
{
}
int is_authorized(unsigned int access = pwr_mAccess_AllSev, int msg = 1);
void open_login();
void logout();
void activate_print();
void activate_zoom_in();
void activate_zoom_out();
void activate_zoom_reset();
void activate_help();
void activate_help_project();
void activate_help_proview();
static void message(void* attr, char severity, const char* message);
static int is_authorized(void* ctx, unsigned int access, int msg);
static int command_cb(void* ctx, char* cmd);
static void delete_item_yes(void* ctx, void* data);
static int sevhist_get_select_cb(
void* ctx, pwr_tOid* oid, char* aname, char* oname);
static void sevhist_help_cb(void* ctx, const char* key);
virtual ~XttLog();
int command(char* input_str);
int readcmdfile(char* incommand);
int read_bootfile(char* systemname, char* systemgroup);
};
#endif
/*
* ProviewR Open Source Process Control.
* Copyright (C) 2005-2020 SSAB EMEA AB.
*
* This file is part of ProviewR.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProviewR. If not, see <http://www.gnu.org/licenses/>
*
* Linking ProviewR statically or dynamically with other modules is
* making a combined work based on ProviewR. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
*
* In addition, as a special exception, the copyright holders of
* ProviewR give you permission to, from the build function in the
* ProviewR Configurator, combine ProviewR with modules generated by the
* ProviewR PLC Editor to a PLC program, regardless of the license
* terms of these modules. You may copy and distribute the resulting
* combined work under the terms of your choice, provided that every
* copy of the combined work is accompanied by a complete copy of
* the source code of ProviewR (the version used to produce the
* combined work), being distributed under the terms of the GNU
* General Public License plus this exception.
*/
/* xtt_lognav.cpp -- Display test info */
#include <stdlib.h>
#include "pwr_baseclasses.h"
#include "co_cdh.h"
#include "co_dcli.h"
#include "co_string.h"
#include "co_time.h"
#include "flow_msg.h"
#include "xtt_lognav.h"
/*
#define LOGNAV__INPUT_SYNTAX 2
#define LOGNAV__OBJNOTFOUND 4
#define LOGNAV__STRINGTOLONG 6
#define LOGNAV__ITEM_NOCREA 8
*/
#define LOGNAV__SUCCESS 1
void LogNav::message(char sev, const char* text)
{
(message_cb)(parent_ctx, sev, text);
}
void LogNav::print(char* filename)
{
brow_Print(brow->ctx, filename);
}
//
// Free pixmaps
//
void LogNavBrow::free_pixmaps()
{
brow_FreeAnnotPixmap(ctx, pixmap_leaf);
brow_FreeAnnotPixmap(ctx, pixmap_map);
brow_FreeAnnotPixmap(ctx, pixmap_openmap);
}
//
// Create pixmaps for leaf, closed map and open map
//
void LogNavBrow::allocate_pixmaps()
{
brow_LoadPBM(ctx, "xnav_bitmap_leaf", &pixmap_leaf);
brow_LoadPBM(ctx, "xnav_bitmap_map", &pixmap_map);
brow_LoadPBM(ctx, "xnav_bitmap_openmap", &pixmap_openmap);
}
//
// Create the navigator widget
//
LogNav::LogNav(void* xn_parent_ctx, LogNav_hier *xn_tree, pwr_tStatus* status)
: parent_ctx(xn_parent_ctx), tree(xn_tree),
message_cb(NULL)
{
*status = 1;
}
//
// Delete a nav context
//
LogNav::~LogNav()
{
}
LogNavBrow::~LogNavBrow()
{
free_pixmaps();
}
//
// Callbacks from brow
//
static int lognav_brow_cb(FlowCtx* ctx, flow_tEvent event)
{
LogNav* lognav;
ItemBase* item;
if (event->event == flow_eEvent_ObjectDeleted) {
brow_GetUserData(event->object.object, (void**)&item);
delete item;
return 1;
}
brow_GetCtxUserData((BrowCtx*)ctx, (void**)&lognav);
lognav->message(' ', "");
switch (event->event) {
case flow_eEvent_Key_PageDown: {
brow_Page(lognav->brow->ctx, 0.8);
break;
}
case flow_eEvent_Key_PageUp: {
brow_Page(lognav->brow->ctx, -0.8);
break;
}
case flow_eEvent_ScrollDown: {
brow_Page(lognav->brow->ctx, 0.1);
break;
}
case flow_eEvent_ScrollUp: {
brow_Page(lognav->brow->ctx, -0.1);
break;
}
case flow_eEvent_Key_Up: {
brow_tNode* node_list;
int node_count;
brow_tObject object;
int sts;
brow_GetSelectedNodes(lognav->brow->ctx, &node_list, &node_count);
if (!node_count) {
sts = brow_GetLastVisible(lognav->brow->ctx, &object);
if (EVEN(sts))
return 1;
} else {
if (!brow_IsVisible(
lognav->brow->ctx, node_list[0], flow_eVisible_Partial)) {
sts = brow_GetLastVisible(lognav->brow->ctx, &object);
if (EVEN(sts))
return 1;
} else {
sts = brow_GetPrevious(lognav->brow->ctx, node_list[0], &object);
if (EVEN(sts)) {
if (node_count)
free(node_list);
return 1;
}
}
}
brow_SelectClear(lognav->brow->ctx);
brow_SetInverse(object, 1);
brow_SelectInsert(lognav->brow->ctx, object);
if (!brow_IsVisible(lognav->brow->ctx, object, flow_eVisible_Full))
brow_CenterObject(lognav->brow->ctx, object, 0.25);
if (node_count)
free(node_list);
break;
}
case flow_eEvent_Key_Down: {
brow_tNode* node_list;
int node_count;
brow_tObject object;
int sts;
brow_GetSelectedNodes(lognav->brow->ctx, &node_list, &node_count);
if (!node_count) {
sts = brow_GetFirstVisible(lognav->brow->ctx, &object);
if (EVEN(sts))
return 1;
} else {
if (!brow_IsVisible(
lognav->brow->ctx, node_list[0], flow_eVisible_Partial)) {
sts = brow_GetFirstVisible(lognav->brow->ctx, &object);
if (EVEN(sts))
return 1;
} else {
sts = brow_GetNext(lognav->brow->ctx, node_list[0], &object);
if (EVEN(sts)) {
if (node_count)
free(node_list);
return 1;
}
}
}
brow_SelectClear(lognav->brow->ctx);
brow_SetInverse(object, 1);
brow_SelectInsert(lognav->brow->ctx, object);
if (!brow_IsVisible(lognav->brow->ctx, object, flow_eVisible_Full))
brow_CenterObject(lognav->brow->ctx, object, 0.75);
if (node_count)
free(node_list);
break;
}
case flow_eEvent_SelectClear:
brow_ResetSelectInverse(lognav->brow->ctx);
break;
case flow_eEvent_MB1Click: {
// Select
double ll_x, ll_y, ur_x, ur_y;
int sts;
switch (event->object.object_type) {
case flow_eObjectType_Node:
brow_MeasureNode(event->object.object, &ll_x, &ll_y, &ur_x, &ur_y);
if (event->object.x < ll_x + 1.0) {
// Simulate doubleclick
flow_tEvent doubleclick_event;
doubleclick_event = (flow_tEvent)calloc(1, sizeof(*doubleclick_event));
memcpy(doubleclick_event, event, sizeof(*doubleclick_event));
doubleclick_event->event = flow_eEvent_MB1DoubleClick;
sts = lognav_brow_cb(ctx, doubleclick_event);
free((char*)doubleclick_event);
return sts;
}
if (brow_FindSelectedObject(lognav->brow->ctx, event->object.object)) {
brow_SelectClear(lognav->brow->ctx);
} else {
brow_SelectClear(lognav->brow->ctx);
brow_SetInverse(event->object.object, 1);
brow_SelectInsert(lognav->brow->ctx, event->object.object);
}
break;
default:
brow_SelectClear(lognav->brow->ctx);
}
break;
}
case flow_eEvent_Key_Left: {
brow_tNode* node_list;
int node_count;
brow_tObject object;
int sts;
brow_GetSelectedNodes(lognav->brow->ctx, &node_list, &node_count);
if (!node_count)
return 1;
if (brow_IsOpen(node_list[0]))
// Close this node
object = node_list[0];
else {
// Close parent
sts = brow_GetParent(lognav->brow->ctx, node_list[0], &object);
if (EVEN(sts)) {
free(node_list);
return 1;
}
}
brow_GetUserData(object, (void**)&item);
item->close(lognav, 0, 0);
brow_SelectClear(lognav->brow->ctx);
brow_SetInverse(object, 1);
brow_SelectInsert(lognav->brow->ctx, object);
if (!brow_IsVisible(lognav->brow->ctx, object, flow_eVisible_Full))
brow_CenterObject(lognav->brow->ctx, object, 0.25);
free(node_list);
break;
}
case flow_eEvent_Key_Right: {
brow_tNode* node_list;
int node_count;
brow_GetSelectedNodes(lognav->brow->ctx, &node_list, &node_count);
if (!node_count)
return 1;
brow_GetUserData(node_list[0], (void**)&item);
switch (item->type) {
case lognav_eItemType_Hier:
((ItemHier*)item)->open_children(lognav, 0, 0);
break;
case lognav_eItemType_Entry:
((ItemEntry*)item)->open_children(lognav, 0, 0);
break;
default:;
}
}
case flow_eEvent_MB1DoubleClick:
switch (event->object.object_type) {
case flow_eObjectType_Node:
brow_GetUserData(event->object.object, (void**)&item);
switch (item->type) {
case lognav_eItemType_Hier:
((ItemHier*)item)
->open_children(lognav, event->object.x, event->object.y);
case lognav_eItemType_Entry:
((ItemEntry*)item)
->open_children(lognav, event->object.x, event->object.y);
break;
default:;
}
break;
default:;
}
break;
default:;
}
return 1;
}
//
// Create nodeclasses
//
void LogNavBrow::create_nodeclasses()
{
allocate_pixmaps();
// Create red class
brow_CreateNodeClass(
ctx, "Red", flow_eNodeGroup_Common, &nc_red);
brow_AddAnnotPixmap(nc_red, 0, 0.2, 0.1, flow_eDrawType_Line, 2, 0);
brow_AddFilledRect(nc_red, 1.05, 0.05, 0.6, 0.6, flow_eDrawType_LineRed);
brow_AddRect(nc_red, 1.05, 0.05, 0.6, 0.6, flow_eDrawType_Line, 0, 0);
brow_AddAnnot(nc_red, 2, 0.6, 0, flow_eDrawType_TextHelvetica, 2,
flow_eAnnotType_OneLine, 0);
brow_AddAnnot(nc_red, 9.5, 0.6, 1, flow_eDrawType_TextHelvetica, 2,
flow_eAnnotType_OneLine, 1);
brow_AddFrame(nc_red, 0, 0, 20, 0.83, flow_eDrawType_LineGray, -1, 1);
// Create green class
brow_CreateNodeClass(
ctx, "Green", flow_eNodeGroup_Common, &nc_green);
brow_AddAnnotPixmap(nc_green, 0, 0.2, 0.1, flow_eDrawType_Line, 2, 0);
brow_AddFilledRect(nc_green, 1.05, 0.05, 0.6, 0.6, flow_eDrawType_Green);
brow_AddRect(nc_green, 1.05, 0.05, 0.6, 0.6, flow_eDrawType_Line, 0, 0);
brow_AddAnnot(nc_green, 2, 0.6, 0, flow_eDrawType_TextHelvetica, 2,
flow_eAnnotType_OneLine, 0);
brow_AddAnnot(nc_green, 9.5, 0.6, 1, flow_eDrawType_TextHelvetica, 2,
flow_eAnnotType_OneLine, 1);
brow_AddFrame(nc_green, 0, 0, 20, 0.83, flow_eDrawType_LineGray, -1, 1);
// Create yellow class
brow_CreateNodeClass(
ctx, "Yellow", flow_eNodeGroup_Common, &nc_yellow);
brow_AddAnnotPixmap(nc_yellow, 0, 0.2, 0.1, flow_eDrawType_Line, 2, 0);
brow_AddFilledRect(nc_yellow, 1.05, 0.05, 0.6, 0.6, flow_eDrawType_Yellow);
brow_AddRect(nc_yellow, 1.05, 0.05, 0.6, 0.6, flow_eDrawType_Line, 0, 0);
brow_AddAnnot(nc_yellow, 2, 0.6, 0, flow_eDrawType_TextHelvetica, 2,
flow_eAnnotType_OneLine, 0);
brow_AddAnnot(nc_yellow, 9.5, 0.6, 1, flow_eDrawType_TextHelvetica, 2,
flow_eAnnotType_OneLine, 1);
brow_AddFrame(nc_yellow, 0, 0, 20, 0.83, flow_eDrawType_LineGray, -1, 1);
// Create white class
brow_CreateNodeClass(
ctx, "White", flow_eNodeGroup_Common, &nc_white);
brow_AddAnnotPixmap(nc_white, 0, 0.2, 0.1, flow_eDrawType_Line, 2, 0);
brow_AddRect(nc_white, 1.05, 0.05, 0.6, 0.6, flow_eDrawType_Line, 0, 0);
brow_AddAnnot(nc_white, 2, 0.6, 0, flow_eDrawType_TextHelvetica, 2,
flow_eAnnotType_OneLine, 0);
brow_AddAnnot(nc_white, 9.5, 0.6, 1, flow_eDrawType_TextHelvetica, 2,
flow_eAnnotType_OneLine, 1);
brow_AddFrame(nc_white, 0, 0, 20, 0.83, flow_eDrawType_LineGray, -1, 1);
// Create without mark
brow_CreateNodeClass(
ctx, "NoMark", flow_eNodeGroup_Common, &nc_nomark);
brow_AddAnnotPixmap(nc_nomark, 0, 0.2, 0.1, flow_eDrawType_Line, 2, 0);
brow_AddAnnot(nc_nomark, 2, 0.6, 0, flow_eDrawType_TextHelvetica, 2,
flow_eAnnotType_OneLine, 0);
brow_AddAnnot(nc_nomark, 9.5, 0.6, 1, flow_eDrawType_TextHelvetica, 2,
flow_eAnnotType_OneLine, 1);
brow_AddFrame(nc_nomark, 0, 0, 20, 0.83, flow_eDrawType_LineGray, -1, 1);
}
int LogNav::create_items()
{
brow_SetNodraw(brow->ctx);
for (int i = 0; i < tree->child.size(); i++) {
new ItemHier(this, &tree->child[i], NULL, flow_eDest_IntoLast);
}
brow_ResetNodraw(brow->ctx);
brow_Redraw(brow->ctx, 0);
return LOGNAV__SUCCESS;
}
void LogNavBrow::brow_setup()
{
brow_sAttributes brow_attr;
unsigned long mask;
mask = 0;
mask |= brow_eAttr_indentation;
brow_attr.indentation = 0.5;
mask |= brow_eAttr_annotation_space;
brow_attr.annotation_space = 0.5;
brow_SetAttributes(ctx, &brow_attr, mask);
brow_SetCtxUserData(ctx, lognav);
brow_EnableEvent(
ctx, flow_eEvent_MB1Click, flow_eEventType_CallBack, lognav_brow_cb);
brow_EnableEvent(ctx, flow_eEvent_MB1DoubleClick, flow_eEventType_CallBack,
lognav_brow_cb);
brow_EnableEvent(
ctx, flow_eEvent_SelectClear, flow_eEventType_CallBack, lognav_brow_cb);
brow_EnableEvent(
ctx, flow_eEvent_ObjectDeleted, flow_eEventType_CallBack, lognav_brow_cb);
brow_EnableEvent(
ctx, flow_eEvent_Key_Up, flow_eEventType_CallBack, lognav_brow_cb);
brow_EnableEvent(
ctx, flow_eEvent_Key_Down, flow_eEventType_CallBack, lognav_brow_cb);
brow_EnableEvent(
ctx, flow_eEvent_Key_Right, flow_eEventType_CallBack, lognav_brow_cb);
brow_EnableEvent(
ctx, flow_eEvent_Key_Left, flow_eEventType_CallBack, lognav_brow_cb);
brow_EnableEvent(
ctx, flow_eEvent_Key_PF3, flow_eEventType_CallBack, lognav_brow_cb);
brow_EnableEvent(
ctx, flow_eEvent_Radiobutton, flow_eEventType_CallBack, lognav_brow_cb);
brow_EnableEvent(
ctx, flow_eEvent_Key_PageUp, flow_eEventType_CallBack, lognav_brow_cb);
brow_EnableEvent(
ctx, flow_eEvent_Key_PageDown, flow_eEventType_CallBack, lognav_brow_cb);
brow_EnableEvent(
ctx, flow_eEvent_ScrollUp, flow_eEventType_CallBack, lognav_brow_cb);
brow_EnableEvent(
ctx, flow_eEvent_ScrollDown, flow_eEventType_CallBack, lognav_brow_cb);
}
//
// Backcall routine called at creation of the brow widget
// Enable event, create nodeclasses and insert the root objects.
//
int LogNav::init_brow_cb(FlowCtx* fctx, void* client_data)
{
LogNav* lognav = (LogNav*)client_data;
BrowCtx* ctx = (BrowCtx*)fctx;
lognav->brow = new LogNavBrow(ctx, (void*)lognav);
lognav->brow->brow_setup();
lognav->brow->create_nodeclasses();
// Create the root items
lognav->create_items();
if (lognav->command_cb) {
pwr_tCmd cmd = "@$HOME/test_xtt_setup";
lognav->command_cb(lognav->parent_ctx, cmd);
}
return 1;
}
int LogNav::get_select(ItemBase** item)
{
brow_tNode* node_list;
int node_count;
brow_GetSelectedNodes(brow->ctx, &node_list, &node_count);
if (!node_count)
return 0;
brow_GetUserData(node_list[0], (void**)item);
return 1;
}
//
// Get zoom
//
void LogNav::get_zoom(double* zoom_factor)
{
brow_GetZoom(brow->ctx, zoom_factor);
}
//
// Zoom
//
void LogNav::zoom(double zoom_factor)
{
brow_Zoom(brow->ctx, zoom_factor);
}
//
// Return to base zoom factor
//
void LogNav::unzoom()
{
brow_UnZoom(brow->ctx);
}
ItemBase::ItemBase(lognav_eItemType t) : type(t)
{
}
ItemBase::~ItemBase()
{
}
int ItemBase::close(LogNav* lognav, double x, double y)
{
return 1;
}
ItemHier ::ItemHier (LogNav* lognav, LogNav_hier* xitem,
brow_tNode dest, flow_eDest dest_code)
: ItemBase(lognav_eItemType_Hier), item(xitem)
{
brow_tNodeClass nc;
type = lognav_eItemType_Hier;
switch (item->severity) {
case lognav_eSeverity_Fatal:
case lognav_eSeverity_Error:
case lognav_eSeverity_DetailError:
nc = lognav->brow->nc_red;
break;
case lognav_eSeverity_Warning:
case lognav_eSeverity_DetailWarning:
nc = lognav->brow->nc_yellow;
break;
case lognav_eSeverity_Info:
case lognav_eSeverity_Success:
case lognav_eSeverity_No:
case lognav_eSeverity_Detail:
nc = lognav->brow->nc_nomark;
break;
}
brow_CreateNode(lognav->brow->ctx, "HierItem", nc, dest,
dest_code, (void*)this, 1, &node);
if (item->child.size() == 0)
brow_SetAnnotPixmap(node, 0, lognav->brow->pixmap_leaf);
else
brow_SetAnnotPixmap(node, 0, lognav->brow->pixmap_map);
brow_SetAnnotation(node, 0, item->text, strlen(item->text));
}
int ItemHier::open_children(LogNav* lognav, double x, double y)
{
double node_x, node_y;
brow_GetNodePosition(node, &node_x, &node_y);
if (brow_IsOpen(node)) {
// Close
brow_SetNodraw(lognav->brow->ctx);
brow_CloseNode(lognav->brow->ctx, node);
brow_SetAnnotPixmap(node, 0, lognav->brow->pixmap_map);
brow_ResetOpen(node, lognav_mOpen_All);
brow_ResetNodraw(lognav->brow->ctx);
brow_Redraw(lognav->brow->ctx, node_y);
} else {
brow_SetNodraw(lognav->brow->ctx);
for (int i = 0; i < item->child.size(); i++) {
if (item->child[i].type == lognav_eItemType_Hier)
new ItemHier(lognav, &item->child[i], node, flow_eDest_IntoLast);
else
new ItemEntry(lognav, &item->child[i], node, flow_eDest_IntoLast);
}
brow_SetAnnotPixmap(node, 0, lognav->brow->pixmap_openmap);
brow_SetOpen(node, lognav_mOpen_Children);
brow_ResetNodraw(lognav->brow->ctx);
brow_Redraw(lognav->brow->ctx, node_y);
}
return 1;
}
int ItemHier::close(LogNav* lognav, double x, double y)
{
double node_x, node_y;
brow_GetNodePosition(node, &node_x, &node_y);
if (brow_IsOpen(node)) {
// Close
brow_SetNodraw(lognav->brow->ctx);
brow_CloseNode(lognav->brow->ctx, node);
brow_SetAnnotPixmap(node, 0, lognav->brow->pixmap_map);
brow_ResetOpen(node, lognav_mOpen_All);
brow_ResetNodraw(lognav->brow->ctx);
brow_Redraw(lognav->brow->ctx, node_y);
}
return 1;
}
ItemEntry ::ItemEntry (LogNav* lognav, LogNav_hier* xitem,
brow_tNode dest, flow_eDest dest_code)
: ItemBase(lognav_eItemType_Hier), item(xitem)
{
char timstr[40];
brow_tNodeClass nc;
type = lognav_eItemType_Entry;
switch (item->severity) {
case lognav_eSeverity_Fatal:
case lognav_eSeverity_Error:
case lognav_eSeverity_DetailError:
nc = lognav->brow->nc_red;
break;
case lognav_eSeverity_Warning:
case lognav_eSeverity_DetailWarning:
nc = lognav->brow->nc_yellow;
break;
case lognav_eSeverity_Info:
case lognav_eSeverity_Success:
case lognav_eSeverity_No:
case lognav_eSeverity_Detail:
nc = lognav->brow->nc_nomark;
break;
}
brow_CreateNode(lognav->brow->ctx, "EntryItem", nc, dest,
dest_code, (void*)this, 1, &node);
if (item->child.size() == 0)
brow_SetAnnotPixmap(node, 0, lognav->brow->pixmap_leaf);
else
brow_SetAnnotPixmap(node, 0, lognav->brow->pixmap_map);
time_AtoAscii(&item->time, time_eFormat_DateAndTime, timstr, sizeof(timstr));
brow_SetAnnotation(node, 0, timstr, strlen(timstr));
brow_SetAnnotation(node, 1, item->text, strlen(item->text));
}
int ItemEntry::open_children(LogNav* lognav, double x, double y)
{
double node_x, node_y;
if (item->child.size() == 0)
return 1;
brow_GetNodePosition(node, &node_x, &node_y);
if (brow_IsOpen(node)) {
// Close
brow_SetNodraw(lognav->brow->ctx);
brow_CloseNode(lognav->brow->ctx, node);
brow_SetAnnotPixmap(node, 0, lognav->brow->pixmap_map);
brow_ResetOpen(node, lognav_mOpen_All);
brow_ResetNodraw(lognav->brow->ctx);
brow_Redraw(lognav->brow->ctx, node_y);
} else {
brow_SetNodraw(lognav->brow->ctx);
for (int i = 0; i < item->child.size(); i++) {
if (item->child[i].type == lognav_eItemType_Hier)
new ItemHier(lognav, &item->child[i], node, flow_eDest_IntoLast);
else
new ItemEntry(lognav, &item->child[i], node, flow_eDest_IntoLast);
}
brow_SetAnnotPixmap(node, 0, lognav->brow->pixmap_openmap);
brow_SetOpen(node, lognav_mOpen_Children);
brow_ResetNodraw(lognav->brow->ctx);
brow_Redraw(lognav->brow->ctx, node_y);
}
return 1;
}
int ItemEntry::close(LogNav* lognav, double x, double y)
{
double node_x, node_y;
brow_GetNodePosition(node, &node_x, &node_y);
if (brow_IsOpen(node)) {
// Close
brow_SetNodraw(lognav->brow->ctx);
brow_CloseNode(lognav->brow->ctx, node);
brow_SetAnnotPixmap(node, 0, lognav->brow->pixmap_map);
brow_ResetOpen(node, lognav_mOpen_All);
brow_ResetNodraw(lognav->brow->ctx);
brow_Redraw(lognav->brow->ctx, node_y);
}
return 1;
}
/*
* ProviewR Open Source Process Control.
* Copyright (C) 2005-2020 SSAB EMEA AB.
*
* This file is part of ProviewR.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProviewR. If not, see <http://www.gnu.org/licenses/>
*
* Linking ProviewR statically or dynamically with other modules is
* making a combined work based on ProviewR. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
*
* In addition, as a special exception, the copyright holders of
* ProviewR give you permission to, from the build function in the
* ProviewR Configurator, combine ProviewR with modules generated by the
* ProviewR PLC Editor to a PLC program, regardless of the license
* terms of these modules. You may copy and distribute the resulting
* combined work under the terms of your choice, provided that every
* copy of the combined work is accompanied by a complete copy of
* the source code of ProviewR (the version used to produce the
* combined work), being distributed under the terms of the GNU
* General Public License plus this exception.
*/
#ifndef xtt_lognav_h
#define xtt_lognav_h
/* xtt_attrnav.h -- Sev Table Viewer */
#include <vector>
#include "pwr_privilege.h"
#include "flow_browapi.h"
#include "rt_sevcli.h"
class ItemBase;
typedef enum {
lognav_eItemType_Hier,
lognav_eItemType_Entry,
lognav_eItemType_Detail
} lognav_eItemType;
typedef enum {
lognav_mOpen_All = ~0,
lognav_mOpen_Children = 1 << 0,
lognav_mOpen_Attributes = 1 << 1
} lognav_mOpen;
typedef enum {
lognav_eSeverity_No,
lognav_eSeverity_Detail,
lognav_eSeverity_DetailWarning,
lognav_eSeverity_DetailError,
lognav_eSeverity_Success,
lognav_eSeverity_Info,
lognav_eSeverity_Warning,
lognav_eSeverity_Error,
lognav_eSeverity_Fatal
} lognav_eSeverity;
class LogNav_object {
public:
};
class LogNav_hier : public LogNav_object {
public:
lognav_eSeverity severity;
lognav_eItemType type;
pwr_tTime time;
char text[120];
std::vector<LogNav_hier> child;
LogNav_hier() : severity(lognav_eSeverity_No), time(pwr_cNTime) {}
LogNav_hier(const LogNav_hier& x) : severity(x.severity), type(x.type),
child(x.child) {
memcpy(&time, &x.time, sizeof(pwr_tTime));
strcpy(text, x.text);
}
};
typedef enum {
lognav_eTreeItemType_No,
lognav_eTreeItemType_Hier,
lognav_eTreeItemType_Entry,
lognav_eTreeItemType_Detail
} lognav_eTreeItemType;
//! Class for handling of brow.
class LogNavBrow {
public:
LogNavBrow(BrowCtx* brow_ctx, void* xn) : ctx(brow_ctx), lognav(xn)
{
}
~LogNavBrow();
BrowCtx* ctx;
void* lognav;
brow_tNodeClass nc_red;
brow_tNodeClass nc_green;
brow_tNodeClass nc_yellow;
brow_tNodeClass nc_white;
brow_tNodeClass nc_nomark;
flow_sAnnotPixmap* pixmap_leaf;
flow_sAnnotPixmap* pixmap_map;
flow_sAnnotPixmap* pixmap_openmap;
void free_pixmaps();
void allocate_pixmaps();
void create_nodeclasses();
void brow_setup();
};
//! The navigation area of the attribute editor.
class LogNav {
public:
LogNav(void* xn_parent_ctx, LogNav_hier *xn_tree, pwr_tStatus* status);
virtual ~LogNav();
void* parent_ctx;
LogNavBrow* brow;
LogNav_hier *tree;
int item_cnt;
void (*message_cb)(void*, char, const char*);
int (*command_cb)(void*, char* cmd);
int list_layout;
void print(char* filename);
int create_items();
int get_select(ItemBase** item);
void get_zoom(double* zoom_factor);
void zoom(double zoom_factor);
void unzoom();
virtual void message(char sev, const char* text);
virtual void set_inputfocus()
{
}
static int init_brow_cb(FlowCtx* fctx, void* client_data);
};
class ItemBase {
public:
ItemBase(lognav_eItemType t);
virtual ~ItemBase();
lognav_eItemType type;
virtual int close(LogNav* lognav, double x, double y);
};
//! Hierarchy item.
class ItemHier : public ItemBase {
public:
ItemHier(LogNav* lognav, LogNav_hier* item, brow_tNode dest,
flow_eDest dest_code);
virtual ~ItemHier()
{
}
LogNav_hier *item;
brow_tNode node;
int open_children(LogNav* lognav, double x, double y);
int close(LogNav* lognav, double x, double y);
};
//! Log entry item.
class ItemEntry : public ItemBase {
public:
ItemEntry(LogNav* lognav, LogNav_hier* item, brow_tNode dest,
flow_eDest dest_code);
virtual ~ItemEntry()
{
}
LogNav_hier *item;
brow_tNode node;
int open_children(LogNav* lognav, double x, double y);
int close(LogNav* lognav, double x, double y);
};
#endif
/*
* ProviewR Open Source Process Control.
* Copyright (C) 2005-2020 SSAB EMEA AB.
*
* This file is part of ProviewR.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProviewR. If not, see <http://www.gnu.org/licenses/>
*
* Linking ProviewR statically or dynamically with other modules is
* making a combined work based on ProviewR. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
*
* In addition, as a special exception, the copyright holders of
* ProviewR give you permission to, from the build function in the
* ProviewR Configurator, combine ProviewR with modules generated by the
* ProviewR PLC Editor to a PLC program, regardless of the license
* terms of these modules. You may copy and distribute the resulting
* combined work under the terms of your choice, provided that every
* copy of the combined work is accompanied by a complete copy of
* the source code of ProviewR (the version used to produce the
* combined work), being distributed under the terms of the GNU
* General Public License plus this exception.
*/
/* xtt_lognav_command.cpp
This module contains routines for handling of command line in test_xtt. */
#include <ctype.h>
#include <stdlib.h>
#include "co_api_user.h"
#include "co_ccm.h"
#include "co_ccm_msg.h"
#include "co_dbs.h"
#include "co_dcli.h"
#include "co_dcli_msg.h"
#include "co_error.h"
#include "co_string.h"
#include "co_syi.h"
#include "co_user.h"
#include "cow_login.h"
#include "cow_wow.h"
#include "cow_xhelp.h"
#include "flow_msg.h"
#include "glow_curvectx.h"
#include "xtt_log.h"
#include "xtt_lognav.h"
#include "xtt_sevhist.h"
#define XTTLOG__HOLDCOMMAND 21;
#define XTTLOG__SUCCESS 23;
static pwr_tStatus command_sts = 1;
static XttLog* current_xttlog;
static int xttlog_exit_func(void* client_data, void* client_flag);
static int xttlog_help_func(void* client_data, void* client_flag);
static int xttlog_open_func(void* client_data, void* client_flag);
static int xttlog_show_func(void* client_data, void* client_flag);
dcli_tCmdTable xttlog_command_table[] = {
{ "OPEN", &xttlog_open_func, { "dcli_arg1", "dcli_arg2", "/NAME", "" } },
{ "SHOW", &xttlog_show_func, { "dcli_arg1", "" } },
{ "EXIT", &xttlog_exit_func,
{
"",
} },
{ "QUIT", &xttlog_exit_func,
{
"",
} },
{ "HELP", &xttlog_help_func,
{ "dcli_arg1", "dcli_arg2", "dcli_arg3", "dcli_arg4", "/HELPFILE",
"/POPNAVIGATOR", "/BOOKMARK", "/INDEX", "/BASE", "/RETURNCOMMAND",
"/WIDTH", "/HEIGHT", "/VERSION", "" } },
{ "", NULL, { "" } }
};
static void xttlog_store_xttlog(XttLog* xttlog)
{
current_xttlog = xttlog;
}
static int xttlog_help_func(void* client_data, void* client_flag)
{
XttLog* xttlog = (XttLog*)client_data;
int sts;
char arg_str[80];
char file_str[80];
char bookmark_str[80];
char key[80];
char return_str[80];
int pop;
int width, height;
int nr;
if (ODD(dcli_get_qualifier("/INDEX", file_str, sizeof(file_str)))) {
if (ODD(dcli_get_qualifier("/HELPFILE", file_str, sizeof(file_str)))) {
sts = CoXHelp::dhelp_index(navh_eHelpFile_Other, file_str);
if (EVEN(sts))
xttlog->message('E', "Unable to find file");
} else {
if (ODD(dcli_get_qualifier("/BASE", 0, 0)))
sts = CoXHelp::dhelp_index(navh_eHelpFile_Base, NULL);
else
sts = CoXHelp::dhelp_index(navh_eHelpFile_Project, NULL);
}
return 1;
}
if (ODD(dcli_get_qualifier("/VERSION", 0, 0))) {
sts = CoXHelp::dhelp("version", "", navh_eHelpFile_Other,
"$pwr_load/xtt_version_help.dat", 0);
if (EVEN(sts)) {
sts = CoXHelp::dhelp("version", "", navh_eHelpFile_Other,
"$pwr_load/sev_xtt_version_help.dat", 0);
if (EVEN(sts))
xttlog->message('E', "No help on this subject");
}
return sts;
}
int strict = 0;
if (EVEN(dcli_get_qualifier("dcli_arg1", arg_str, sizeof(arg_str)))) {
sts = CoXHelp::dhelp("help command", "", navh_eHelpFile_Base, NULL, strict);
return 1;
}
if (EVEN(dcli_get_qualifier("/BOOKMARK", bookmark_str, sizeof(bookmark_str))))
strcpy(bookmark_str, "");
strcpy(key, arg_str);
if (ODD(dcli_get_qualifier("dcli_arg2", arg_str, sizeof(arg_str)))) {
strcat(key, " ");
strcat(key, arg_str);
if (ODD(dcli_get_qualifier("dcli_arg3", arg_str, sizeof(arg_str)))) {
strcat(key, " ");
strcat(key, arg_str);
if (ODD(dcli_get_qualifier("dcli_arg3", arg_str, sizeof(arg_str)))) {
strcat(key, " ");
strcat(key, arg_str);
if (ODD(dcli_get_qualifier("dcli_arg4", arg_str, sizeof(arg_str)))) {
strcat(key, " ");
strcat(key, arg_str);
}
}
}
}
if (!ODD(
dcli_get_qualifier("/RETURNCOMMAND", return_str, sizeof(return_str))))
strcpy(return_str, "");
if (ODD(dcli_get_qualifier("/WIDTH", arg_str, sizeof(arg_str)))) {
// convert to integer
nr = sscanf(arg_str, "%d", &width);
if (nr != 1) {
xttlog->message('E', "Width syntax error");
return XTTLOG__HOLDCOMMAND;
}
} else
width = 0;
if (ODD(dcli_get_qualifier("/HEIGHT", arg_str, sizeof(arg_str)))) {
// convert to integer
nr = sscanf(arg_str, "%d", &height);
if (nr != 1) {
xttlog->message('E', "Height syntax error");
return XTTLOG__HOLDCOMMAND;
}
} else
height = 0;
pop = ODD(dcli_get_qualifier("/POPNAVIGATOR", 0, 0));
if (ODD(dcli_get_qualifier("/HELPFILE", file_str, sizeof(file_str)))) {
sts = CoXHelp::dhelp(
key, bookmark_str, navh_eHelpFile_Other, file_str, strict);
if (EVEN(sts))
xttlog->message('E', "No help on this subject");
} else if (ODD(dcli_get_qualifier("/BASE", 0, 0))) {
sts = CoXHelp::dhelp(key, bookmark_str, navh_eHelpFile_Base, 0, strict);
if (EVEN(sts))
xttlog->message('E', "No help on this subject");
} else {
sts = CoXHelp::dhelp(key, bookmark_str, navh_eHelpFile_Base, 0, strict);
if (EVEN(sts)) {
sts = CoXHelp::dhelp(
key, bookmark_str, navh_eHelpFile_Project, 0, strict);
if (EVEN(sts))
xttlog->message('E', "No help on this subject");
}
}
return 1;
}
static int xttlog_exit_func(void* client_data, void* client_flag)
{
XttLog* xttlog = (XttLog*)client_data;
if (xttlog->close_cb)
(xttlog->close_cb)(xttlog->parent_ctx);
else
exit(1);
return 1;
}
static int xttlog_open_func(void* client_data, void* client_flag)
{
XttLog* xttlog = (XttLog*)client_data;
char arg1_str[80];
int arg1_sts;
arg1_sts = dcli_get_qualifier("dcli_arg1", arg1_str, sizeof(arg1_str));
if (str_StartsWith(arg1_str, "GRAPH")) {
} else
xttlog->message('E', "Syntax error");
return XTTLOG__SUCCESS;
}
static int xttlog_show_func(void* client_data, void* client_flag)
{
XttLog* xttlog = (XttLog*)client_data;
char arg1_str[80];
int arg1_sts;
arg1_sts = dcli_get_qualifier("dcli_arg1", arg1_str, sizeof(arg1_str));
if (str_StartsWith(arg1_str, "USER")) {
} else
xttlog->message('E', "Syntax error");
return 1;
}
int XttLog::command(char* input_str)
{
char command[1000];
int sts, sym_sts;
char symbol_value[DCLI_SYM_VALUE_SIZE];
if (input_str[0] == '@') {
sts = dcli_replace_symbol(input_str, command, sizeof(command));
if (EVEN(sts))
return sts;
/* Read command file */
sts = readcmdfile(&command[1]);
if (sts == DCLI__NOFILE) {
char tmp[1030];
snprintf(tmp, sizeof(tmp), "Unable to open file \"%s\"", &command[1]);
message('E', tmp);
return DCLI__SUCCESS;
} else if (EVEN(sts))
return sts;
return DCLI__SUCCESS;
}
dcli_toupper(input_str, input_str);
sts = dcli_replace_symbol(input_str, command, sizeof(command));
if (EVEN(sts))
return sts;
sts = dcli_cli(
(dcli_tCmdTable*)&xttlog_command_table, command, (void*)this, 0);
if (sts == DCLI__COM_NODEF) {
/* Try to find a matching symbol */
sym_sts = dcli_get_symbol_cmd(command, symbol_value);
if (ODD(sym_sts)) {
if (symbol_value[0] == '@') {
/* Read command file */
sts = readcmdfile(&symbol_value[1]);
if (sts == DCLI__NOFILE) {
char tmp[230];
snprintf(tmp, sizeof(tmp), "Unable to open file \"%s\"", &symbol_value[1]);
message('E', tmp);
return DCLI__SUCCESS;
} else if (EVEN(sts))
return sts;
return DCLI__SUCCESS;
}
sts = dcli_cli(
(dcli_tCmdTable*)&xttlog_command_table, symbol_value, (void*)this, 0);
} else if (sym_sts == DCLI__SYMBOL_AMBIG)
sts = sym_sts;
}
if (sts == DCLI__COM_AMBIG)
message('E', "Ambiguous command");
else if (sts == DCLI__COM_NODEF)
message('E', "Undefined command");
else if (sts == DCLI__QUAL_AMBIG)
message('E', "Ambiguous qualifier");
else if (sts == DCLI__QUAL_NODEF)
message('E', "Undefined qualifier");
else if (sts == DCLI__SYMBOL_AMBIG)
message('E', "Ambiguous symbol abbrevation");
command_sts = sts;
return DCLI__SUCCESS;
}
static int xttlog_ccm_errormessage_func(
char* msg, int severity, void* client_data)
{
XttLog* xttlog = (XttLog*)client_data;
if (EVEN(severity))
xttlog->message('I', msg);
else
xttlog->message('E', msg);
return 1;
}
static int xttlog_ccm_deffilename_func(
char* outfile, char* infile, void* client_data)
{
pwr_tFileName fname;
dcli_translate_filename(fname, infile);
dcli_get_defaultfilename(fname, outfile, ".rtt_com");
return 1;
}
int xttlog_externcmd_func(char* cmd, void* client_data)
{
XttLog* xttlog = (XttLog*)client_data;
return xttlog->command(cmd);
}
int XttLog::readcmdfile(char* incommand)
{
char input_str[160];
int sts;
int appl_sts;
if (!ccm_func_registred) {
ccm_func_registred = 1;
}
strcpy(input_str, incommand);
str_trim(input_str, input_str);
xttlog_store_xttlog(this);
/* Read and execute the command file */
sts = ccm_file_exec(input_str, xttlog_externcmd_func,
xttlog_ccm_deffilename_func, xttlog_ccm_errormessage_func, &appl_sts,
verify, 0, NULL, 0, 0, NULL, (void*)this);
if (EVEN(sts))
return sts;
return 1;
}
include $(pwre_dir_symbols)
ifndef variables_mk
include $(pwre_croot)/src/tools/bld/src/variables.mk
endif
ifndef rules_mk
include $(pwre_croot)/src/tools/bld/src/rules.mk
endif
export_obj := $(pwr_exe)/pwrtest.so
clean_obj := clean_pwrtest.so
.PHONY : all init copy lib exe clean
all : init copy lib exe | silent
init :
@ if [ ! -e $(bld_dir) ]; then \
mkdir -p $(bld_dir); \
fi
copy :
lib :
exe : $(export_obj) | silent
clean : $(clean_obj)
silent :
@ :
.SUFFIXES:
$(exe_dir)/pwrtest.so : pwrtestmodule.cpp
@ if [ "$(PWRE_CONF_PYDEV)" = "1" ]; then\
echo "Bulding Python c extension pwrtest";\
python setup_pwrtest.py -q build --build-base $(bld_dir);\
if [ "$(pwre_hw)" = "hw_x86_64" ]; then \
mv $(bld_dir)/lib.linux-x86_64-2.7/pwrtest.so $(pwr_exe); \
elif [ "$(pwre_hw)" = "hw_x86" ]; then \
mv $(bld_dir)/lib.linux-i686-2.7/pwrtest.so $(pwr_exe); \
fi;\
python setup_pwrtest.py -q install_egg_info --install-dir $(pwr_exe);\
else\
echo "Not building Python c extension pwrtest";\
fi
clean_pwrtest.so : pwrtestmodule.cpp
rm $(pwr_exe)/pwrtest.so
#include <Python.h>
#include <datetime.h>
#include "pwr.h"
#include "co_cdh.h"
#include "co_dcli.h"
#include "co_string.h"
#include "co_api_user.h"
#include "co_msg.h"
#include "co_time.h"
#include "co_string.h"
#include "co_tst_msg.h"
#include "co_tst_log.h"
/**
* Doc for pwrtest module
*/
PyDoc_STRVAR(pwrtest_doc,"\
ProviewR Test Python API\n\n\
The test Python API contains a number of classes and functions\n\
for regression test.\n\n\
The API contains the classes\n\n\
Log logg message to test logfile.\n\n\
Type help(pwrtest.Log) to get more information about\n\
these classes.");
/**
* Doc for LogObject class
*/
PyDoc_STRVAR(log_doc,"\
ProviewR test logger\n\n\
The Log object represents the test logger.\n\
");
PyDoc_STRVAR(Log_log_doc,"\
log()\n--\n\n\
Log string to logfile.\n\n\
Example\n\
-------\n\
log = pwrtest.logger('myappl','$pwrp_log/myappl.log')\n\
log.log('E', 'Some error detected')\n\
");
PyDoc_STRVAR(Log_vlog_doc,"\
log()\n--\n\n\
Log string to logfile with format.\n\n\
Example\n\
-------\n\
log = pwrtest.logger('myappl','$pwrp_log/myappl.log')\n\
log.vlog('E', 'Error, %s is not equal %s', str1, str2)\n\
");
/*
* Doc for static methods
*/
PyDoc_STRVAR(pwrtest_logger_doc,"\
logger(name, file)\n--\n\n\
Open logfile.\n\n\
Arguments\n\
---------\n\
name String\n\
Name of application.\n\
file String\n\
Name of logfile.\n\n\
Example\n\
-------\n\
pwrtest.logger('myappl', '$pwrp_log/myappl.log')\n");
typedef struct {
PyObject_HEAD
tst_log *tstlog;
char name[80];
} LogObject;
static PyObject *Log_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
static PyObject *Log_str(PyObject *self);
static int Log_init(LogObject *self, PyObject *args, PyObject *kwds);
static PyObject *Log_log(LogObject *self, PyObject *args);
static PyObject *Log_vlog(LogObject *self, PyObject *args);
static PyMethodDef Log_methods[] = {
{ "log", (PyCFunction) Log_log, METH_VARARGS, Log_log_doc },
{ "vlog", (PyCFunction) Log_vlog, METH_VARARGS, Log_vlog_doc },
{ NULL }
};
static PyTypeObject LogType = {
PyVarObject_HEAD_INIT(NULL, 0)
"Log", /* tp_name */
sizeof(LogObject), /* tp_basicsize */
0, /* tp_itemsize */
0, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
Log_str, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
Log_str, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
log_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
Log_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)Log_init, /* tp_init */
0, /* tp_alloc */
Log_new, /* tp_new */
};
static void *set_error(pwr_tStatus sts)
{
char msg[120];
msg_GetMsg(sts, msg, sizeof(msg));
PyErr_SetString(PyExc_RuntimeError, msg);
return NULL;
}
/*
* Log object functions
*/
static PyObject *
Log_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
LogObject *self;
self = (LogObject *)type->tp_alloc(type, 0);
if (self != NULL) {
self->tstlog = 0;
}
return (PyObject *)self;
}
static PyObject *
Log_str(PyObject *self)
{
return PyUnicode_FromFormat("%s", ((LogObject *)self)->name);
}
static int
Log_init(LogObject *self, PyObject *args, PyObject *kwds)
{
char *name;
char *filename;
pwr_tStatus sts;
if (! PyArg_ParseTuple(args, "ss", &name, &filename))
return -1;
strncpy(self->name, name, sizeof(self->name));
self->tstlog = new tst_log(&sts, name, filename);
if (EVEN(sts)) {
set_error(sts);
return -1;
}
return 0;
}
static PyObject *
Log_log(LogObject *self, PyObject *args)
{
const char *str1;
const char *str2 = 0;
const char *severity;
if ( !PyArg_ParseTuple(args, "ss|s", &severity, &str1, &str2))
return NULL;
if (str2 == 0)
self->tstlog->log(severity[0], str1);
else
self->tstlog->log(severity[0], str1, str2);
Py_RETURN_NONE;
}
static PyObject *
Log_vlog(LogObject *self, PyObject *args)
{
const char *format;
const char *str1 = 0;
const char *str2 = 0;
const char *str3 = 0;
const char *str4 = 0;
const char *str5 = 0;
const char *severity;
if ( !PyArg_ParseTuple(args, "ss|sssss", &severity, &format,
&str1, &str2, &str3, &str4, &str5))
return NULL;
if (str1 == 0)
self->tstlog->vlog(severity[0], format);
else if (str2 == 0)
self->tstlog->vlog(severity[0], format, str1);
else if (str3 == 0)
self->tstlog->vlog(severity[0], format, str1, str2);
else if (str4 == 0)
self->tstlog->vlog(severity[0], format, str1, str2, str3);
else if (str5 == 0)
self->tstlog->vlog(severity[0], format, str1, str2, str3, str4);
else
self->tstlog->vlog(severity[0], format, str1, str2, str3, str4, str5);
Py_RETURN_NONE;
}
/**
* Static methods
*/
static PyObject *pwrtest_logger(PyObject *self, PyObject *args)
{
PyObject *o = Log_new(&LogType, args, 0);
Log_init((LogObject *)o, args, 0);
return o;
}
static PyMethodDef PwrtestMethods[] = {
{"logger", pwrtest_logger, METH_VARARGS, pwrtest_logger_doc},
{NULL, NULL, 0, NULL}};
PyMODINIT_FUNC initpwrtest(void)
{
PyObject *m;
if (PyType_Ready(&LogType) < 0)
return;
m = Py_InitModule3("pwrtest", PwrtestMethods, pwrtest_doc);
if (m == NULL)
return;
Py_INCREF(&LogType);
PyModule_AddObject(m, "Log", (PyObject *)&LogType);
PyModule_AddIntConstant(m, "FRAME_OPTIONS_CONDITION", 1);
PyDateTime_IMPORT;
}
from distutils.core import setup, Extension
import os
pwr_lib = os.environ['pwr_lib']
pwr_obj = os.environ['pwr_obj']
pwr_inc = os.environ['pwr_inc']
pwr_elib = os.environ['pwr_elib']
pwr_eobj = os.environ['pwr_eobj']
pwr_einc = os.environ['pwr_einc']
pwrtestmodule = Extension( name='pwrtest',
sources=['pwrtestmodule.cpp'],
define_macros=[('OS_POSIX', '1'),
('OS','linux'),
('HW_X86', '1'),
('HW', 'x86')],
extra_compile_args=['-g', '-O0'],
extra_link_args=['-O0'],
extra_objects=[pwr_eobj + '/pwr_msg_co.o',
pwr_eobj + '/pwr_msg_rt.o'],
include_dirs=[pwr_inc,pwr_einc],
library_dirs=[pwr_lib,pwr_elib],
libraries=['pwr_rt','pwr_co','pwr_msg_dummy','pthread',
'rt', 'm', 'crypt'],
language='c++'
)
setup( name='pwrtest',
version='1.0',
url='www.proview.se',
author='ProviewR development team',
author_email='support@proview.se',
license='GPL V2',
description='ProviewR runtime interface',
ext_modules=[pwrtestmodule])
......@@ -35,12 +35,12 @@ silent :
.SUFFIXES:
$(exe_dir)/pwrwb.so : pwrwbmodule.cpp
@ if [ $(PWRE_CONF_PYDEV) -eq 1 ]; then\
@ if [ "$(PWRE_CONF_PYDEV)" = "1" ]; then\
echo "Bulding Python c extension pwrwb";\
python setup_pwrwb.py -q build --build-base $(bld_dir);\
if [ "$(pwre_hw)" == "hw_x86_64" ]; then \
if [ "$(pwre_hw)" = "hw_x86_64" ]; then \
mv $(bld_dir)/lib.linux-x86_64-2.7/pwrwb.so $(pwr_exe); \
elif [ "$(pwre_hw)" == "hw_x86" ]; then \
elif [ "$(pwre_hw)" = "hw_x86" ]; then \
mv $(bld_dir)/lib.linux-i686-2.7/pwrwb.so $(pwr_exe); \
fi;\
python setup_pwrwb.py -q install_egg_info --install-dir $(pwr_exe);\
......
......@@ -1928,12 +1928,12 @@ Aref_value(PyObject *s, PyObject *args)
case pwr_eType_Float32: {
pwr_tFloat32 value = *(pwr_tFloat32 *)buf;
free(buf);
return Py_BuildValue("d", value);
return Py_BuildValue("f", value);
}
case pwr_eType_Float64: {
pwr_tFloat64 value = *(pwr_tFloat64 *)buf;
free(buf);
return Py_BuildValue("D", value);
return Py_BuildValue("d", value);
}
case pwr_eType_String: {
PyObject *ret = Py_BuildValue("s", buf);
......@@ -2073,7 +2073,7 @@ Aref_setValue(PyObject *s, PyObject *args)
break;
}
case pwr_eType_Float64: {
if ( !PyArg_ParseTuple(args, "D", buf))
if ( !PyArg_ParseTuple(args, "d", buf))
goto error_return;
break;
}
......
......@@ -12,24 +12,32 @@ except:
pwre_conf_qt = ""
if pwre_conf_qt == "1":
libs = ['pwr_wb_gtk', 'pwr_xtt_gtk', 'pwr_ge_gtk', 'pwr_cow_gtk',
'pwr_flow_gtk', 'pwr_glow_gtk',
libs = ['pwr_wb_qt', 'pwr_xtt_qt', 'pwr_ge_qt', 'pwr_cow_qt',
'pwr_flow_qt', 'pwr_glow_qt',
'pwr_wb', 'pwr_xtt', 'pwr_ge', 'pwr_cow', 'pwr_flow', 'pwr_glow',
'pwr_wb_gtk', 'pwr_xtt_gtk', 'pwr_ge_gtk', 'pwr_cow_gtk', 'pwr_flow_gtk', 'pwr_glow_gtk',
'pwr_wb_qt', 'pwr_xtt_qt', 'pwr_ge_qt', 'pwr_cow_qt', 'pwr_flow_qt', 'pwr_glow_qt',
'pwr_wb', 'pwr_xtt', 'pwr_ge', 'pwr_cow',
'pwr_flow', 'pwr_glow',
'pwr_rt', 'pwr_statussrv', 'pwr_co', 'pwr_msg_dummy']
xlibs = ['gtk-x11-2.0']
xlibs = ['QtCore', 'QtGui']
else:
libs = ['pwr_wb_qt', 'pwr_xtt_qt', 'pwr_ge_qt', 'pwr_cow_qt',
'pwr_flow_qt', 'pwr_glow_qt',
libs = ['pwr_wb_gtk', 'pwr_xtt_gtk', 'pwr_ge_gtk', 'pwr_cow_gtk',
'pwr_flow_gtk', 'pwr_glow_gtk',
'pwr_wb', 'pwr_xtt', 'pwr_ge', 'pwr_cow', 'pwr_flow', 'pwr_glow',
'pwr_wb_qt', 'pwr_xtt_qt', 'pwr_ge_qt', 'pwr_cow_qt', 'pwr_flow_qt', 'pwr_glow_qt',
'pwr_wb_gtk', 'pwr_xtt_gtk', 'pwr_ge_gtk', 'pwr_cow_gtk', 'pwr_flow_gtk', 'pwr_glow_gtk',
'pwr_wb', 'pwr_xtt', 'pwr_ge', 'pwr_cow',
'pwr_flow', 'pwr_glow',
'pwr_rt', 'pwr_statussrv', 'pwr_co', 'pwr_msg_dummy']
xlibs = ['QtCore', 'QtGui']
xlibs = ['gtk-x11-2.0']
try:
pwre_conf_mysql = os.environ['PWRE_CONF_MYSQL']
except:
pwre_conf_mysql = ""
if pwre_conf_mysql == "1":
mysqllibs = ['mysqlclient']
else:
mysqllibs = []
pwrwbmodule = Extension( name='pwrwb',
sources=['pwrwbmodule.cpp'],
define_macros=[('OS_POSIX', '1'),
......@@ -46,8 +54,8 @@ pwrwbmodule = Extension( name='pwrwb',
library_dirs=[pwr_lib],
libraries=libs +
['db_cxx', 'rpcsvc', 'asound', 'pthread',
'm', 'db', 'z', 'crypt', 'rt', 'fl', 'X11', 'mysqlclient',
'sqlite3', 'rsvg-2', 'QtCore', 'QtGui'] + xlibs,
'm', 'db', 'z', 'crypt', 'rt', 'X11',
'sqlite3', 'rsvg-2'] + xlibs + mysqllibs,
# extra_link_args=['-L/usr/lib/x86_64-linux-gnu', commands.getoutput('pkg-config --libs gtk+-2.0')],
language='c++'
)
......
......@@ -6172,6 +6172,41 @@ static int xnav_delete_func(void* client_data, void* client_flag)
sts = xnav->delete_object(name_str);
return sts;
} else if (str_NoCaseStrncmp(arg1_str, "TREE", strlen(arg1_str)) == 0) {
// Command is "DELETE TREE"
char name_str[80];
pwr_tObjid objid;
IF_NOGDH_RETURN;
// Check authorization
if (!((xnav->priv & pwr_mPrv_RtWrite) || (xnav->priv & pwr_mPrv_System))) {
xnav->message('E', "Not authorized for this operation");
return 0;
}
if (EVEN(dcli_get_qualifier("/NAME", name_str, sizeof(name_str)))) {
xnav->message('E', "Enter name");
return XNAV__HOLDCOMMAND;
}
/* Get objid for the object */
sts = gdh_NameToObjid(name_str, &objid);
if (EVEN(sts)) {
xnav->message('E', "Object does not exist");
return XNAV__HOLDCOMMAND;
}
sts = gdh_DeleteObjectTree(objid);
if (EVEN(sts)) {
xnav->message('E', "Unable to delete object tree");
return XNAV__HOLDCOMMAND;
}
xnav->message('I', "Object deleted");
return XNAV__SUCCESS;
} else
xnav->message('E', "Syntax error");
......@@ -8783,6 +8818,11 @@ int xnav_cut_segments(char* outname, char* name, int segments)
char* s[20];
int i, j, last_i = 0;
if (segments == 0) {
strcpy(outname, "");
return 1;
}
for (i = 0; i < segments; i++) {
s[i] = strrchr(name, '-');
if (s[i] == 0) {
......@@ -8938,7 +8978,7 @@ static int xnav_attribute_func(char* name, int* return_decl,
if (EVEN(sts))
strcpy(string_val, "Undefined Object");
else
strncpy(string_val, object_element, sizeof(string_val));
strncpy(string_val, hier_name, sizeof(string_val));
string_val[sizeof(string_val) - 1] = 0;
decl = CCM_DECL_STRING;
break;
......@@ -8965,6 +9005,13 @@ static int xnav_attribute_func(char* name, int* return_decl,
decl = CCM_DECL_STRING;
break;
}
case pwr_eType_DeltaTime: {
/* Convert time to ascii */
sts = time_DtoAscii((pwr_tDeltaTime*)object_element, 1,
string_val, sizeof(string_val));
decl = CCM_DECL_STRING;
break;
}
}
*return_decl = decl;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment