Commit 7f660ade authored by Michael Meskes's avatar Michael Meskes

- Fixed some parser bugs.

        - Removed some simple rules to work arounf bison limit for now.
        - Update c_keywords.c to reflect changes in keywords.c.
parent 0d7c58a9
...@@ -1254,6 +1254,12 @@ Sun May 19 19:21:34 CEST 2002 ...@@ -1254,6 +1254,12 @@ Sun May 19 19:21:34 CEST 2002
- Synced preproc.y with gram.y. - Synced preproc.y with gram.y.
- Synced pgc.l with scan.l. - Synced pgc.l with scan.l.
- Synced keywords.c. - Synced keywords.c.
Mon May 20 10:58:36 CEST 2002
- Fixed some parser bugs.
- Removed some simple rules to work arounf bison limit for now.
- Update c_keywords.c to reflect changes in keywords.c.
- Set ecpg version to 2.10.0. - Set ecpg version to 2.10.0.
- Set library version to 3.4.0. - Set library version to 3.4.0.
...@@ -29,7 +29,7 @@ static ScanKeyword ScanKeywords[] = { ...@@ -29,7 +29,7 @@ static ScanKeyword ScanKeywords[] = {
{"enum", SQL_ENUM}, {"enum", SQL_ENUM},
{"extern", S_EXTERN}, {"extern", S_EXTERN},
{"float", FLOAT}, {"float", FLOAT},
{"int", SQL_INT}, {"int", INT},
{"long", SQL_LONG}, {"long", SQL_LONG},
{"register", S_REGISTER}, {"register", S_REGISTER},
{"short", SQL_SHORT}, {"short", SQL_SHORT},
......
...@@ -18,7 +18,7 @@ extern char *descriptor_index; ...@@ -18,7 +18,7 @@ extern char *descriptor_index;
extern char *descriptor_name; extern char *descriptor_name;
extern char *connection; extern char *connection;
extern char *input_filename; extern char *input_filename;
extern char *yytext, extern char *yytext, *token_start,
errortext[128]; errortext[128];
#ifdef YYDEBUG #ifdef YYDEBUG
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.91 2002/05/19 20:00:53 meskes Exp $ * $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.92 2002/05/20 09:29:41 meskes Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -50,9 +50,8 @@ static int literalalloc; /* current allocated buffer size */ ...@@ -50,9 +50,8 @@ static int literalalloc; /* current allocated buffer size */
#define startlit() (literalbuf[0] = '\0', literallen = 0) #define startlit() (literalbuf[0] = '\0', literallen = 0)
static void addlit(char *ytext, int yleng); static void addlit(char *ytext, int yleng);
static void addlitchar (unsigned char); static void addlitchar (unsigned char);
static unsigned char unescape_single_char(unsigned char);
static char *token_start; char *token_start;
int state_before; int state_before;
struct _yy_buffer struct _yy_buffer
...@@ -307,7 +306,7 @@ cppline {space}*#(.*\\{space})*.* ...@@ -307,7 +306,7 @@ cppline {space}*#(.*\\{space})*.*
ECHO; ECHO;
if (xcdepth <= 0) if (xcdepth <= 0)
{ {
BEGIN(INITIAL); BEGIN(state_before);
token_start = NULL; token_start = NULL;
} }
else else
...@@ -377,7 +376,7 @@ cppline {space}*#(.*\\{space})*.* ...@@ -377,7 +376,7 @@ cppline {space}*#(.*\\{space})*.*
} }
<xq>{xqdouble} { addlitchar('\''); } <xq>{xqdouble} { addlitchar('\''); }
<xq>{xqinside} { addlit(yytext, yyleng); } <xq>{xqinside} { addlit(yytext, yyleng); }
<xq>{xqescape} { addlitchar(unescape_single_char(yytext[1])); } <xq>{xqescape} { addlit(yytext, yyleng); }
<xq>{xqoctesc} { unsigned char c = strtoul(yytext+1, NULL, 8); <xq>{xqoctesc} { unsigned char c = strtoul(yytext+1, NULL, 8);
addlitchar(c); } addlitchar(c); }
<xq>{xqcat} { /* ignore */ } <xq>{xqcat} { /* ignore */ }
...@@ -936,22 +935,9 @@ addlitchar(unsigned char ychar) ...@@ -936,22 +935,9 @@ addlitchar(unsigned char ychar)
literalbuf[literallen] = '\0'; literalbuf[literallen] = '\0';
} }
unsigned char int
unescape_single_char(unsigned char c) yywrap(void)
{ {
switch (c) return(1);
{
case 'b':
return '\b';
case 'f':
return '\f';
case 'n':
return '\n';
case 'r':
return '\r';
case 't':
return '\t';
default:
return c;
}
} }
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/Attic/preproc.y,v 1.188 2002/05/19 20:00:53 meskes Exp $ */ /* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/Attic/preproc.y,v 1.189 2002/05/20 09:29:41 meskes Exp $ */
/* Copyright comment */ /* Copyright comment */
%{ %{
...@@ -328,7 +328,7 @@ make_name(void) ...@@ -328,7 +328,7 @@ make_name(void)
%type <str> RemoveAggrStmt opt_procedural select_no_parens %type <str> RemoveAggrStmt opt_procedural select_no_parens
%type <str> RemoveOperStmt RenameStmt all_Op opt_Trusted opt_lancompiler %type <str> RemoveOperStmt RenameStmt all_Op opt_Trusted opt_lancompiler
%type <str> VariableSetStmt var_value zone_value VariableShowStmt %type <str> VariableSetStmt var_value zone_value VariableShowStmt
%type <str> VariableResetStmt AlterTableStmt DropUserStmt from_list %type <str> VariableResetStmt AlterTableStmt from_list
%type <str> opt_trans user_list OptUserList OptUserElem relation_name %type <str> opt_trans user_list OptUserList OptUserElem relation_name
%type <str> CreateUserStmt AlterUserStmt CreateSeqStmt OptSeqList %type <str> CreateUserStmt AlterUserStmt CreateSeqStmt OptSeqList
%type <str> OptSeqElem TriggerForSpec TriggerForOpt TriggerForType %type <str> OptSeqElem TriggerForSpec TriggerForOpt TriggerForType
...@@ -361,18 +361,19 @@ make_name(void) ...@@ -361,18 +361,19 @@ make_name(void)
%type <str> insert_target_list insert_column_item DropRuleStmt %type <str> insert_target_list insert_column_item DropRuleStmt
%type <str> createfunc_opt_item set_rest var_list_or_default %type <str> createfunc_opt_item set_rest var_list_or_default
%type <str> CreateFunctionStmt createfunc_opt_list func_table %type <str> CreateFunctionStmt createfunc_opt_list func_table
%type <str> DropUserStmt
%type <str> ECPGWhenever ECPGConnect connection_target ECPGOpen %type <str> ECPGWhenever ECPGConnect connection_target ECPGOpen
%type <str> indicator ECPGExecute ECPGPrepare ecpg_using ecpg_into %type <str> indicator ECPGExecute ECPGPrepare ecpg_using ecpg_into
%type <str> storage_clause opt_initializer c_anything blockstart %type <str> storage_clause opt_initializer c_anything
%type <str> blockend variable_list variable c_thing c_term %type <str> variable_list variable c_thing c_term
%type <str> opt_pointer ECPGDisconnect dis_name storage_modifier %type <str> opt_pointer ECPGDisconnect dis_name storage_modifier
%type <str> stmt ECPGRelease execstring server_name %type <str> stmt ECPGRelease execstring server_name
%type <str> connection_object opt_server opt_port c_stuff c_stuff_item %type <str> connection_object opt_server opt_port c_stuff c_stuff_item
%type <str> user_name opt_user char_variable ora_user ident opt_reference %type <str> user_name opt_user char_variable ora_user ident opt_reference
%type <str> quoted_ident_stringvar var_type_declarations %type <str> quoted_ident_stringvar var_type_declarations
%type <str> db_prefix server opt_options opt_connection_name c_list %type <str> db_prefix server opt_options opt_connection_name c_list
%type <str> ECPGSetConnection cpp_line ECPGTypedef c_args ECPGKeywords %type <str> ECPGSetConnection ECPGTypedef c_args ECPGKeywords
%type <str> enum_type civar civarind ECPGCursorStmt ECPGDeallocate %type <str> enum_type civar civarind ECPGCursorStmt ECPGDeallocate
%type <str> ECPGFree ECPGDeclare ECPGVar opt_at enum_definition %type <str> ECPGFree ECPGDeclare ECPGVar opt_at enum_definition
%type <str> struct_type s_struct vt_declarations variable_declarations %type <str> struct_type s_struct vt_declarations variable_declarations
...@@ -382,7 +383,7 @@ make_name(void) ...@@ -382,7 +383,7 @@ make_name(void)
%type <str> ECPGGetDescriptorHeader ECPGColLabel %type <str> ECPGGetDescriptorHeader ECPGColLabel
%type <str> reserved_keyword unreserved_keyword %type <str> reserved_keyword unreserved_keyword
%type <str> col_name_keyword func_name_keyword %type <str> col_name_keyword func_name_keyword
%type <str> ECPGTypeName variablelist cvariable %type <str> ECPGTypeName variablelist
%type <descriptor> ECPGGetDescriptor %type <descriptor> ECPGGetDescriptor
...@@ -410,9 +411,9 @@ statement: ecpgstart opt_at stmt ';' { connection = NULL; } ...@@ -410,9 +411,9 @@ statement: ecpgstart opt_at stmt ';' { connection = NULL; }
| ecpgstart stmt ';' | ecpgstart stmt ';'
| ECPGDeclaration | ECPGDeclaration
| c_thing { fprintf(yyout, "%s", $1); free($1); } | c_thing { fprintf(yyout, "%s", $1); free($1); }
| cpp_line { fprintf(yyout, "%s", $1); free($1); } | CPP_LINE { fprintf(yyout, "%s", $1); free($1); }
| blockstart { fputs($1, yyout); free($1); } | '{' { braces_open++; fputs("{", yyout); }
| blockend { fputs($1, yyout); free($1); } | '}' { remove_variables(braces_open--); fputs("}", yyout); }
; ;
opt_at: AT connection_target opt_at: AT connection_target
...@@ -689,14 +690,13 @@ AlterUserSetStmt: ALTER USER UserId SET set_rest ...@@ -689,14 +690,13 @@ AlterUserSetStmt: ALTER USER UserId SET set_rest
* *
* *
*****************************************************************************/ *****************************************************************************/
DropUserStmt: DROP USER user_list DropUserStmt: DROP USER user_list
{ $$ = cat2_str(make_str("drop user"), $3);} { $$ = cat2_str(make_str("drop user"), $3);}
; ;
/* /*
* Options for CREATE USER and ALTER USER * Options for CREATE USER and ALTER USER
*/ */
OptUserList: OptUserList OptUserElem { $$ = cat2_str($1, $2); } OptUserList: OptUserList OptUserElem { $$ = cat2_str($1, $2); }
| /* EMPTY */ { $$ = EMPTY; } | /* EMPTY */ { $$ = EMPTY; }
; ;
...@@ -725,7 +725,6 @@ user_list: user_list ',' UserId ...@@ -725,7 +725,6 @@ user_list: user_list ',' UserId
{ $$ = $1; } { $$ = $1; }
; ;
/***************************************************************************** /*****************************************************************************
* *
* Create a postgresql group * Create a postgresql group
...@@ -822,13 +821,12 @@ schema_stmt: CreateStmt { $$ = $1; } ...@@ -822,13 +821,12 @@ schema_stmt: CreateStmt { $$ = $1; }
* SET TIME ZONE 'var_value' * SET TIME ZONE 'var_value'
* *
*****************************************************************************/ *****************************************************************************/
VariableSetStmt: SET set_rest VariableSetStmt: SET set_rest
{ $$ = cat2_str(make_str("set"), $2 ); } { $$ = cat2_str(make_str("set"), $2 ); }
| SET LOCAL set_rest | SET LOCAL set_rest
{ $$ = cat2_str(make_str("set local"), $2 ); } { $$ = cat2_str(make_str("set local"), $3 ); }
| SET SESSION set_rest | SET SESSION set_rest
{ $$ = cat2_str(make_str("set session"), $2 ); } { $$ = cat2_str(make_str("set session"), $3 ); }
; ;
set_rest: ColId TO var_list_or_default set_rest: ColId TO var_list_or_default
...@@ -876,7 +874,6 @@ opt_boolean: TRUE_P { $$ = make_str("true"); } ...@@ -876,7 +874,6 @@ opt_boolean: TRUE_P { $$ = make_str("true"); }
| ON { $$ = make_str("on"); } | ON { $$ = make_str("on"); }
| OFF { $$ = make_str("off"); } | OFF { $$ = make_str("off"); }
; ;
/* Timezone values can be: /* Timezone values can be:
* - a string such as 'pst8pdt' * - a string such as 'pst8pdt'
* - a column identifier such as "pst8pdt" * - a column identifier such as "pst8pdt"
...@@ -2193,7 +2190,7 @@ opt_equal: '=' { $$ = make_str("="); } ...@@ -2193,7 +2190,7 @@ opt_equal: '=' { $$ = make_str("="); }
*****************************************************************************/ *****************************************************************************/
AlterDatabaseSetStmt: ALTER DATABASE database_name SET set_rest AlterDatabaseSetStmt: ALTER DATABASE database_name SET set_rest
{ $$ = cat_str(4, make_str("alter database"), $3, make_Str("set"), $5); } { $$ = cat_str(4, make_str("alter database"), $3, make_str("set"), $5); }
| ALTER DATABASE database_name VariableResetStmt | ALTER DATABASE database_name VariableResetStmt
{ $$ = cat_str(3, make_str("alter database"), $3, $4); } { $$ = cat_str(3, make_str("alter database"), $3, $4); }
; ;
...@@ -2881,7 +2878,7 @@ opt_decimal: '(' PosIntConst ',' PosIntConst ')' ...@@ -2881,7 +2878,7 @@ opt_decimal: '(' PosIntConst ',' PosIntConst ')'
* The following implements BIT() and BIT VARYING(). * The following implements BIT() and BIT VARYING().
*/ */
Bit: BIT opt_varying '(' PosIntConst ')' Bit: BIT opt_varying '(' PosIntConst ')'
{ $$ = cat_str(5, $1, $2, make_str("("), $4, make_str(")")); } { $$ = cat_str(5, make_str("bit"), $2, make_str("("), $4, make_str(")")); }
| BIT opt_varying | BIT opt_varying
{ $$ = cat2_str(make_str("bit"), $2); } { $$ = cat2_str(make_str("bit"), $2); }
; ;
...@@ -3687,7 +3684,7 @@ connection_target: database_name opt_server opt_port ...@@ -3687,7 +3684,7 @@ connection_target: database_name opt_server opt_port
} }
; ;
db_prefix: ident cvariable db_prefix: ident CVARIABLE
{ {
if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0) if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0)
{ {
...@@ -3778,7 +3775,7 @@ user_name: UserId ...@@ -3778,7 +3775,7 @@ user_name: UserId
} }
; ;
char_variable: cvariable char_variable: CVARIABLE
{ {
/* check if we have a char variable */ /* check if we have a char variable */
struct variable *p = find_variable($1); struct variable *p = find_variable($1);
...@@ -4421,14 +4418,14 @@ ECPGAllocateDescr: SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar ...@@ -4421,14 +4418,14 @@ ECPGAllocateDescr: SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar
* read from descriptor * read from descriptor
*/ */
ECPGGetDescHeaderItem: cvariable '=' desc_header_item ECPGGetDescHeaderItem: CVARIABLE '=' desc_header_item
{ push_assignment($1, $3); } { push_assignment($1, $3); }
; ;
desc_header_item: SQL_COUNT { $$ = ECPGd_count; } desc_header_item: SQL_COUNT { $$ = ECPGd_count; }
; ;
ECPGGetDescItem: cvariable '=' descriptor_item { push_assignment($1, $3); }; ECPGGetDescItem: CVARIABLE '=' descriptor_item { push_assignment($1, $3); };
descriptor_item: SQL_CARDINALITY { $$ = ECPGd_cardinality; } descriptor_item: SQL_CARDINALITY { $$ = ECPGd_cardinality; }
| SQL_DATA { $$ = ECPGd_data; } | SQL_DATA { $$ = ECPGd_data; }
...@@ -4461,7 +4458,7 @@ ECPGGetDescriptorHeader: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar ...@@ -4461,7 +4458,7 @@ ECPGGetDescriptorHeader: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar
; ;
ECPGGetDescriptor: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar ECPGGetDescriptor: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar
SQL_VALUE cvariable ECPGGetDescItems SQL_VALUE CVARIABLE ECPGGetDescItems
{ $$.str = $5; $$.name = $3; } { $$.str = $5; $$.name = $3; }
| SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE Iconst ECPGGetDescItems | SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE Iconst ECPGGetDescItems
{ $$.str = $5; $$.name = $3; } { $$.str = $5; $$.name = $3; }
...@@ -4851,6 +4848,7 @@ function_name: ident { $$ = $1; } ...@@ -4851,6 +4848,7 @@ function_name: ident { $$ = $1; }
ColLabel: ECPGColLabel { $$ = $1; } ColLabel: ECPGColLabel { $$ = $1; }
| ECPGTypeName { $$ = $1; } | ECPGTypeName { $$ = $1; }
| CHAR { $$ = make_str("char"); } | CHAR { $$ = make_str("char"); }
| INT { $$ = make_str("int"); }
| UNION { $$ = make_str("union"); } | UNION { $$ = make_str("union"); }
; ;
...@@ -5043,7 +5041,8 @@ unreserved_keyword: ...@@ -5043,7 +5041,8 @@ unreserved_keyword:
* looks too much like a function call for an LR(1) parser. * looks too much like a function call for an LR(1) parser.
*/ */
col_name_keyword: col_name_keyword:
BIT { $$ = make_str("bit"); } BIGINT { $$ = make_str("bigint");}
| BIT { $$ = make_str("bit"); }
/* CHAR must be excluded from ECPGColLabel because of conflict with UNSIGNED /* CHAR must be excluded from ECPGColLabel because of conflict with UNSIGNED
| CHAR { $$ = make_str("char"); } | CHAR { $$ = make_str("char"); }
*/ */
...@@ -5054,13 +5053,19 @@ col_name_keyword: ...@@ -5054,13 +5053,19 @@ col_name_keyword:
| EXISTS { $$ = make_str("exists"); } | EXISTS { $$ = make_str("exists"); }
| EXTRACT { $$ = make_str("extract"); } | EXTRACT { $$ = make_str("extract"); }
| FLOAT { $$ = make_str("float"); } | FLOAT { $$ = make_str("float"); }
/* INT must be excluded from ECPGColLabel because of conflict
| INT { $$ = make_str("int"); }
*/
| INTEGER { $$ = make_str("integer"); }
| INTERVAL { $$ = make_str("interval"); } | INTERVAL { $$ = make_str("interval"); }
| NCHAR { $$ = make_str("nchar"); } | NCHAR { $$ = make_str("nchar"); }
| NONE { $$ = make_str("none"); } | NONE { $$ = make_str("none"); }
| NULLIF { $$ = make_str("nullif"); } | NULLIF { $$ = make_str("nullif"); }
| NUMERIC { $$ = make_str("numeric"); } | NUMERIC { $$ = make_str("numeric"); }
| POSITION { $$ = make_str("position"); } | POSITION { $$ = make_str("position"); }
| REAL { $$ = make_str("real"); }
| SETOF { $$ = make_str("setof"); } | SETOF { $$ = make_str("setof"); }
| SMALLINT { $$ = make_str("smallint"); }
| SUBSTRING { $$ = make_str("substring"); } | SUBSTRING { $$ = make_str("substring"); }
| TIME { $$ = make_str("time"); } | TIME { $$ = make_str("time"); }
| TIMESTAMP { $$ = make_str("timestamp"); } | TIMESTAMP { $$ = make_str("timestamp"); }
...@@ -5188,14 +5193,14 @@ c_args: /*EMPTY*/ { $$ = EMPTY; } ...@@ -5188,14 +5193,14 @@ c_args: /*EMPTY*/ { $$ = EMPTY; }
| c_list { $$ = $1; } | c_list { $$ = $1; }
; ;
coutputvariable: cvariable indicator coutputvariable: CVARIABLE indicator
{ add_variable(&argsresult, find_variable($1), find_variable($2)); } { add_variable(&argsresult, find_variable($1), find_variable($2)); }
| cvariable | CVARIABLE
{ add_variable(&argsresult, find_variable($1), &no_indicator); } { add_variable(&argsresult, find_variable($1), &no_indicator); }
; ;
civarind: cvariable indicator civarind: CVARIABLE indicator
{ {
if ($2 != NULL && (find_variable($2))->type->type == ECPGt_array) if ($2 != NULL && (find_variable($2))->type->type == ECPGt_array)
mmerror(PARSE_ERROR, ET_ERROR, "arrays of indicators are not allowed on input"); mmerror(PARSE_ERROR, ET_ERROR, "arrays of indicators are not allowed on input");
...@@ -5204,18 +5209,15 @@ civarind: cvariable indicator ...@@ -5204,18 +5209,15 @@ civarind: cvariable indicator
} }
; ;
civar: cvariable civar: CVARIABLE
{ {
add_variable(&argsinsert, find_variable($1), &no_indicator); add_variable(&argsinsert, find_variable($1), &no_indicator);
$$ = $1; $$ = $1;
} }
; ;
cvariable: CVARIABLE { $$ = $1; }
;
indicator: CVARIABLE { check_indicator((find_variable($1))->type); $$ = $1; } indicator: CVARIABLE { check_indicator((find_variable($1))->type); $$ = $1; }
| SQL_INDICATOR cvariable { check_indicator((find_variable($2))->type); $$ = $2; } | SQL_INDICATOR CVARIABLE { check_indicator((find_variable($2))->type); $$ = $2; }
| SQL_INDICATOR name { check_indicator((find_variable($2))->type); $$ = $2; } | SQL_INDICATOR name { check_indicator((find_variable($2))->type); $$ = $2; }
; ;
...@@ -5235,8 +5237,6 @@ quoted_ident_stringvar: IDENT ...@@ -5235,8 +5237,6 @@ quoted_ident_stringvar: IDENT
* C stuff * C stuff
*/ */
cpp_line: CPP_LINE { $$ = $1; };
c_stuff_item: c_anything { $$ = $1; } c_stuff_item: c_anything { $$ = $1; }
| '(' ')' { $$ = make_str("()"); } | '(' ')' { $$ = make_str("()"); }
| '(' c_stuff ')' | '(' c_stuff ')'
...@@ -5315,25 +5315,13 @@ c_anything: IDENT { $$ = $1; } ...@@ -5315,25 +5315,13 @@ c_anything: IDENT { $$ = $1; }
| '=' { $$ = make_str("="); } | '=' { $$ = make_str("="); }
; ;
blockstart : '{'
{
braces_open++;
$$ = make_str("{");
};
blockend : '}'
{
remove_variables(braces_open--);
$$ = make_str("}");
};
%% %%
void yyerror( char * error) void yyerror( char * error)
{ {
char buf[1024]; char buf[1024];
snprintf(buf,sizeof buf,"%s at or near \"%s\"",error,yytext); snprintf(buf,sizeof buf,"%s at or near \"%s\"", error, token_start ? token_start : yytext);
buf[sizeof(buf)-1]=0; buf[sizeof(buf)-1]=0;
mmerror(PARSE_ERROR, ET_ERROR, buf); mmerror(PARSE_ERROR, ET_ERROR, buf);
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment