Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
OpenXG-RAN
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
zzha zzha
OpenXG-RAN
Commits
79b85864
Commit
79b85864
authored
Mar 29, 2022
by
frtabu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
config module enhancement (dump of running config): start implem.
parent
9301d8a7
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
200 additions
and
15 deletions
+200
-15
common/config/config_load_configmodule.c
common/config/config_load_configmodule.c
+29
-5
common/config/config_load_configmodule.h
common/config/config_load_configmodule.h
+3
-0
common/config/config_userapi.c
common/config/config_userapi.c
+6
-1
common/config/libconfig/config_libconfig.c
common/config/libconfig/config_libconfig.c
+131
-2
common/config/libconfig/config_libconfig.h
common/config/libconfig/config_libconfig.h
+1
-0
common/utils/telnetsrv/telnetsrv.c
common/utils/telnetsrv/telnetsrv.c
+3
-2
common/utils/telnetsrv/telnetsrv_proccmd.c
common/utils/telnetsrv/telnetsrv_proccmd.c
+9
-2
common/utils/websrv/websrv.c
common/utils/websrv/websrv.c
+1
-1
executables/softmodem-common.c
executables/softmodem-common.c
+1
-0
openair1/SIMULATION/TOOLS/random_channel.c
openair1/SIMULATION/TOOLS/random_channel.c
+7
-2
targets/ARCH/rfsimulator/simulator.c
targets/ARCH/rfsimulator/simulator.c
+9
-0
No files found.
common/config/config_load_configmodule.c
View file @
79b85864
...
...
@@ -88,10 +88,21 @@ int load_config_sharedlib(configmodule_interface_t *cfgptr) {
st
=
-
1
;
}
if
(
cfgptr
->
rtflags
&
CONFIG_SAVERUNCFG
)
{
sprintf
(
fname
,
"config_%s_set"
,
cfgptr
->
cfgmode
);
cfgptr
->
set
=
dlsym
(
lib_handle
,
fname
);
if
(
cfgptr
->
set
==
NULL
)
{
printf
(
"[CONFIG] %s %d no function %s for config mode %s
\n
"
,
__FILE__
,
__LINE__
,
fname
,
cfgptr
->
cfgmode
);
st
=
-
1
;
}
}
sprintf
(
fname
,
"config_%s_end"
,
cfgptr
->
cfgmode
);
cfgptr
->
end
=
dlsym
(
lib_handle
,
fname
);
if
(
cfgptr
->
getlist
==
NULL
)
{
if
(
cfgptr
->
end
==
NULL
)
{
printf
(
"[CONFIG] %s %d no function %s for config mode %s
\n
"
,
__FILE__
,
__LINE__
,
fname
,
cfgptr
->
cfgmode
);
}
...
...
@@ -186,6 +197,7 @@ configmodule_interface_t *load_configmodule(int argc,
uint32_t
initflags
)
{
char
*
cfgparam
=
NULL
;
char
*
modeparams
=
NULL
;
char
*
cfgmode
=
NULL
;
char
*
strtokctx
=
NULL
;
...
...
@@ -193,7 +205,8 @@ configmodule_interface_t *load_configmodule(int argc,
uint32_t
tmpflags
=
0
;
int
i
;
int
OoptIdx
=-
1
;
int
OWoptIdx
=-
1
;
printf
(
"CMDLINE: "
);
for
(
int
i
=
0
;
i
<
argc
;
i
++
)
printf
(
"
\"
%s
\"
"
,
argv
[
i
]);
...
...
@@ -208,7 +221,11 @@ configmodule_interface_t *load_configmodule(int argc,
cfgparam
=
argv
[
i
+
1
];
OoptIdx
=
i
;
}
char
*
OWopt
=
strstr
(
argv
[
i
],
"OW"
);
if
(
OWopt
==
argv
[
i
]
+
2
)
{
OWoptIdx
=
i
;
}
if
(
strstr
(
argv
[
i
],
"help_config"
)
!=
NULL
)
{
config_printhelp
(
Config_Params
,
CONFIG_PARAMLENGTH
(
Config_Params
),
CONFIG_SECTIONNAME
);
exit
(
0
);
...
...
@@ -258,6 +275,11 @@ configmodule_interface_t *load_configmodule(int argc,
/* argv[0] is the exec name, always Ok */
cfgptr
->
argv_info
[
0
]
|=
CONFIG_CMDLINEOPT_PROCESSED
;
/* a file with config parameters as defined after all processing will be created */
if
(
OWoptIdx
>=
0
)
{
cfgptr
->
argv_info
[
OWoptIdx
]
|=
CONFIG_CMDLINEOPT_PROCESSED
;
cfgptr
->
rtflags
|=
CONFIG_SAVERUNCFG
;
}
/* when OoptIdx is >0, -O option has been detected at position OoptIdx
* we must memorize arv[OoptIdx is Ok */
if
(
OoptIdx
>=
0
)
{
...
...
@@ -294,7 +316,6 @@ configmodule_interface_t *load_configmodule(int argc,
printf
(
"%s "
,
cfgptr
->
cfgP
[
i
]);
}
printf
(
", debug flags: 0x%08x
\n
"
,
cfgptr
->
rtflags
);
if
(
strstr
(
cfgparam
,
CONFIG_CMDLINEONLY
)
==
NULL
)
{
i
=
load_config_sharedlib
(
cfgptr
);
...
...
@@ -313,7 +334,10 @@ configmodule_interface_t *load_configmodule(int argc,
cfgptr
->
getlist
=
config_cmdlineonly_getlist
;
cfgptr
->
end
=
(
configmodule_endfunc_t
)
nooptfunc
;
}
printf
(
"[CONFIG] debug flags: 0x%08x
\n
"
,
cfgptr
->
rtflags
);
if
(
modeparams
!=
NULL
)
free
(
modeparams
);
if
(
cfgmode
!=
NULL
)
free
(
cfgmode
);
...
...
common/config/config_load_configmodule.h
View file @
79b85864
...
...
@@ -54,6 +54,7 @@
#define CONFIG_DEBUGPTR (1<<1) // print memory allocation/free debug messages
#define CONFIG_DEBUGCMDLINE (1<<2) // print command line processing messages
#define CONFIG_NOABORTONCHKF (1<<4) // disable abort execution when parameter checking function fails
#define CONFIG_SAVERUNCFG (1<<5) // create config file with running values, as after cfg file + command line processing
#define CONFIG_NOEXITONHELP (1<<19) // do not exit after printing help
#define CONFIG_HELP (1<<20) // print help message
#define CONFIG_ABORT (1<<21) // config failed,abort execution
...
...
@@ -61,6 +62,7 @@
typedef
int
(
*
configmodule_initfunc_t
)(
char
*
cfgP
[],
int
numP
);
typedef
int
(
*
configmodule_getfunc_t
)(
paramdef_t
*
,
int
numparams
,
char
*
prefix
);
typedef
int
(
*
configmodule_getlistfunc_t
)(
paramlist_def_t
*
,
paramdef_t
*
,
int
numparams
,
char
*
prefix
);
typedef
int
(
*
configmodule_setfunc_t
)(
paramdef_t
*
cfgoptions
,
int
numoptions
,
char
*
prefix
);
typedef
void
(
*
configmodule_endfunc_t
)(
void
);
typedef
struct
configmodule_interface
{
int
argc
;
...
...
@@ -72,6 +74,7 @@ typedef struct configmodule_interface {
configmodule_initfunc_t
init
;
configmodule_getfunc_t
get
;
configmodule_getlistfunc_t
getlist
;
configmodule_setfunc_t
set
;
configmodule_endfunc_t
end
;
uint32_t
numptrs
;
uint32_t
rtflags
;
...
...
common/config/config_userapi.c
View file @
79b85864
...
...
@@ -237,6 +237,9 @@ int config_get(paramdef_t *params, int numparams, char *prefix) {
if
(
ret
>=
0
)
{
config_process_cmdline
(
params
,
numparams
,
prefix
);
if
(
cfgif
->
rtflags
&
CONFIG_SAVERUNCFG
)
{
config_get_if
()
->
set
(
params
,
numparams
,
prefix
);
}
config_execcheck
(
params
,
numparams
,
prefix
);
}
...
...
@@ -271,9 +274,11 @@ int config_getlist(paramlist_def_t *ParamList, paramdef_t *params, int numparams
char
cfgpath
[
MAX_OPTNAME_SIZE
*
2
+
6
];
/* prefix.listname.[listindex] */
for
(
int
i
=
0
;
i
<
ParamList
->
numelt
;
++
i
)
{
// TODO config_process_cmdline?
sprintf
(
cfgpath
,
"%s.[%i]"
,
newprefix
,
i
);
config_process_cmdline
(
ParamList
->
paramarray
[
i
],
numparams
,
cfgpath
);
if
(
config_get_if
()
->
rtflags
&
CONFIG_SAVERUNCFG
)
{
config_get_if
()
->
set
(
ParamList
->
paramarray
[
i
],
numparams
,
cfgpath
);
}
config_execcheck
(
ParamList
->
paramarray
[
i
],
numparams
,
cfgpath
);
}
...
...
common/config/libconfig/config_libconfig.c
View file @
79b85864
...
...
@@ -34,7 +34,8 @@
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <libgen.h>
#include <time.h>
#include <libgen.h>
#include "config_libconfig.h"
...
...
@@ -87,8 +88,115 @@ int read_intarray(paramdef_t *cfgoptions,config_setting_t *setting, char *cfgpat
return
cfgoptions
->
numelt
;
}
int
config_libconfig_setparams
(
paramdef_t
*
cfgoptions
,
int
numoptions
,
config_setting_t
*
asetting
)
{
int
status
;
int
errors
=
0
;
for
(
int
i
=
0
;
i
<
numoptions
;
i
++
)
{
status
=
CONFIG_FALSE
;
switch
(
cfgoptions
[
i
].
type
)
{
case
TYPE_STRING
:
//status=config_setting_set_string (asetting, *cfgoptions[i].strptr;
break
;
case
TYPE_STRINGLIST
:
break
;
case
TYPE_UINT8
:
case
TYPE_INT8
:
case
TYPE_UINT16
:
case
TYPE_INT16
:
case
TYPE_UINT32
:
case
TYPE_INT32
:
case
TYPE_MASK
:
status
=
config_setting_set_int
(
asetting
,
(
int
)
*
(
cfgoptions
[
i
].
iptr
)
);
break
;
case
TYPE_UINT64
:
case
TYPE_INT64
:
status
=
config_setting_set_int64
(
asetting
,
(
int64_t
)
*
(
cfgoptions
[
i
].
i64ptr
)
);
break
;
case
TYPE_UINTARRAY
:
case
TYPE_INTARRAY
:
break
;
case
TYPE_DOUBLE
:
status
=
config_setting_set_float
(
asetting
,
(
double
)
*
(
cfgoptions
[
i
].
dblptr
)
);
break
;
case
TYPE_IPV4ADDR
:
break
;
case
TYPE_LIST
:
break
;
default:
fprintf
(
stderr
,
"[LIBCONFIG] %s type %i not supported
\n
"
,
cfgoptions
[
i
].
optname
,
cfgoptions
[
i
].
type
);
status
=
CONFIG_FALSE
;
break
;
}
/* switch on param type */
if
(
status
!=
CONFIG_TRUE
)
{
errors
++
;
fprintf
(
stderr
,
"[LIBCONFIG] Error creating setting %i: %s type %i
\n
"
,
i
,
cfgoptions
[
i
].
optname
,
cfgoptions
[
i
].
type
);
}
}
if
(
errors
==
0
)
{
print_params
(
"[LIBCONFIG], %i settings set successfully "
,
numoptions
);
}
else
{
fprintf
(
stderr
,
"[LIBCONFIG] ...%i/%i settings creation errors
\n
"
,
errors
,
numoptions
);
}
return
errors
;
}
int
config_libconfig_set
(
paramdef_t
*
cfgoptions
,
int
numoptions
,
char
*
prefix
)
{
char
*
tokctx1
=
NULL
;
int
listidx
=-
1
;
char
*
prefixbck
=
NULL
;
char
*
prefix_elem1
=
NULL
;
config_setting_t
*
asetting
=
config_root_setting
(
&
(
libconfig_privdata
.
runtcfg
));
if
(
prefix
!=
NULL
)
{
prefixbck
=
strdup
(
prefix
);
prefix_elem1
=
strtok_r
(
prefixbck
,
"."
,
&
tokctx1
);
}
int
n1
=
0
;
while
(
prefix_elem1
!=
NULL
)
{
n1
+=
strlen
(
prefix_elem1
)
+
1
;
char
*
prefix_elem2
=
(
n1
<
strlen
(
prefix
)
)
?
prefix_elem1
+
n1
:
""
;
if
(
prefix_elem2
[
0
]
!=
'['
)
{
config_setting_t
*
tmpset
=
config_setting_lookup
(
asetting
,
prefix_elem1
);
if
(
tmpset
==
NULL
)
asetting
=
config_setting_add
(
asetting
,
prefix_elem1
,
CONFIG_TYPE_GROUP
);
else
asetting
=
tmpset
;
}
else
{
listidx
=
(
int
)
strtol
(
prefix_elem2
,
NULL
,
10
);
config_setting_t
*
tmpset
=
config_setting_lookup
(
asetting
,
prefix_elem1
);
if
(
tmpset
==
NULL
)
asetting
=
config_setting_add
(
asetting
,
prefix_elem1
,
CONFIG_TYPE_LIST
);
else
asetting
=
tmpset
;
// tmpset =
}
if
(
asetting
==
NULL
)
{
fprintf
(
stderr
,
"[LIBCONFIG] Error creating setting %s %s %i
\n
"
,
prefix_elem1
,
prefix_elem2
,
listidx
);
break
;
}
prefix_elem1
=
strtok_r
(
NULL
,
"."
,
&
tokctx1
);
}
free
(
prefixbck
);
if
(
asetting
!=
NULL
)
{
config_libconfig_setparams
(
cfgoptions
,
numoptions
,
asetting
);
printf_params
(
"[LIBCONFIG] %i settings added in group %s
\n
"
,
numoptions
,(
prefix
==
NULL
)
?
""
:
prefix
);
return
0
;
}
else
{
fprintf
(
stderr
,
"[LIBCONFIG] Error parsing %s params, skipped...
\n
"
,(
prefix
==
NULL
)
?
""
:
prefix
);
return
-
1
;
}
}
int
config_libconfig_get
(
paramdef_t
*
cfgoptions
,
int
numoptions
,
char
*
prefix
)
{
...
...
@@ -376,6 +484,12 @@ int config_libconfig_init(char *cfgP[], int numP) {
free
(
tmppath
);
return
-
1
;
}
/* possibly init a libconfig struct for saving really used params */
if
(
cfgptr
->
rtflags
&
CONFIG_SAVERUNCFG
)
{
config_init
(
&
(
libconfig_privdata
.
runtcfg
));
// config_set_options (&(libconfig_privdata.runtcfg), CONFIG_OPTION_ALLOW_OVERRIDES, CONFIG_TRUE);
}
free
(
tmppath
);
return
0
;
}
...
...
@@ -383,7 +497,22 @@ int config_libconfig_init(char *cfgP[], int numP) {
void
config_libconfig_end
(
void
)
{
config_destroy
(
&
(
libconfig_privdata
.
cfg
));
if
(
cfgptr
->
rtflags
&
CONFIG_SAVERUNCFG
)
{
char
*
newcfgf
=
malloc
(
strlen
(
libconfig_privdata
.
configfile
+
20
));
time_t
t
=
time
(
NULL
);
struct
tm
tm
=
*
localtime
(
&
t
);
sprintf
(
newcfgf
,
"%s-run%d_%02d_%02d_%02d%02d"
,
libconfig_privdata
.
configfile
,
tm
.
tm_year
+
1900
,
tm
.
tm_mon
+
1
,
tm
.
tm_mday
,
tm
.
tm_hour
,
tm
.
tm_min
);
if
(
config_write_file
(
&
(
libconfig_privdata
.
runtcfg
)
,
newcfgf
)
!=
CONFIG_TRUE
)
{
fprintf
(
stderr
,
"[LIBCONFIG] %s %d file %s - line %d: %s
\n
"
,
__FILE__
,
__LINE__
,
newcfgf
,
config_error_line
(
&
(
libconfig_privdata
.
runtcfg
)),
config_error_text
(
&
(
libconfig_privdata
.
runtcfg
)));
}
else
{
printf
(
"[LIBCONFIG] file %s created successfully
\n
"
,
newcfgf
);
}
config_destroy
(
&
(
libconfig_privdata
.
runtcfg
));
free
(
newcfgf
);
}
if
(
libconfig_privdata
.
configfile
!=
NULL
)
{
free
(
libconfig_privdata
.
configfile
);
libconfig_privdata
.
configfile
=
NULL
;
...
...
common/config/libconfig/config_libconfig.h
View file @
79b85864
...
...
@@ -46,6 +46,7 @@ extern "C"
typedef
struct
libconfig_privatedata
{
char
*
configfile
;
config_t
cfg
;
config_t
runtcfg
;
}
libconfig_privatedata_t
;
#ifdef __cplusplus
...
...
common/utils/telnetsrv/telnetsrv.c
View file @
79b85864
...
...
@@ -501,7 +501,7 @@ int process_command(char *buf) {
j
=
sscanf
(
buf
,
"%19s %19s %m[^
\t\n
]"
,
modulename
,
cmd
,
&
cmdb
);
if
(
telnetparams
.
telnetdbg
>
0
)
printf
(
"process_command: %i words, module=%s cmd=%s, parameters= %s
\n
"
,
j
,
modulename
,
cmd
,
cmdb
);
printf
(
"process_command: %i words, module=%s cmd=%s, parameters= %s
\n
"
,
j
,
modulename
,
cmd
,
(
cmdb
==
NULL
)
?
""
:
cmdb
);
for
(
i
=
0
;
j
>=
2
&&
telnetparams
.
CmdParsers
[
i
].
var
!=
NULL
&&
telnetparams
.
CmdParsers
[
i
].
cmd
!=
NULL
;
i
++
)
{
if
(
(
strncasecmp
(
telnetparams
.
CmdParsers
[
i
].
module
,
modulename
,
strlen
(
telnetparams
.
CmdParsers
[
i
].
module
))
==
0
))
{
...
...
@@ -522,7 +522,8 @@ int process_command(char *buf) {
cmddata
->
cmdfunc
=
(
qcmdfunc_t
)
telnetparams
.
CmdParsers
[
i
].
cmd
[
k
].
cmdfunc
;
cmddata
->
prnt
=
client_printf
;
cmddata
->
debug
=
telnetparams
.
telnetdbg
;
cmddata
->
cmdbuff
=
strdup
(
cmdb
);
if
(
cmdb
!=
NULL
)
cmddata
->
cmdbuff
=
strdup
(
cmdb
);
pushNotifiedFIFO
(
telnetparams
.
CmdParsers
[
i
].
cmd
[
k
].
qptr
,
msg
);
}
else
{
telnetparams
.
CmdParsers
[
i
].
cmd
[
k
].
cmdfunc
(
cmdb
,
telnetparams
.
telnetdbg
,
client_printf
);
...
...
common/utils/telnetsrv/telnetsrv_proccmd.c
View file @
79b85864
...
...
@@ -194,7 +194,10 @@ struct dirent *entry;
int
proccmd_show
(
char
*
buf
,
int
debug
,
telnet_printfunc_t
prnt
)
{
if
(
buf
==
NULL
)
{
prnt
(
"ERROR wrong softmodem SHOW command...
\n
"
);
return
0
;
}
if
(
debug
>
0
)
prnt
(
" proccmd_show received %s
\n
"
,
buf
);
if
(
strcasestr
(
buf
,
"thread"
)
!=
NULL
)
{
...
...
@@ -270,6 +273,10 @@ int bv1,bv2;
int
res
;
char
sv1
[
64
];
if
(
buf
==
NULL
)
{
prnt
(
"ERROR wrong thread command...
\n
"
);
return
0
;
}
bv1
=
0
;
bv2
=
0
;
sv1
[
0
]
=
0
;
...
...
@@ -307,7 +314,7 @@ int proccmd_exit(char *buf, int debug, telnet_printfunc_t prnt)
{
if
(
debug
>
0
)
prnt
(
"process module received %s
\n
"
,
buf
);
end_configmodule
();
exit_fun
(
"telnet server received exit command
\n
"
);
return
0
;
}
...
...
common/utils/websrv/websrv.c
View file @
79b85864
...
...
@@ -177,7 +177,7 @@ int websrv_callback_get_softmodemcmd(const struct _u_request * request, struct _
if
(
strcmp
(
telnetparams
->
CmdParsers
[
i
].
module
,
module
)
==
0
)
{
for
(
int
j
=
0
;
telnetparams
->
CmdParsers
[
i
].
var
[
j
].
varvalptr
!=
NULL
;
j
++
)
{
char
*
strval
=
telnet_getvarvalue
(
i
,
j
);
char
*
strbool
=
"
N
"
;
char
*
strbool
=
"
false
"
;
json_t
*
oneaction
=
json_pack
(
"{s:s,s:s,s:s,s:s}"
,
"type"
,
"variable"
,
"name"
,
telnetparams
->
CmdParsers
[
i
].
var
[
j
].
varname
,
"value"
,
strval
,
"modifiable"
,
strbool
);
if
(
oneaction
==
NULL
)
{
LOG_E
(
UTIL
,
"websrv cannot encode oneaction %s/%s
\n
"
,
module
,
telnetparams
->
CmdParsers
[
i
].
var
[
j
].
varname
);
...
...
executables/softmodem-common.c
View file @
79b85864
...
...
@@ -202,6 +202,7 @@ void signal_handler(int sig) {
softmodem_printresources
(
sig
,(
telnet_printfunc_t
)
printf
);
if
(
sig
!=
SOFTMODEM_RTSIGNAL
)
{
printf
(
"Linux signal %s...
\n
"
,
strsignal
(
sig
));
end_configmodule
();
exit_function
(
__FILE__
,
__FUNCTION__
,
__LINE__
,
"softmodem starting exit procedure
\n
"
);
}
}
...
...
openair1/SIMULATION/TOOLS/random_channel.c
View file @
79b85864
...
...
@@ -1931,10 +1931,15 @@ static void display_channelmodel(channel_desc_t *cd,int debug, telnet_printfunc_
}
}
static
int
channelmod_show_cmd
(
char
*
buff
,
int
debug
,
telnet_printfunc_t
prnt
)
{
char
*
subcmd
=
NULL
;
int
s
=
sscanf
(
buff
,
"%ms
\n
"
,
&
subcmd
);
int
s
;
if
(
buff
==
NULL
)
{
subcmd
=
strdup
(
""
);
//enforce help display
s
=
2
;
}
else
{
s
=
sscanf
(
buff
,
"%ms
\n
"
,
&
subcmd
);
}
if
(
s
>
0
)
{
if
(
strcmp
(
subcmd
,
"predef"
)
==
0
)
{
...
...
targets/ARCH/rfsimulator/simulator.c
View file @
79b85864
...
...
@@ -316,6 +316,15 @@ static void rfsimulator_readconfig(rfsimulator_state_t *rfsimulator) {
static
int
rfsimu_setchanmod_cmd
(
char
*
buff
,
int
debug
,
telnet_printfunc_t
prnt
,
void
*
arg
)
{
char
*
modelname
=
NULL
;
char
*
modeltype
=
NULL
;
rfsimulator_state_t
*
t
=
(
rfsimulator_state_t
*
)
arg
;
if
(
t
->
channelmod
==
false
)
{
prnt
(
"ERROR channel modelisation disabled...
\n
"
);
return
0
;
}
if
(
buff
==
NULL
)
{
prnt
(
"ERROR wrong rfsimu setchannelmod command...
\n
"
);
return
0
;
}
if
(
debug
)
prnt
(
"rfsimu_setchanmod_cmd buffer
\"
%s
\"\n
"
,
buff
);
int
s
=
sscanf
(
buff
,
"%m[^ ] %ms
\n
"
,
&
modelname
,
&
modeltype
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment