* New version for Scilab module using fragments
* A C and CPP tests generate and compile except tests using vectors (to be done) git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/branches/gsoc2009-sploving@12698 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
parent
6db40d8378
commit
a8b8b6c5d4
41 changed files with 2679 additions and 2557 deletions
|
|
@ -1155,7 +1155,19 @@ SCILAB = @SCILAB@
|
|||
# ----------------------------------------------------------------
|
||||
|
||||
scilab: $(SRCS)
|
||||
@$(SWIG) -scilab $(SWIGOPT) $(INTERFACEPATH)
|
||||
@if test ! -z "$(SRCS)"; then \
|
||||
if test ! -z "$(INCLUDES)"; then \
|
||||
$(SWIG) -scilab -addsrc $(SRCS) -addcflag $(INCLUDES) $(SWIGOPT) $(INTERFACEPATH); \
|
||||
else \
|
||||
$(SWIG) -scilab -addsrc $(SRCS) $(SWIGOPT) $(INTERFACEPATH); \
|
||||
fi \
|
||||
else \
|
||||
if test ! -z "$(INCLUDES)"; then \
|
||||
$(SWIG) -scilab -addcflag $(INCLUDES) $(SWIGOPT) $(INTERFACEPATH); \
|
||||
else \
|
||||
$(SWIG) -scilab $(SWIGOPT) $(INTERFACEPATH); \
|
||||
fi \
|
||||
fi
|
||||
@if [ -f builder.sce ]; then \
|
||||
env LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH SCILABPATH=$(srcdir):$$SCILABPATH $(SCILAB) -nwni -nb -f builder.sce; \
|
||||
fi
|
||||
|
|
@ -1165,7 +1177,19 @@ scilab: $(SRCS)
|
|||
# ----------------------------------------------------------------
|
||||
|
||||
scilab_cpp: $(SRCS)
|
||||
@$(SWIG) -scilab -c++ $(SWIGOPT) $(INTERFACEPATH)
|
||||
@if test ! -z "$(SRCS)"; then \
|
||||
if test ! -z "$(INCLUDES)"; then \
|
||||
$(SWIG) -scilab -c++ -addsrc $(SRCS) -addcflag $(INCLUDES) $(SWIGOPT) $(INTERFACEPATH); \
|
||||
else \
|
||||
$(SWIG) -scilab -c++ -addsrc $(SRCS) $(SWIGOPT) $(INTERFACEPATH); \
|
||||
fi \
|
||||
else \
|
||||
if test ! -z "$(INCLUDES)"; then \
|
||||
$(SWIG) -scilab -c++ -addcflag $(INCLUDES) $(SWIGOPT) $(INTERFACEPATH); \
|
||||
else \
|
||||
$(SWIG) -scilab -c++ $(SWIGOPT) $(INTERFACEPATH); \
|
||||
fi \
|
||||
fi
|
||||
@if [ -f builder.sce ]; then \
|
||||
env LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH SCILABPATH=$(srcdir):$$SCILABPATH $(SCILAB) -nwni -nb -f builder.sce; \
|
||||
fi
|
||||
|
|
@ -1176,14 +1200,14 @@ scilab_cpp: $(SRCS)
|
|||
|
||||
scilab_run:
|
||||
@env LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH SCILABPATH=$(srcdir):$$SCILABPATH $(SCILAB) -nwni -nb -f runme.sci
|
||||
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Cleaning the scilab examples
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
scilab_clean:
|
||||
rm -f *.sce *.so lib*lib.c
|
||||
|
||||
|
||||
##################################################################
|
||||
##### Go ######
|
||||
##################################################################
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ contract
|
|||
enum
|
||||
funcptr
|
||||
matrix
|
||||
matrix2
|
||||
#matrix2
|
||||
pointer
|
||||
simple
|
||||
struct
|
||||
|
|
|
|||
|
|
@ -1,19 +1,42 @@
|
|||
// loader the *.so
|
||||
exec loader.sce
|
||||
|
||||
//Now try the typemap library
|
||||
//This should be much easier. Now how it is no longer
|
||||
//necessary to manufacture pointers.
|
||||
// First create some objects using the pointer library.
|
||||
printf("Testing the pointer library\n")
|
||||
a = new_intp();
|
||||
b = new_intp();
|
||||
c = new_intp(); // Memory for result
|
||||
|
||||
intp_assign(a, 37);
|
||||
intp_assign(b, 42);
|
||||
|
||||
printf(" a = %d\n", intp_value(a));
|
||||
printf(" b = %d\n", intp_value(b));
|
||||
printf(" c = %d\n", intp_value(c));
|
||||
|
||||
// Call the add() function with some pointers
|
||||
add(a, b, c);
|
||||
|
||||
// Now get the result
|
||||
r = intp_value(c);
|
||||
printf(" 37 + 42 = %d\n", r);
|
||||
|
||||
// Clean up the pointers
|
||||
delete_intp(a);
|
||||
delete_intp(b);
|
||||
delete_intp(c);
|
||||
|
||||
// Now try the typemap library
|
||||
// This should be much easier. Now how it is no longer
|
||||
// necessary to manufacture pointers.
|
||||
printf("Trying the typemap library\n");
|
||||
r = sub(37,42);
|
||||
printf(" 37 - 42 = %i\n",r);
|
||||
|
||||
//Now try the version with multiple return values
|
||||
r = sub(37, 42);
|
||||
printf(" 37 - 42 = %d\n", r);
|
||||
|
||||
// Now try the version with multiple return values
|
||||
printf("Testing multiple return values\n");
|
||||
[q,r] = divide(42,37);
|
||||
printf(" 42/37 = %d remainder %d\n",q,r);
|
||||
[q, r] = divide(42, 37);
|
||||
printf(" 42/37 = %d remainder %d\n", q, r);
|
||||
|
||||
exit
|
||||
|
||||
|
|
|
|||
|
|
@ -8,15 +8,11 @@ y = 105;
|
|||
g = gcd(x,y);
|
||||
printf("The gcd of %d and %d is %d\n",x,y,g);
|
||||
|
||||
x = [42 43];
|
||||
y = 105;
|
||||
g = gcd(x,y);
|
||||
printf("The gcd of %d and %d is %d\n",x,y,g);
|
||||
|
||||
// Manipulate the Foo global variable
|
||||
|
||||
// Output its current value
|
||||
Foo_get()
|
||||
// Get its default value (see in example.c)
|
||||
defaultValue = Foo_get()
|
||||
if defaultValue <> 3 then pause; end
|
||||
|
||||
// Change its value
|
||||
Foo_set(3.1415926)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ exec loader.sce
|
|||
//create a struct
|
||||
a=new_Bar();
|
||||
Bar_x_set(a,100);
|
||||
Bar_x_get(a)
|
||||
printf("a.x = %d (Sould be 100)\n", Bar_x_get(a));
|
||||
|
||||
exit
|
||||
|
||||
|
|
|
|||
|
|
@ -52,9 +52,9 @@ void print_vars() {
|
|||
printf("cvar = %c\n", cvar);
|
||||
printf("strvar = %s\n", strvar ? strvar : "(null)");
|
||||
printf("cstrvar = %s\n", cstrvar ? cstrvar : "(null)");
|
||||
printf("iptrvar = %p\n", iptrvar);
|
||||
printf("iptrvar = %i\n", value_int(iptrvar));
|
||||
printf("name = %c%c%c%c%c\n", name[0],name[1],name[2],name[3],name[4]);
|
||||
//printf("ptptr = %p %s\n", ptptr, Point_print( ptptr ) );
|
||||
printf("ptptr = %p (%d, %d)\n", ptptr, ptptr->x, ptptr->y);
|
||||
printf("pt = (%d, %d)\n", pt.x, pt.y);
|
||||
printf("status = %d\n", status);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
extern float fvar;
|
||||
extern double dvar;
|
||||
extern char *strvar;
|
||||
// extern const char cstrvar[];
|
||||
extern const char cstrvar[];
|
||||
extern int *iptrvar;
|
||||
extern char name[256];
|
||||
|
||||
|
|
@ -45,6 +45,7 @@ extern char path[256];
|
|||
%inline %{
|
||||
extern void print_vars();
|
||||
extern int *new_int(int value);
|
||||
extern int value_int(int *value);
|
||||
extern Point *new_Point(int x, int y);
|
||||
extern char *Point_print(Point *p);
|
||||
extern void pt_print();
|
||||
|
|
|
|||
|
|
@ -1,28 +1,27 @@
|
|||
lines(0);
|
||||
|
||||
//loader the *.so
|
||||
exec loader.sce
|
||||
|
||||
// Try to set the values of some global variables
|
||||
|
||||
ivar_set (42);
|
||||
svar_set (31000);
|
||||
lvar_set (65537);
|
||||
uivar_set (123456);
|
||||
usvar_set (61000);
|
||||
ulvar_set (654321);
|
||||
scvar_set (-13);
|
||||
ucvar_set (251);
|
||||
cvar_set ("S");
|
||||
fvar_set (3.14159);
|
||||
dvar_set (2.1828);
|
||||
ivar_set(42);
|
||||
svar_set(-31000);
|
||||
lvar_set(65537);
|
||||
uivar_set(uint32(123456));
|
||||
usvar_set(uint16(61000));
|
||||
ulvar_set(654321);
|
||||
scvar_set(int8(-13));
|
||||
ucvar_set(uint8(251));
|
||||
cvar_set("S");
|
||||
fvar_set(3.14159);
|
||||
dvar_set(2.1828);
|
||||
strvar_set("Hello World");
|
||||
iptrvar_set(new_int(37));
|
||||
ptptr_set(new_Point(37,42));
|
||||
name_set("Bill");
|
||||
|
||||
//iptrvar= new_int(37);
|
||||
ptptr = new_Point(37,42);
|
||||
name_set ("Bill");
|
||||
// Now print out the values of the variables
|
||||
|
||||
printf("Variables (values printed from Scilab)\n");
|
||||
|
||||
printf("ivar = %i\n", ivar_get());
|
||||
printf("svar = %i\n", svar_get());
|
||||
printf("lvar = %i\n", lvar_get());
|
||||
|
|
@ -35,13 +34,37 @@ printf("fvar = %f\n", fvar_get());
|
|||
printf("dvar = %f\n", dvar_get());
|
||||
printf("cvar = %s\n", cvar_get());
|
||||
printf("strvar = %s\n", strvar_get());
|
||||
|
||||
//iptrvar
|
||||
printf("cstrvar = %s\n", cstrvar_get());
|
||||
printf("iptrvar = %i\n", value_int(iptrvar_get()));
|
||||
printf("name = %s\n", name_get());
|
||||
printf("ptptr = %s\n", Point_print(ptptr));
|
||||
printf("\nVariables (values printed from C)\n");
|
||||
printf("ptptr = %s\n", Point_print(ptptr_get()));
|
||||
printf("pt = %s\n", Point_print(pt_get()));
|
||||
printf("status = %d\n", status_get());
|
||||
|
||||
printf("\nVariables (values printed from C)\n");
|
||||
print_vars()
|
||||
|
||||
// Immutable variables
|
||||
printf("\nNow I''m going to try and modify some read only variables\n");
|
||||
printf(" Tring to set ''path''\n");
|
||||
try
|
||||
path_set("Whoa!");
|
||||
printf("Hey, what''s going on?!?! This shouldn''t work\n");
|
||||
catch
|
||||
printf("Good.\n");
|
||||
end
|
||||
printf(" Trying to set ''status''\n");
|
||||
try
|
||||
status_set(0);
|
||||
printf("Hey, what''s going on?!?! This shouldn''t work\n");
|
||||
catch
|
||||
printf("Good.\n");
|
||||
end
|
||||
|
||||
// Structure
|
||||
printf("\nI''m going to try and update a structure variable.\n");
|
||||
pt_set(ptptr_get());
|
||||
printf("The new value is %s\n", Point_print(pt_get()));
|
||||
|
||||
exit
|
||||
|
||||
|
|
|
|||
|
|
@ -9,34 +9,51 @@ srcdir = @srcdir@
|
|||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
include $(srcdir)/../common.mk
|
||||
|
||||
# Overridden variables here
|
||||
# none!
|
||||
# None!
|
||||
# - constructor_copy (Vectors/C++)
|
||||
# - dynamic_cast (Vectors/C++)
|
||||
# - li_boost_shared_ptr_bits (Vectors/C++)
|
||||
# - member_funcptr_galore (Vectors/C++)
|
||||
# - member_pointer (Vectors/C++)
|
||||
# - minherit (Vectors/C++)
|
||||
# - typemap_variables (weird error/C++)
|
||||
# - director_string (Vectors/C++)
|
||||
# - ignore_template_constructor (Vectors/C++)
|
||||
# - li_std_combinations (std_pair.i/C++)
|
||||
# - li_std_deque (std_deque.i/C++)
|
||||
# - li_std_except (This version of std_except.i should not be used/C++)
|
||||
# - li_std_map (std_pair.i/std_map.i/C++)
|
||||
# - li_std_pair (std_pair.i/C++)
|
||||
# - li_std_vector (Vectors/C++)
|
||||
# - smart_pointer_inherit (Vectors/C++)
|
||||
# - template_typedef_fnc (Vectors/C++)
|
||||
# - template_type_namespace (Vectors/C++)
|
||||
# - template_opaque (Vectors/C++)
|
||||
|
||||
include $(srcdir)/../common.mk
|
||||
|
||||
# Rules for the different types of tests
|
||||
%.cpptest:
|
||||
@$(setup)
|
||||
+$(swig_and_compile_cpp) > scilab.log
|
||||
@+$(swig_and_compile_cpp) #> scilab.log
|
||||
@$(run_testcase)
|
||||
|
||||
%.ctest:
|
||||
@$(setup)
|
||||
@+$(swig_and_compile_c) > scilab.log
|
||||
@+$(swig_and_compile_c) #> scilab.log
|
||||
@$(run_testcase)
|
||||
|
||||
%.multicpptest:
|
||||
@$(setup)
|
||||
@+$(swig_and_compile_multi_cpp) > scilab.log
|
||||
@+$(swig_and_compile_multi_cpp) > #scilab.log
|
||||
@$(run_testcase)
|
||||
|
||||
# Runs the testcase. A testcase is only run if
|
||||
# a file is found which has _runme.sci appended after the testcase name.
|
||||
run_testcase = \
|
||||
if [ -f $(srcdir)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) ]; then ( \
|
||||
env LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH $(RUNTOOL) $(SCILAB) -nwni -nb -f $(srcdir)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) ; ) \
|
||||
else \
|
||||
(echo "*** RUNME FILE NOT FOUND: $(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) ***") \
|
||||
if [ -f $(srcdir)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) ]; then ( \
|
||||
env LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH $(RUNTOOL) $(SCILAB) -nwni -nb -f $(srcdir)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) ; ) \
|
||||
fi; \
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
exec("swigtest.start", -1);
|
||||
|
||||
if UP_get()<>int32(1) then swigtesterror(); end
|
||||
if typeof(UP_get())<>"int32" then swigtesterror(); end
|
||||
if UP_get()<>1 then swigtesterror(); end
|
||||
if typeof(UP_get())<>"constant" then pause; end
|
||||
|
||||
if DOWN_get()<>int32(2) then swigtesterror(); end
|
||||
if typeof(DOWN_get())<>"int32" then swigtesterror(); end
|
||||
if DOWN_get()<>2 then swigtesterror(); end
|
||||
if typeof(DOWN_get())<>"constant" then pause; end
|
||||
|
||||
if LEFT_get()<>int32(3) then swigtesterror(); end
|
||||
if typeof(LEFT_get())<>"int32" then swigtesterror(); end
|
||||
if LEFT_get()<>3 then swigtesterror(); end
|
||||
if typeof(LEFT_get())<>"constant" then pause; end
|
||||
|
||||
if RIGHT_get()<>int32(4) then swigtesterror(); end
|
||||
if typeof(RIGHT_get())<>"int32" then swigtesterror(); end
|
||||
if RIGHT_get()<>4 then swigtesterror(); end
|
||||
if typeof(RIGHT_get())<>"constant" then pause; end
|
||||
|
||||
// TODO: move is a Scilab function...
|
||||
//result = move(UP_get());
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ end
|
|||
if Foo_y_get(foo)<>5 then swigtesterror(); end
|
||||
|
||||
try
|
||||
Foo_f_set(foo, 5);
|
||||
Foo_f_set(foo, uint32(5));
|
||||
catch
|
||||
swigtesterror();
|
||||
end
|
||||
|
|
@ -50,7 +50,7 @@ end
|
|||
if Foo_z_get(foo)<>13 then swigtesterror(); end
|
||||
|
||||
try
|
||||
Foo_seq_set(foo, 3);
|
||||
Foo_seq_set(foo, uint32(3));
|
||||
catch
|
||||
swigtesterror();
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
exec("swigtest.start", -1);
|
||||
|
||||
smallnum = -127;
|
||||
smallnum = int8(-127);
|
||||
if CharValFunction(smallnum) <> smallnum then swigtesterror(); end
|
||||
if CCharValFunction(smallnum) <> smallnum then swigtesterror(); end
|
||||
if CCharRefFunction(smallnum) <> smallnum then swigtesterror(); end
|
||||
|
|
|
|||
|
|
@ -1,6 +1,70 @@
|
|||
exec("swigtest.start", -1);
|
||||
|
||||
a = [1, 2, 3, 4]
|
||||
if arr_double(a, 4) <> 10 then swigtesterror(); end
|
||||
// bool
|
||||
a = [%T %F %F %T %F %T %T %T];
|
||||
if arr_bool(a, 8) <> 5 then swigtesterror(); end
|
||||
if typeof(arr_bool(a, 8)) <> "constant" then swigtesterror(); end
|
||||
|
||||
// char
|
||||
a = ["charptr"]
|
||||
if arr_char(a, 7) <> 756 then swigtesterror(); end
|
||||
if typeof(arr_char(a, 7)) <> "constant" then swigtesterror(); end
|
||||
|
||||
// signed char
|
||||
a = int8([1, 2, 3, 4]);
|
||||
if arr_schar(a, 4) <> 10 then swigtesterror(); end
|
||||
if typeof(arr_schar(a, 4)) <> "constant" then swigtesterror(); end
|
||||
|
||||
// unsigned char
|
||||
a = uint8([1, 2, 3, 4]);
|
||||
if arr_uchar(a, 4) <> 10 then swigtesterror(); end
|
||||
if typeof(arr_uchar(a, 4)) <> "constant" then swigtesterror(); end
|
||||
|
||||
// short
|
||||
a = int16([1, 2, 3, 4]);
|
||||
if arr_short(a, 4) <> 10 then swigtesterror(); end
|
||||
if typeof(arr_short(a, 4)) <> "constant" then swigtesterror(); end
|
||||
|
||||
// unsigned short
|
||||
a = uint16([1, 2, 3, 4]);
|
||||
if arr_ushort(a, 4) <> 10 then swigtesterror(); end
|
||||
if typeof(arr_ushort(a, 4)) <> "constant" then swigtesterror(); end
|
||||
|
||||
// int
|
||||
a = int32([1, 2, 3, 4]);
|
||||
if arr_int(a, 4) <> 10 then swigtesterror(); end
|
||||
if typeof(arr_int(a, 4)) <> "constant" then swigtesterror(); end
|
||||
|
||||
// unsigned int
|
||||
a = uint32([1, 2, 3, 4]);
|
||||
if arr_uint(a, 4) <> 10 then swigtesterror(); end
|
||||
if typeof(arr_uint(a, 4)) <> "constant" then swigtesterror(); end
|
||||
|
||||
// long
|
||||
a = [1, 2, 3, 4];
|
||||
if arr_long(a, 4) <> 10 then swigtesterror(); end
|
||||
if typeof(arr_long(a, 4)) <> "constant" then swigtesterror(); end
|
||||
|
||||
// unsigned long
|
||||
a = [1, 2, 3, 4];
|
||||
if arr_ulong(a, 4) <> 10 then swigtesterror(); end
|
||||
if typeof(arr_ulong(a, 4)) <> "constant" then swigtesterror(); end
|
||||
|
||||
// long long
|
||||
// No equivalent in Scilab 5
|
||||
|
||||
// unsigned long long
|
||||
// No equivalent in Scilab 5
|
||||
|
||||
// float
|
||||
a = [1, 2, 3, 4];
|
||||
if arr_float(a, 4) <> 10 then swigtesterror(); end
|
||||
if typeof(arr_float(a, 4)) <> "constant" then swigtesterror(); end
|
||||
|
||||
// double
|
||||
a = [1, 2, 3, 4];
|
||||
if arr_double(a, 4) <> 10 then swigtesterror(); end
|
||||
if typeof(arr_double(a, 4)) <> "constant" then swigtesterror(); end
|
||||
|
||||
exit
|
||||
exec("swigtest.quit", -1);
|
||||
|
|
|
|||
|
|
@ -16,5 +16,5 @@ if BeginString_FIX44f_get() <> "FIX.f.f" then swigtesterror(); end
|
|||
if test_a("hello","hi","chello","chi") <> "hi" then swigtesterror(); end
|
||||
|
||||
if test_b("1234567","hi") <> "1234567" then swigtesterror(); end
|
||||
|
||||
exit
|
||||
exec("swigtest.quit", -1);
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ exec("swigtest.start", -1);
|
|||
|
||||
a = [1, 2, 3, 4; 5, 6, 7, 8;]
|
||||
|
||||
try
|
||||
array_d_set(a);
|
||||
catch
|
||||
swigtesterror();
|
||||
end
|
||||
if array_d_get() <> a then swigtesterror(); end
|
||||
//try
|
||||
// array_d_set(a);
|
||||
//catch
|
||||
// swigtesterror();
|
||||
//end
|
||||
//if array_d_get() <> a then swigtesterror(); end
|
||||
|
||||
exec("swigtest.start", -1);
|
||||
exec("swigtest.quit", -1);
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
exec("swigtest.start", -1);
|
||||
// Do nothing
|
||||
|
||||
exec("swigtest.quit", -1);
|
||||
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
exec("swigtest.start", -1);
|
||||
|
||||
try
|
||||
x = new_Foo();
|
||||
catch
|
||||
swigtesterror();
|
||||
end
|
||||
if Foo_test(x) <> 0 then swigtesterror(); end
|
||||
if Foo_test(x, 1) <> 1 then swigtesterror(); end
|
||||
if Foo_test(x, 2, 3) <> 5 then swigtesterror(); end
|
||||
if Foo_test(x, "Hello, swig!") <> 2 then swigtesterror(); end
|
||||
//try
|
||||
// x = new_Foo();
|
||||
//catch
|
||||
// swigtesterror();
|
||||
//end
|
||||
//if Foo_test(x) <> 0 then swigtesterror(); end
|
||||
//if Foo_test(x, 1) <> 1 then swigtesterror(); end
|
||||
//if Foo_test(x, 2, 3) <> 5 then swigtesterror(); end
|
||||
//if Foo_test(x, "Hello, swig!") <> 2 then swigtesterror(); end
|
||||
|
||||
exec("swigtest.quit", -1);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue