Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
OpenXG UE
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
Michael Black
OpenXG UE
Commits
c9ec4408
Commit
c9ec4408
authored
Oct 27, 2017
by
Cedric Roux
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/T-add-tracer' into develop_integration_w43
parents
10743c7d
b89534a5
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
480 additions
and
6 deletions
+480
-6
common/utils/T/.gitignore
common/utils/T/.gitignore
+4
-0
common/utils/T/tracer/Makefile
common/utils/T/tracer/Makefile
+16
-6
common/utils/T/tracer/extract_output_subframe.c
common/utils/T/tracer/extract_output_subframe.c
+158
-0
common/utils/T/tracer/to_vcd.c
common/utils/T/tracer/to_vcd.c
+302
-0
No files found.
common/utils/T/.gitignore
View file @
c9ec4408
...
@@ -10,4 +10,8 @@ tracer/replay
...
@@ -10,4 +10,8 @@ tracer/replay
tracer/textlog
tracer/textlog
tracer/vcd
tracer/vcd
tracer/macpdu2wireshark
tracer/macpdu2wireshark
tracer/ue
tracer/to_vcd
tracer/extract_input_subframe
tracer/extract_output_subframe
tracee/tracee
tracee/tracee
common/utils/T/tracer/Makefile
View file @
c9ec4408
...
@@ -3,10 +3,11 @@ CFLAGS=-Wall -g -pthread -DT_TRACER -I.
...
@@ -3,10 +3,11 @@ CFLAGS=-Wall -g -pthread -DT_TRACER -I.
#CFLAGS += -O3 -ffast-math -fomit-frame-pointer
#CFLAGS += -O3 -ffast-math -fomit-frame-pointer
LIBS
=
-lX11
-lm
-lpng
-lXft
LIBS
=
-lm
XLIBS
=
-lX11
-lpng
-lXft
all
:
record replay extract_config textlog enb ue vcd macpdu2wireshark
\
all
:
record replay extract_config textlog enb ue vcd macpdu2wireshark
\
extract_input_subframe
extract_input_subframe
extract_output_subframe to_vcd
record
:
utils.o record.o database.o config.o
record
:
utils.o record.o database.o config.o
$(CC)
$(CFLAGS)
-o
record
$^
$(LIBS)
$(CC)
$(CFLAGS)
-o
record
$^
$(LIBS)
...
@@ -21,25 +22,33 @@ extract_input_subframe: extract_input_subframe.o database.o event.o utils.o \
...
@@ -21,25 +22,33 @@ extract_input_subframe: extract_input_subframe.o database.o event.o utils.o \
config.o
config.o
$(CC)
$(CFLAGS)
-o
$@
$^
$(LIBS)
$(CC)
$(CFLAGS)
-o
$@
$^
$(LIBS)
extract_output_subframe
:
extract_output_subframe.o database.o event.o utils.o
\
config.o
$(CC)
$(CFLAGS)
-o
$@
$^
$(LIBS)
textlog
:
utils.o textlog.o database.o event.o handler.o config.o
\
textlog
:
utils.o textlog.o database.o event.o handler.o config.o
\
event_selector.o view/view.a gui/gui.a logger/logger.a
\
event_selector.o view/view.a gui/gui.a logger/logger.a
\
filter/filter.a
filter/filter.a
$(CC)
$(CFLAGS)
-o
textlog
$^
$(LIBS)
$(CC)
$(CFLAGS)
-o
textlog
$^
$(LIBS)
$(XLIBS)
enb
:
utils.o enb.o database.o event.o handler.o config.o
\
enb
:
utils.o enb.o database.o event.o handler.o config.o
\
event_selector.o view/view.a gui/gui.a logger/logger.a
\
event_selector.o view/view.a gui/gui.a logger/logger.a
\
filter/filter.a
filter/filter.a
$(CC)
$(CFLAGS)
-o
enb
$^
$(LIBS)
$(CC)
$(CFLAGS)
-o
enb
$^
$(LIBS)
$(XLIBS)
ue
:
utils.o ue.o database.o event.o handler.o config.o
\
ue
:
utils.o ue.o database.o event.o handler.o config.o
\
event_selector.o view/view.a gui/gui.a logger/logger.a
\
event_selector.o view/view.a gui/gui.a logger/logger.a
\
filter/filter.a
filter/filter.a
$(CC)
$(CFLAGS)
-o
ue
$^
$(LIBS)
$(CC)
$(CFLAGS)
-o
ue
$^
$(LIBS)
$(XLIBS)
vcd
:
utils.o vcd.o database.o event.o handler.o config.o
\
vcd
:
utils.o vcd.o database.o event.o handler.o config.o
\
event_selector.o view/view.a gui/gui.a logger/logger.a
\
event_selector.o view/view.a gui/gui.a logger/logger.a
\
filter/filter.a
filter/filter.a
$(CC)
$(CFLAGS)
-o
vcd
$^
$(LIBS)
$(CC)
$(CFLAGS)
-o
vcd
$^
$(LIBS)
$(XLIBS)
to_vcd
:
to_vcd.o database.o event.o handler.o utils.o config.o
\
logger/logger.a filter/filter.a
$(CC)
$(CFLAGS)
-o
to_vcd
$^
$(LIBS)
macpdu2wireshark
:
macpdu2wireshark.o database.o utils.o handler.o event.o
\
macpdu2wireshark
:
macpdu2wireshark.o database.o utils.o handler.o event.o
\
config.o
config.o
...
@@ -65,6 +74,7 @@ filter/filter.a:
...
@@ -65,6 +74,7 @@ filter/filter.a:
clean
:
clean
:
rm
-f
*
.o core tracer_remote textlog enb ue vcd record replay
rm
-f
*
.o core tracer_remote textlog enb ue vcd record replay
rm
-f
extract_config macpdu2wireshark extract_input_subframe
rm
-f
extract_config macpdu2wireshark extract_input_subframe
rm
-f
extract_output_subframe to_vcd
cd
gui
&&
make clean
cd
gui
&&
make clean
cd
view
&&
make clean
cd
view
&&
make clean
cd
logger
&&
make clean
cd
logger
&&
make clean
...
...
common/utils/T/tracer/extract_output_subframe.c
0 → 100644
View file @
c9ec4408
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include "database.h"
#include "event.h"
#include "config.h"
void
usage
(
void
)
{
printf
(
"usage: [options] <file> <frame> <subframe> <number of subframes>
\n
"
" the program dumps 'number of subframes' subframes starting
\n
"
" at 'frame:suubframe'
\n
"
"options:
\n
"
" -d <database file> this option is mandatory
\n
"
" -o <output file> output to file (default: stdout)
\n
"
" -v verbose
\n
"
);
exit
(
1
);
}
int
main
(
int
n
,
char
**
v
)
{
char
*
database_filename
=
NULL
;
void
*
database
;
int
i
;
int
output_event_id
;
database_event_format
f
;
char
*
file
=
NULL
;
int
fd
;
int
frame
=
-
1
,
subframe
=
-
1
;
int
number_of_subframes
=
-
1
;
int
frame_arg
,
subframe_arg
,
buffer_arg
;
int
verbose
=
0
;
char
*
out_filename
=
NULL
;
FILE
*
out
;
for
(
i
=
1
;
i
<
n
;
i
++
)
{
if
(
!
strcmp
(
v
[
i
],
"-h"
)
||
!
strcmp
(
v
[
i
],
"--help"
))
usage
();
if
(
!
strcmp
(
v
[
i
],
"-d"
))
{
if
(
i
>
n
-
2
)
usage
();
database_filename
=
v
[
++
i
];
continue
;
}
if
(
!
strcmp
(
v
[
i
],
"-o"
))
{
if
(
i
>
n
-
2
)
usage
();
out_filename
=
v
[
++
i
];
continue
;
}
if
(
!
strcmp
(
v
[
i
],
"-v"
))
{
verbose
=
1
;
continue
;
}
if
(
file
==
NULL
)
{
file
=
v
[
i
];
continue
;
}
if
(
frame
==
-
1
)
{
frame
=
atoi
(
v
[
i
]);
continue
;
}
if
(
subframe
==
-
1
)
{
subframe
=
atoi
(
v
[
i
]);
continue
;
}
if
(
number_of_subframes
==
-
1
)
{
number_of_subframes
=
atoi
(
v
[
i
]);
continue
;}
usage
();
}
if
(
file
==
NULL
||
frame
==
-
1
||
subframe
==
-
1
||
number_of_subframes
==
-
1
)
usage
();
if
(
database_filename
==
NULL
)
{
printf
(
"ERROR: provide a database file (-d)
\n
"
);
exit
(
1
);
}
if
(
out_filename
==
NULL
)
out
=
stdout
;
else
{
out
=
fopen
(
out_filename
,
"w"
);
if
(
out
==
NULL
)
{
perror
(
out_filename
);
exit
(
1
);
}
}
database
=
parse_database
(
database_filename
);
load_config_file
(
database_filename
);
output_event_id
=
event_id_from_name
(
database
,
"ENB_PHY_OUTPUT_SIGNAL"
);
f
=
get_format
(
database
,
output_event_id
);
frame_arg
=
subframe_arg
=
buffer_arg
=
-
1
;
for
(
i
=
0
;
i
<
f
.
count
;
i
++
)
{
if
(
!
strcmp
(
f
.
name
[
i
],
"frame"
))
{
if
(
frame_arg
!=
-
1
)
goto
err
;
if
(
strcmp
(
f
.
type
[
i
],
"int"
))
goto
err
;
frame_arg
=
i
;
}
if
(
!
strcmp
(
f
.
name
[
i
],
"subframe"
))
{
if
(
subframe_arg
!=
-
1
)
goto
err
;
if
(
strcmp
(
f
.
type
[
i
],
"int"
))
goto
err
;
subframe_arg
=
i
;
}
if
(
!
strcmp
(
f
.
name
[
i
],
"txdata"
))
{
if
(
buffer_arg
!=
-
1
)
goto
err
;
if
(
strcmp
(
f
.
type
[
i
],
"buffer"
))
goto
err
;
buffer_arg
=
i
;
}
continue
;
err:
printf
(
"cannot deal with ENB_PHY_OUTPUT_SIGNAL from database file
\n
"
);
exit
(
1
);
}
if
(
frame_arg
==
-
1
||
subframe_arg
==
-
1
||
buffer_arg
==
-
1
)
goto
err
;
fd
=
open
(
file
,
O_RDONLY
);
if
(
fd
==
-
1
)
{
perror
(
file
);
exit
(
1
);
}
int
last_frame
=
-
1
;
int
last_subframe
=
-
1
;
int
subframe_written
=
0
;
while
(
1
)
{
char
v
[
T_BUFFER_MAX
];
event
e
;
e
=
get_event
(
fd
,
v
,
database
);
if
(
e
.
type
==
-
1
)
break
;
if
(
e
.
type
!=
output_event_id
)
continue
;
if
(
verbose
)
printf
(
"found output frame %d subframe %d size %d
\n
"
,
e
.
e
[
frame_arg
].
i
,
e
.
e
[
subframe_arg
].
i
,
e
.
e
[
buffer_arg
].
bsize
);
if
(
!
(
last_frame
!=
-
1
||
(
frame
==
e
.
e
[
frame_arg
].
i
&&
subframe
==
e
.
e
[
subframe_arg
].
i
)))
continue
;
frame
=
e
.
e
[
frame_arg
].
i
;
subframe
=
e
.
e
[
subframe_arg
].
i
;
if
(
last_frame
!=
-
1
)
{
if
(
frame
*
10
+
subframe
!=
(
last_frame
*
10
+
last_subframe
+
1
)
%
10240
)
{
printf
(
"error: discontinuity, not what you want...
\n
"
);
exit
(
1
);
}
}
last_frame
=
frame
;
last_subframe
=
subframe
;
#if 0
for (i = 0; i < e.e[buffer_arg].bsize/2; i++) {
short *x = e.e[buffer_arg].b;
x[i] *= 14;
}
#endif
if
(
verbose
)
printf
(
"save output frame %d subframe %d size %d
\n
"
,
e
.
e
[
frame_arg
].
i
,
e
.
e
[
subframe_arg
].
i
,
e
.
e
[
buffer_arg
].
bsize
);
if
(
fwrite
(
e
.
e
[
buffer_arg
].
b
,
e
.
e
[
buffer_arg
].
bsize
,
1
,
out
)
!=
1
)
{
perror
(
out_filename
);
exit
(
1
);
}
subframe_written
++
;
if
(
subframe_written
!=
number_of_subframes
)
continue
;
/* done */
fflush
(
out
);
if
(
out_filename
!=
NULL
)
{
if
(
fclose
(
out
))
perror
(
out_filename
);
}
if
(
verbose
)
printf
(
"%d subframes written
\n
"
,
subframe_written
);
return
0
;
}
printf
(
"error with input file, %d subframe written
\n
"
,
subframe_written
);
fflush
(
out
);
if
(
out_filename
!=
NULL
)
{
if
(
fclose
(
out
))
perror
(
out_filename
);
}
return
1
;
}
common/utils/T/tracer/to_vcd.c
0 → 100644
View file @
c9ec4408
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <signal.h>
#include <unistd.h>
#include "database.h"
#include "utils.h"
#include "handler.h"
#include "config.h"
#include "logger/logger.h"
#include "view/view.h"
typedef
struct
{
char
*
event
;
char
*
arg
;
char
*
vcd_name
;
int
boolean
;
}
vcd_vars
;
/****************************************************************************/
/* VCD file handling begin */
/****************************************************************************/
FILE
*
out
;
uint64_t
start_time
;
int
start_time_inited
;
void
vcd_init
(
char
*
file
)
{
out
=
fopen
(
file
,
"w"
);
if
(
out
==
NULL
)
{
perror
(
file
);
exit
(
1
);
}
}
void
vcd_write_header
(
vcd_vars
*
v
,
int
n
)
{
int
i
;
if
(
fprintf
(
out
,
"$date
\n
"
" January, 1, 1970.
\n
"
"$end
\n
"
"$version
\n
"
" to_vcd
\n
"
"$end
\n
"
"$timescale 1ns $end
\n
"
"$scope module logic $end
\n
"
)
<=
0
)
abort
();
for
(
i
=
0
;
i
<
n
;
i
++
)
if
(
fprintf
(
out
,
"$var wire %d %s %s $end
\n
"
,
v
[
i
].
boolean
?
1
:
64
,
v
[
i
].
vcd_name
,
v
[
i
].
vcd_name
)
<=
0
)
abort
();
if
(
fprintf
(
out
,
"$upscope $end
\n
"
"$enddefinitions $end
\n
"
"$dumpvars
\n
"
)
<=
0
)
abort
();
for
(
i
=
0
;
i
<
n
;
i
++
)
if
(
v
[
i
].
boolean
)
{
if
(
fprintf
(
out
,
"0%s
\n
"
,
v
[
i
].
vcd_name
)
<=
0
)
abort
();
}
else
{
if
(
fprintf
(
out
,
"b0 %s
\n
"
,
v
[
i
].
vcd_name
)
<=
0
)
abort
();
}
if
(
fprintf
(
out
,
"$end
\n
"
)
<=
0
)
abort
();
}
void
vcd_end
(
void
)
{
if
(
fclose
(
out
))
{
perror
(
"error closing VCD file"
);
exit
(
1
);
}
}
char
*
b64
(
uint64_t
val
)
{
static
char
v
[
65
];
char
*
s
=
&
v
[
64
];
*
s
=
0
;
if
(
val
==
0
)
{
s
--
;
*
s
=
'0'
;
return
s
;
}
while
(
val
)
{
s
--
;
*
s
=
val
&
1
?
'1'
:
'0'
;
val
>>=
1
;
}
return
s
;
}
void
vcd_dump
(
char
*
v
)
{
uint64_t
h
,
m
,
s
,
ns
;
char
t
;
uint64_t
val
;
uint64_t
time
;
char
var
[
256
];
if
(
sscanf
(
v
,
"%"
SCNu64
":%"
SCNu64
":%"
SCNu64
".%"
SCNu64
": %c %"
SCNu64
" %s"
,
&
h
,
&
m
,
&
s
,
&
ns
,
&
t
,
&
val
,
var
)
!=
7
)
goto
err
;
time
=
h
*
60
*
60
*
1000000000
+
m
*
60
*
1000000000
+
s
*
1000000000
+
ns
;
if
(
!
start_time_inited
)
{
start_time
=
time
;
start_time_inited
=
1
;
}
if
(
fprintf
(
out
,
"#%"
PRIu64
"
\n
"
,
time
-
start_time
)
<=
0
)
abort
();
switch
(
t
)
{
case
'b'
:
if
(
fprintf
(
out
,
"%d%s
\n
"
,
val
!=
0
,
var
)
<=
0
)
abort
();
break
;
case
'l'
:
if
(
fprintf
(
out
,
"b%s %s
\n
"
,
b64
(
val
),
var
)
<=
0
)
abort
();
break
;
default:
goto
err
;
}
return
;
err:
printf
(
"bad vcd_dump line '%s'
\n
"
,
v
);
exit
(
1
);
}
/****************************************************************************/
/* VCD file handling end */
/****************************************************************************/
/****************************************************************************/
/* vcd view start */
/****************************************************************************/
struct
vcd_view
{
view
common
;
};
static
void
vcd_view_clear
(
view
*
this
)
{
/* nothing */
}
static
void
vcd_view_append
(
view
*
_this
,
char
*
s
)
{
vcd_dump
(
s
);
}
static
view
*
new_view_vcd
(
void
)
{
struct
vcd_view
*
ret
=
calloc
(
1
,
sizeof
(
struct
vcd_view
));
if
(
ret
==
NULL
)
abort
();
ret
->
common
.
clear
=
vcd_view_clear
;
ret
->
common
.
append
=
(
void
(
*
)(
view
*
,
...))
vcd_view_append
;
return
(
view
*
)
ret
;
}
/****************************************************************************/
/* vcd view end */
/****************************************************************************/
void
activate_traces
(
int
socket
,
int
number_of_events
,
int
*
is_on
)
{
char
t
=
1
;
if
(
socket_send
(
socket
,
&
t
,
1
)
==
-
1
||
socket_send
(
socket
,
&
number_of_events
,
sizeof
(
int
))
==
-
1
||
socket_send
(
socket
,
is_on
,
number_of_events
*
sizeof
(
int
))
==
-
1
)
abort
();
}
void
usage
(
void
)
{
printf
(
"options:
\n
"
" -d <database file> this option is mandatory
\n
"
" -o <output file> this option is mandatory
\n
"
" -ip <host> connect to given IP address (default %s)
\n
"
" -p <port> connect to given port (default %d)
\n
"
" -b <event> <arg> <vcd name> trace as binary (0 off, anything else on)
\n
"
" -l <event> <arg> <vcd name> trace as uint64_t
\n
"
,
DEFAULT_REMOTE_IP
,
DEFAULT_REMOTE_PORT
);
exit
(
1
);
}
int
run
=
1
;
static
int
socket
=
-
1
;
void
force_stop
(
int
x
)
{
printf
(
"
\n
gently quit...
\n
"
);
close
(
socket
);
socket
=
-
1
;
run
=
0
;
}
int
main
(
int
n
,
char
**
v
)
{
char
*
output_filename
=
NULL
;
char
*
database_filename
=
NULL
;
void
*
database
;
char
*
ip
=
DEFAULT_REMOTE_IP
;
int
port
=
DEFAULT_REMOTE_PORT
;
int
*
is_on
;
int
number_of_events
;
int
i
;
vcd_vars
vars
[
n
];
int
nvars
=
0
;
view
*
vcd_view
;
event_handler
*
h
;
logger
*
textlog
;
/* write on a socket fails if the other end is closed and we get SIGPIPE */
if
(
signal
(
SIGPIPE
,
SIG_IGN
)
==
SIG_ERR
)
abort
();
for
(
i
=
1
;
i
<
n
;
i
++
)
{
if
(
!
strcmp
(
v
[
i
],
"-h"
)
||
!
strcmp
(
v
[
i
],
"--help"
))
usage
();
if
(
!
strcmp
(
v
[
i
],
"-d"
))
{
if
(
i
>
n
-
2
)
usage
();
database_filename
=
v
[
++
i
];
continue
;
}
if
(
!
strcmp
(
v
[
i
],
"-o"
))
{
if
(
i
>
n
-
2
)
usage
();
output_filename
=
v
[
++
i
];
continue
;
}
if
(
!
strcmp
(
v
[
i
],
"-ip"
))
{
if
(
i
>
n
-
2
)
usage
();
ip
=
v
[
++
i
];
continue
;
}
if
(
!
strcmp
(
v
[
i
],
"-p"
))
{
if
(
i
>
n
-
2
)
usage
();
port
=
atoi
(
v
[
++
i
]);
continue
;
}
if
(
!
strcmp
(
v
[
i
],
"-b"
))
{
if
(
i
>
n
-
4
)
usage
();
vars
[
nvars
].
event
=
v
[
++
i
];
vars
[
nvars
].
arg
=
v
[
++
i
];
vars
[
nvars
].
vcd_name
=
v
[
++
i
];
vars
[
nvars
++
].
boolean
=
1
;
continue
;
}
if
(
!
strcmp
(
v
[
i
],
"-l"
))
{
if
(
i
>
n
-
4
)
usage
();
vars
[
nvars
].
event
=
v
[
++
i
];
vars
[
nvars
].
arg
=
v
[
++
i
];
vars
[
nvars
].
vcd_name
=
v
[
++
i
];
vars
[
nvars
++
].
boolean
=
0
;
continue
;
}
usage
();
}
if
(
output_filename
==
NULL
)
{
printf
(
"ERROR; provide an output file (-o)
\n
"
);
exit
(
1
);
}
if
(
database_filename
==
NULL
)
{
printf
(
"ERROR: provide a database file (-d)
\n
"
);
exit
(
1
);
}
database
=
parse_database
(
database_filename
);
load_config_file
(
database_filename
);
number_of_events
=
number_of_ids
(
database
);
is_on
=
calloc
(
number_of_events
,
sizeof
(
int
));
if
(
is_on
==
NULL
)
abort
();
h
=
new_handler
(
database
);
/* create the view */
vcd_view
=
new_view_vcd
();
/* setup traces */
for
(
i
=
0
;
i
<
nvars
;
i
++
)
{
char
format
[
256
];
if
(
strlen
(
vars
[
i
].
arg
)
>
256
-
3
)
abort
();
if
(
strlen
(
vars
[
i
].
vcd_name
)
>
256
-
1
)
abort
();
sprintf
(
format
,
"%c [%s] %s"
,
vars
[
i
].
boolean
?
'b'
:
'l'
,
vars
[
i
].
arg
,
vars
[
i
].
vcd_name
);
textlog
=
new_textlog
(
h
,
database
,
vars
[
i
].
event
,
format
);
logger_add_view
(
textlog
,
vcd_view
);
on_off
(
database
,
vars
[
i
].
event
,
is_on
,
1
);
}
socket
=
connect_to
(
ip
,
port
);
/* activate selected traces */
activate_traces
(
socket
,
number_of_events
,
is_on
);
vcd_init
(
output_filename
);
vcd_write_header
(
vars
,
nvars
);
/* exit on ctrl+c and ctrl+z */
if
(
signal
(
SIGQUIT
,
force_stop
)
==
SIG_ERR
)
abort
();
if
(
signal
(
SIGINT
,
force_stop
)
==
SIG_ERR
)
abort
();
if
(
signal
(
SIGTSTP
,
force_stop
)
==
SIG_ERR
)
abort
();
/* read messages */
while
(
run
)
{
char
v
[
T_BUFFER_MAX
];
event
e
;
e
=
get_event
(
socket
,
v
,
database
);
if
(
e
.
type
==
-
1
)
{
printf
(
"disconnected? let's quit gently
\n
"
);
break
;
}
handle_event
(
h
,
e
);
}
vcd_end
();
return
0
;
}
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