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
canghaiwuhen
OpenXG-RAN
Commits
9ddae27c
Commit
9ddae27c
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
fbd5fff7
4d1705e3
Changes
4
Show 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 @
9ddae27c
...
@@ -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 @
9ddae27c
...
@@ -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 @
9ddae27c
#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 @
9ddae27c
#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