add function to dispatch LAMMPS errors to library interfaces
This commit is contained in:
@ -128,7 +128,7 @@ version of the previous example:
|
|||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
Executing LAMMPS commands
|
Executing LAMMPS commands
|
||||||
=========================
|
*************************
|
||||||
|
|
||||||
Once a LAMMPS instance is created, it is possible to "drive" the LAMMPS
|
Once a LAMMPS instance is created, it is possible to "drive" the LAMMPS
|
||||||
simulation by telling LAMMPS to read commands from a file or to pass
|
simulation by telling LAMMPS to read commands from a file or to pass
|
||||||
@ -177,7 +177,7 @@ Below is a small demonstration of the uses of the different functions:
|
|||||||
---------------
|
---------------
|
||||||
|
|
||||||
Accessing system properties
|
Accessing system properties
|
||||||
===========================
|
***************************
|
||||||
|
|
||||||
The C-library interface allows the :doc:`extraction of different kinds
|
The C-library interface allows the :doc:`extraction of different kinds
|
||||||
of information <Library_properties>` about the active simulation
|
of information <Library_properties>` about the active simulation
|
||||||
@ -241,6 +241,7 @@ of the contents of the ``LIBLAMMPS`` Fortran interface to LAMMPS.
|
|||||||
|
|
||||||
:f c_ptr handle: reference to the LAMMPS class
|
:f c_ptr handle: reference to the LAMMPS class
|
||||||
:f subroutine close: :f:func:`close`
|
:f subroutine close: :f:func:`close`
|
||||||
|
:f subroutine error: :f:func:`error`
|
||||||
:f function version: :f:func:`version`
|
:f function version: :f:func:`version`
|
||||||
:f subroutine file: :f:func:`file`
|
:f subroutine file: :f:func:`file`
|
||||||
:f subroutine command: :f:func:`command`
|
:f subroutine command: :f:func:`command`
|
||||||
@ -305,6 +306,18 @@ Procedures Bound to the lammps Derived Type
|
|||||||
|
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
.. f:subroutine:: error(error_type, error_text)
|
||||||
|
|
||||||
|
This method is a wrapper around the :cpp:func:`lammps_error` function and will dispatch
|
||||||
|
an error through the LAMMPS Error class.
|
||||||
|
|
||||||
|
.. versionadded:: TBD
|
||||||
|
|
||||||
|
:p integer error_type: constant to select which Error class function to call
|
||||||
|
:p character(len=\*) error_text: error message
|
||||||
|
|
||||||
|
--------
|
||||||
|
|
||||||
.. f:function:: version()
|
.. f:function:: version()
|
||||||
|
|
||||||
This method returns the numeric LAMMPS version like :cpp:func:`lammps_version`
|
This method returns the numeric LAMMPS version like :cpp:func:`lammps_version`
|
||||||
|
|||||||
@ -11,6 +11,7 @@ This section documents the following functions:
|
|||||||
- :cpp:func:`lammps_mpi_finalize`
|
- :cpp:func:`lammps_mpi_finalize`
|
||||||
- :cpp:func:`lammps_kokkos_finalize`
|
- :cpp:func:`lammps_kokkos_finalize`
|
||||||
- :cpp:func:`lammps_python_finalize`
|
- :cpp:func:`lammps_python_finalize`
|
||||||
|
- :cpp:func:`lammps_error`
|
||||||
|
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
@ -115,3 +116,8 @@ calling program.
|
|||||||
|
|
||||||
.. doxygenfunction:: lammps_python_finalize
|
.. doxygenfunction:: lammps_python_finalize
|
||||||
:project: progguide
|
:project: progguide
|
||||||
|
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
.. doxygenfunction:: lammps_error
|
||||||
|
:project: progguide
|
||||||
|
|||||||
@ -56,6 +56,7 @@ MODULE LIBLAMMPS
|
|||||||
TYPE(c_ptr) :: handle
|
TYPE(c_ptr) :: handle
|
||||||
CONTAINS
|
CONTAINS
|
||||||
PROCEDURE :: close => lmp_close
|
PROCEDURE :: close => lmp_close
|
||||||
|
PROCEDURE :: error => lmp_error
|
||||||
PROCEDURE :: file => lmp_file
|
PROCEDURE :: file => lmp_file
|
||||||
PROCEDURE :: command => lmp_command
|
PROCEDURE :: command => lmp_command
|
||||||
PROCEDURE :: commands_list => lmp_commands_list
|
PROCEDURE :: commands_list => lmp_commands_list
|
||||||
@ -144,6 +145,14 @@ MODULE LIBLAMMPS
|
|||||||
SUBROUTINE lammps_kokkos_finalize() BIND(C)
|
SUBROUTINE lammps_kokkos_finalize() BIND(C)
|
||||||
END SUBROUTINE lammps_kokkos_finalize
|
END SUBROUTINE lammps_kokkos_finalize
|
||||||
|
|
||||||
|
SUBROUTINE lammps_error(handle, error_type, error_text) BIND(C)
|
||||||
|
IMPORT :: c_ptr, c_int
|
||||||
|
IMPLICIT NONE
|
||||||
|
TYPE(c_ptr), VALUE :: handle
|
||||||
|
INTEGER(c_int), VALUE :: error_type
|
||||||
|
TYPE(c_ptr), VALUE :: error_text
|
||||||
|
END SUBROUTINE lammps_error
|
||||||
|
|
||||||
SUBROUTINE lammps_file(handle, filename) BIND(C)
|
SUBROUTINE lammps_file(handle, filename) BIND(C)
|
||||||
IMPORT :: c_ptr
|
IMPORT :: c_ptr
|
||||||
IMPLICIT NONE
|
IMPLICIT NONE
|
||||||
@ -417,6 +426,18 @@ CONTAINS
|
|||||||
END IF
|
END IF
|
||||||
END SUBROUTINE lmp_close
|
END SUBROUTINE lmp_close
|
||||||
|
|
||||||
|
! equivalent function to lammps_error()
|
||||||
|
SUBROUTINE lmp_error(self, error_type, error_text)
|
||||||
|
CLASS(lammps) :: self
|
||||||
|
INTEGER :: error_type
|
||||||
|
CHARACTER(len=*) :: error_text
|
||||||
|
TYPE(c_ptr) :: str
|
||||||
|
|
||||||
|
str = f2c_string(error_text)
|
||||||
|
CALL lammps_error(self%handle, error_type, str)
|
||||||
|
CALL lammps_free(str)
|
||||||
|
END SUBROUTINE lmp_error
|
||||||
|
|
||||||
! equivalent function to lammps_file()
|
! equivalent function to lammps_file()
|
||||||
SUBROUTINE lmp_file(self, filename)
|
SUBROUTINE lmp_file(self, filename)
|
||||||
CLASS(lammps) :: self
|
CLASS(lammps) :: self
|
||||||
@ -492,7 +513,7 @@ CONTAINS
|
|||||||
END FUNCTION lmp_get_thermo
|
END FUNCTION lmp_get_thermo
|
||||||
|
|
||||||
! equivalent subroutine to lammps_extract_box
|
! equivalent subroutine to lammps_extract_box
|
||||||
SUBROUTINE lmp_extract_box (self, boxlo, boxhi, xy, yz, xz, pflags, boxflag)
|
SUBROUTINE lmp_extract_box(self, boxlo, boxhi, xy, yz, xz, pflags, boxflag)
|
||||||
CLASS(lammps), INTENT(IN) :: self
|
CLASS(lammps), INTENT(IN) :: self
|
||||||
REAL(c_double), INTENT(OUT), TARGET, OPTIONAL :: boxlo(3), boxhi(3)
|
REAL(c_double), INTENT(OUT), TARGET, OPTIONAL :: boxlo(3), boxhi(3)
|
||||||
REAL(c_double), INTENT(OUT), TARGET, OPTIONAL :: xy, yz, xz
|
REAL(c_double), INTENT(OUT), TARGET, OPTIONAL :: xy, yz, xz
|
||||||
@ -515,11 +536,11 @@ CONTAINS
|
|||||||
END SUBROUTINE lmp_extract_box
|
END SUBROUTINE lmp_extract_box
|
||||||
|
|
||||||
! equivalent function to lammps_reset_box
|
! equivalent function to lammps_reset_box
|
||||||
SUBROUTINE lmp_reset_box (self, boxlo, boxhi, xy, yz, xz)
|
SUBROUTINE lmp_reset_box(self, boxlo, boxhi, xy, yz, xz)
|
||||||
CLASS(lammps), INTENT(IN) :: self
|
CLASS(lammps), INTENT(IN) :: self
|
||||||
REAL(C_double), INTENT(IN) :: boxlo(3), boxhi(3), xy, yz, xz
|
REAL(C_double), INTENT(IN) :: boxlo(3), boxhi(3), xy, yz, xz
|
||||||
|
|
||||||
CALL lammps_reset_box (self%handle, boxlo, boxhi, xy, yz, xz)
|
CALL lammps_reset_box(self%handle, boxlo, boxhi, xy, yz, xz)
|
||||||
END SUBROUTINE lmp_reset_box
|
END SUBROUTINE lmp_reset_box
|
||||||
|
|
||||||
! equivalent function to lammps_memory_usage
|
! equivalent function to lammps_memory_usage
|
||||||
@ -532,14 +553,14 @@ CONTAINS
|
|||||||
END SUBROUTINE lmp_memory_usage
|
END SUBROUTINE lmp_memory_usage
|
||||||
|
|
||||||
! equivalent function to lammps_get_mpi_comm
|
! equivalent function to lammps_get_mpi_comm
|
||||||
INTEGER FUNCTION lmp_get_mpi_comm (self)
|
INTEGER FUNCTION lmp_get_mpi_comm(self)
|
||||||
CLASS(lammps), INTENT(IN) :: self
|
CLASS(lammps), INTENT(IN) :: self
|
||||||
|
|
||||||
lmp_get_mpi_comm = lammps_get_mpi_comm(self%handle)
|
lmp_get_mpi_comm = lammps_get_mpi_comm(self%handle)
|
||||||
END FUNCTION lmp_get_mpi_comm
|
END FUNCTION lmp_get_mpi_comm
|
||||||
|
|
||||||
! equivalent function to lammps_extract_setting
|
! equivalent function to lammps_extract_setting
|
||||||
INTEGER (c_int) FUNCTION lmp_extract_setting (self, keyword)
|
INTEGER (c_int) FUNCTION lmp_extract_setting(self, keyword)
|
||||||
CLASS(lammps), INTENT(IN) :: self
|
CLASS(lammps), INTENT(IN) :: self
|
||||||
CHARACTER(LEN=*), INTENT(IN) :: keyword
|
CHARACTER(LEN=*), INTENT(IN) :: keyword
|
||||||
TYPE(c_ptr) :: Ckeyword
|
TYPE(c_ptr) :: Ckeyword
|
||||||
@ -549,22 +570,10 @@ CONTAINS
|
|||||||
CALL lammps_free(Ckeyword)
|
CALL lammps_free(Ckeyword)
|
||||||
END FUNCTION lmp_extract_setting
|
END FUNCTION lmp_extract_setting
|
||||||
|
|
||||||
! FIXME Do we need this to be visible to the user?
|
|
||||||
! ! equivalent function to lammps_extract_global_datatype
|
|
||||||
! INTEGER (c_int) FUNCTION lmp_extract_global_datatype (name)
|
|
||||||
! CHARACTER(LEN=*), INTENT(IN) :: name
|
|
||||||
! TYPE(c_ptr) :: Cname
|
|
||||||
!
|
|
||||||
! Cname = f2c_string(name)
|
|
||||||
! lmp_extract_global_datatype
|
|
||||||
! = lammps_extract_global_datatype(c_null_ptr, Cname)
|
|
||||||
! CALL lammps_free(Cname)
|
|
||||||
! END FUNCTION lmp_extract_global_datatype
|
|
||||||
|
|
||||||
! equivalent function to lammps_extract_global
|
! equivalent function to lammps_extract_global
|
||||||
! the assignment is actually overloaded so as to bind the pointers to
|
! the assignment is actually overloaded so as to bind the pointers to
|
||||||
! lammps data based on the information available from LAMMPS
|
! lammps data based on the information available from LAMMPS
|
||||||
FUNCTION lmp_extract_global (self, name) RESULT (global_data)
|
FUNCTION lmp_extract_global(self, name) RESULT (global_data)
|
||||||
CLASS(lammps), INTENT(IN) :: self
|
CLASS(lammps), INTENT(IN) :: self
|
||||||
CHARACTER(LEN=*), INTENT(IN) :: name
|
CHARACTER(LEN=*), INTENT(IN) :: name
|
||||||
TYPE(lammps_data) :: global_data
|
TYPE(lammps_data) :: global_data
|
||||||
@ -625,10 +634,9 @@ CONTAINS
|
|||||||
FORALL ( I=1:length )
|
FORALL ( I=1:length )
|
||||||
global_data%str(i:i) = Fptr(i)
|
global_data%str(i:i) = Fptr(i)
|
||||||
END FORALL
|
END FORALL
|
||||||
CASE DEFAULT
|
CASE DEFAULT
|
||||||
WRITE(ERROR_UNIT,'(A)') 'ERROR: Unknown pointer type in&
|
! FIXME convert to use symbolic constants later
|
||||||
& extract_global'
|
CALL lmp_error(self, 6, 'Unknown pointer type in extract_global')
|
||||||
STOP 2
|
|
||||||
END SELECT
|
END SELECT
|
||||||
END FUNCTION
|
END FUNCTION
|
||||||
|
|
||||||
|
|||||||
@ -13,29 +13,35 @@
|
|||||||
|
|
||||||
# various symbolic constants to be used
|
# various symbolic constants to be used
|
||||||
# in certain calls to select data formats
|
# in certain calls to select data formats
|
||||||
LAMMPS_AUTODETECT = None
|
LAMMPS_AUTODETECT = None
|
||||||
LAMMPS_INT = 0
|
LAMMPS_INT = 0
|
||||||
LAMMPS_INT_2D = 1
|
LAMMPS_INT_2D = 1
|
||||||
LAMMPS_DOUBLE = 2
|
LAMMPS_DOUBLE = 2
|
||||||
LAMMPS_DOUBLE_2D = 3
|
LAMMPS_DOUBLE_2D = 3
|
||||||
LAMMPS_INT64 = 4
|
LAMMPS_INT64 = 4
|
||||||
LAMMPS_INT64_2D = 5
|
LAMMPS_INT64_2D = 5
|
||||||
LAMMPS_STRING = 6
|
LAMMPS_STRING = 6
|
||||||
|
|
||||||
# these must be kept in sync with the enums in library.h
|
# these must be kept in sync with the enums in library.h
|
||||||
LMP_STYLE_GLOBAL = 0
|
LMP_STYLE_GLOBAL = 0
|
||||||
LMP_STYLE_ATOM = 1
|
LMP_STYLE_ATOM = 1
|
||||||
LMP_STYLE_LOCAL = 2
|
LMP_STYLE_LOCAL = 2
|
||||||
|
|
||||||
LMP_TYPE_SCALAR = 0
|
LMP_TYPE_SCALAR = 0
|
||||||
LMP_TYPE_VECTOR = 1
|
LMP_TYPE_VECTOR = 1
|
||||||
LMP_TYPE_ARRAY = 2
|
LMP_TYPE_ARRAY = 2
|
||||||
LMP_SIZE_VECTOR = 3
|
LMP_SIZE_VECTOR = 3
|
||||||
LMP_SIZE_ROWS = 4
|
LMP_SIZE_ROWS = 4
|
||||||
LMP_SIZE_COLS = 5
|
LMP_SIZE_COLS = 5
|
||||||
|
|
||||||
LMP_VAR_EQUAL = 0
|
LMP_ERROR_WARNING = 0
|
||||||
LMP_VAR_ATOM = 1
|
LMP_ERROR_ONE = 1
|
||||||
|
LMP_ERROR_ALL = 2
|
||||||
|
LMP_ERROR_WORLD = 4
|
||||||
|
LMP_ERROR_UNIVERSE = 8
|
||||||
|
|
||||||
|
LMP_VAR_EQUAL = 0
|
||||||
|
LMP_VAR_ATOM = 1
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@ -167,6 +167,8 @@ class lammps(object):
|
|||||||
self.lib.lammps_flush_buffers.argtypes = [c_void_p]
|
self.lib.lammps_flush_buffers.argtypes = [c_void_p]
|
||||||
self.lib.lammps_free.argtypes = [c_void_p]
|
self.lib.lammps_free.argtypes = [c_void_p]
|
||||||
|
|
||||||
|
self.lib.lammps_error.argtypes = [c_void_p, c_int, c_char_p]
|
||||||
|
|
||||||
self.lib.lammps_file.argtypes = [c_void_p, c_char_p]
|
self.lib.lammps_file.argtypes = [c_void_p, c_char_p]
|
||||||
self.lib.lammps_file.restype = None
|
self.lib.lammps_file.restype = None
|
||||||
|
|
||||||
@ -486,6 +488,26 @@ class lammps(object):
|
|||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def error(self, error_type, error_text):
|
||||||
|
"""Forward error to the LAMMPS Error class.
|
||||||
|
|
||||||
|
This is a wrapper around the :cpp:func:`lammps_error` function of the C-library interface.
|
||||||
|
|
||||||
|
.. versionadded:: TBD
|
||||||
|
|
||||||
|
:param error_type:
|
||||||
|
:type error_type: int
|
||||||
|
:param error_text:
|
||||||
|
:type error_text: string
|
||||||
|
"""
|
||||||
|
if error_text: error_text = error_text.encode()
|
||||||
|
else: error_text = "(unknown error)".encode()
|
||||||
|
|
||||||
|
with ExceptionCheck(self):
|
||||||
|
self.lib.lammps_error(self.lmp, error_type, error_text)
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
def version(self):
|
def version(self):
|
||||||
"""Return a numerical representation of the LAMMPS version in use.
|
"""Return a numerical representation of the LAMMPS version in use.
|
||||||
|
|
||||||
|
|||||||
@ -416,6 +416,89 @@ void lammps_python_finalize()
|
|||||||
Python::finalize();
|
Python::finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/** Call a LAMMPS Error class function
|
||||||
|
*
|
||||||
|
\verbatim embed:rst
|
||||||
|
|
||||||
|
This function is a wrapper around functions in the ``Error`` to print an
|
||||||
|
error message and then stop LAMMPS.
|
||||||
|
|
||||||
|
The *error_type* parameter selects which function to call. It is a sum
|
||||||
|
of constants from :cpp:enum:`_LMP_ERROR_CONST`. If the value does not
|
||||||
|
match any valid combination of constants a warning is printed and the
|
||||||
|
function returns.
|
||||||
|
|
||||||
|
.. versionadded:: TBD
|
||||||
|
|
||||||
|
\endverbatim
|
||||||
|
*
|
||||||
|
* \param handle pointer to a previously created LAMMPS instance
|
||||||
|
* \param error_type parameter to select function in the Error class
|
||||||
|
* \param error_text error message */
|
||||||
|
|
||||||
|
void lammps_error(void *handle, int error_type, const char *error_text)
|
||||||
|
{
|
||||||
|
auto lmp = (LAMMPS *) handle;
|
||||||
|
|
||||||
|
BEGIN_CAPTURE
|
||||||
|
{
|
||||||
|
switch (error_type) {
|
||||||
|
case LMP_ERROR_WARNING:
|
||||||
|
lmp->error->warning("(library)", 0, error_text);
|
||||||
|
break;
|
||||||
|
case LMP_ERROR_ONE:
|
||||||
|
lmp->error->one("(library)", 0, error_text);
|
||||||
|
break;
|
||||||
|
case LMP_ERROR_ALL:
|
||||||
|
lmp->error->all("(library)", 0, error_text);
|
||||||
|
break;
|
||||||
|
case LMP_ERROR_WARNING|LMP_ERROR_WORLD:
|
||||||
|
lmp->error->warning("(library)", 0, error_text);
|
||||||
|
break;
|
||||||
|
case LMP_ERROR_ONE|LMP_ERROR_WORLD:
|
||||||
|
lmp->error->one("(library)", 0, error_text);
|
||||||
|
break;
|
||||||
|
case LMP_ERROR_ALL|LMP_ERROR_WORLD:
|
||||||
|
lmp->error->all("(library)", 0, error_text);
|
||||||
|
break;
|
||||||
|
case LMP_ERROR_WARNING|LMP_ERROR_UNIVERSE:
|
||||||
|
lmp->error->universe_warn("(library)", 0, error_text);
|
||||||
|
break;
|
||||||
|
case LMP_ERROR_ONE|LMP_ERROR_UNIVERSE:
|
||||||
|
lmp->error->universe_one("(library)", 0, error_text);
|
||||||
|
break;
|
||||||
|
case LMP_ERROR_ALL|LMP_ERROR_UNIVERSE:
|
||||||
|
lmp->error->universe_all("(library)", 0, error_text);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
auto mesg = fmt::format("Unknown error type {} for message: {}", error_type, error_text);
|
||||||
|
lmp->error->warning("(library)", 0, mesg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END_CAPTURE
|
||||||
|
|
||||||
|
#if defined(LAMMPS_EXCEPTIONS)
|
||||||
|
// with enabled exceptions the above code will simply throw an
|
||||||
|
// exception and record the error message. So we have to explicitly
|
||||||
|
// stop here like we do in main.cpp
|
||||||
|
if (lammps_has_error(handle)) {
|
||||||
|
if (error_type & 1) {
|
||||||
|
lammps_kokkos_finalize();
|
||||||
|
lammps_python_finalize();
|
||||||
|
MPI_Abort(lmp->universe->uworld, 1);
|
||||||
|
} else if (error_type & 2) {
|
||||||
|
lammps_kokkos_finalize();
|
||||||
|
lammps_python_finalize();
|
||||||
|
lammps_mpi_finalize();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
// Library functions to process commands
|
// Library functions to process commands
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|||||||
@ -75,6 +75,18 @@ enum _LMP_TYPE_CONST {
|
|||||||
LMP_SIZE_COLS = 5 /*!< return number of columns */
|
LMP_SIZE_COLS = 5 /*!< return number of columns */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Error codes to select the suitable function in the Error class
|
||||||
|
*
|
||||||
|
* Must be kept in sync with the equivalent constants in lammps/constants.py */
|
||||||
|
|
||||||
|
enum _LMP_ERROR_CONST {
|
||||||
|
LMP_ERROR_WARNING = 0, /*!< call Error::warning() */
|
||||||
|
LMP_ERROR_ONE = 1, /*!< called from one MPI rank */
|
||||||
|
LMP_ERROR_ALL = 2, /*!< called from all MPI ranks */
|
||||||
|
LMP_ERROR_WORLD = 4, /*!< error on Comm::world */
|
||||||
|
LMP_ERROR_UNIVERSE = 8 /*!< error on Comm::universe */
|
||||||
|
};
|
||||||
|
|
||||||
/* Ifdefs to allow this file to be included in C and C++ programs */
|
/* Ifdefs to allow this file to be included in C and C++ programs */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@ -97,6 +109,8 @@ void lammps_mpi_finalize();
|
|||||||
void lammps_kokkos_finalize();
|
void lammps_kokkos_finalize();
|
||||||
void lammps_python_finalize();
|
void lammps_python_finalize();
|
||||||
|
|
||||||
|
void lammps_error(void *handle, int error_type, const char *error_text);
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
/* ----------------------------------------------------------------------
|
||||||
* Library functions to process commands
|
* Library functions to process commands
|
||||||
* ---------------------------------------------------------------------- */
|
* ---------------------------------------------------------------------- */
|
||||||
|
|||||||
Reference in New Issue
Block a user